Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
authorHuang, Tao <huangtao@rock-chips.com>
Fri, 13 May 2016 04:20:56 +0000 (12:20 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 13 May 2016 04:20:56 +0000 (12:20 +0800)
* linux-linaro-lsk-v4.4-android: (797 commits)
  parisc: Use generic extable search and sort routines
  arm64: kasan: Use actual memory node when populating the kernel image shadow
  arm64: mm: treat memstart_addr as a signed quantity
  arm64: lse: deal with clobbered IP registers after branch via PLT
  arm64: mm: check at build time that PAGE_OFFSET divides the VA space evenly
  arm64: kasan: Fix zero shadow mapping overriding kernel image shadow
  arm64: consistently use p?d_set_huge
  arm64: fix KASLR boot-time I-cache maintenance
  arm64: hugetlb: partial revert of 66b3923a1a0f
  arm64: make irq_stack_ptr more robust
  arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
  efi: stub: use high allocation for converted command line
  efi: stub: add implementation of efi_random_alloc()
  efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL
  arm64: kaslr: randomize the linear region
  arm64: add support for kernel ASLR
  arm64: add support for building vmlinux as a relocatable PIE binary
  arm64: switch to relative exception tables
  extable: add support for relative extables to search and sort routines
  scripts/sortextable: add support for ET_DYN binaries
  ...

Conflicts:
arch/arm64/mm/dma-mapping.c
drivers/clk/rockchip/clk-rk3368.c
drivers/mmc/core/core.c
drivers/mmc/core/sdio.c
include/linux/dcache.h

Change-Id: Ibaa1e90ac735db8d9f5e542c266ef27b91616ef4

707 files changed:
Documentation/arm64/booting.txt
Documentation/arm64/silicon-errata.txt [new file with mode: 0644]
Documentation/block/00-INDEX
Documentation/block/mmc-max-speed.txt [new file with mode: 0644]
Documentation/device-mapper/verity.txt
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/opp/opp.txt
Documentation/devicetree/bindings/pinctrl/img,pistachio-pinctrl.txt
Documentation/features/time/irq-time-acct/arch-support.txt
Documentation/features/vm/huge-vmap/arch-support.txt
Documentation/kernel-parameters.txt
MAINTAINERS
Makefile
android/configs/android-base.cfg
arch/arc/include/asm/bitops.h
arch/arc/include/asm/io.h
arch/arm/boot/dts/am43x-epos-evm.dts
arch/arm/boot/dts/armada-375.dtsi
arch/arm/boot/dts/armada-385-linksys.dtsi
arch/arm/boot/dts/at91-sama5d3_xplained.dts
arch/arm/boot/dts/at91-sama5d4_xplained.dts
arch/arm/boot/dts/pxa3xx.dtsi
arch/arm/include/asm/kvm_asm.h
arch/arm/kvm/arm.c
arch/arm/mach-cns3xxx/pcie.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-omap2/cpuidle34xx.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-prima2/Kconfig
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/include/mach/dma.h
arch/arm/mach-socfpga/headsmp.S
arch/arm/plat-samsung/devs.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/alternative.h
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/atomic_lse.h
arch/arm64/include/asm/boot.h
arch/arm64/include/asm/brk-imm.h [new file with mode: 0644]
arch/arm64/include/asm/bug.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/cmpxchg.h
arch/arm64/include/asm/cpu.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/debug-monitors.h
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/ftrace.h
arch/arm64/include/asm/futex.h
arch/arm64/include/asm/hardirq.h
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/irq.h
arch/arm64/include/asm/kasan.h
arch/arm64/include/asm/kernel-pgtable.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/lse.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/module.h
arch/arm64/include/asm/opcodes.h
arch/arm64/include/asm/pgalloc.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/shmparam.h
arch/arm64/include/asm/smp.h
arch/arm64/include/asm/spinlock.h
arch/arm64/include/asm/stacktrace.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/word-at-a-time.h
arch/arm64/include/uapi/asm/ptrace.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/acpi_parking_protocol.c [new file with mode: 0644]
arch/arm64/kernel/alternative.c
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpu_ops.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/efi-entry.S
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/image.h
arch/arm64/kernel/irq.c
arch/arm64/kernel/kaslr.c [new file with mode: 0644]
arch/arm64/kernel/module-plts.c [new file with mode: 0644]
arch/arm64/kernel/module.c
arch/arm64/kernel/module.lds [new file with mode: 0644]
arch/arm64/kernel/perf_callchain.c
arch/arm64/kernel/process.c
arch/arm64/kernel/return_address.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/sleep.S
arch/arm64/kernel/smp.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/suspend.c
arch/arm64/kernel/time.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/hyp.S
arch/arm64/lib/Makefile
arch/arm64/lib/clear_user.S
arch/arm64/lib/copy_from_user.S
arch/arm64/lib/copy_in_user.S
arch/arm64/lib/copy_page.S
arch/arm64/lib/copy_to_user.S
arch/arm64/mm/cache.S
arch/arm64/mm/context.c
arch/arm64/mm/copypage.c
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/dump.c
arch/arm64/mm/extable.c
arch/arm64/mm/fault.c
arch/arm64/mm/flush.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/init.c
arch/arm64/mm/kasan_init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/pageattr.c
arch/arm64/mm/pgd.c
arch/arm64/mm/proc-macros.S
arch/arm64/mm/proc.S
arch/ia64/include/asm/io.h
arch/mips/alchemy/devboards/db1000.c
arch/mips/alchemy/devboards/db1550.c
arch/mips/kernel/unaligned.c
arch/parisc/Kconfig
arch/parisc/include/asm/assembly.h
arch/parisc/include/asm/uaccess.h
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/traps.c
arch/parisc/lib/fixup.S
arch/parisc/mm/fault.c
arch/powerpc/include/asm/word-at-a-time.h
arch/powerpc/include/uapi/asm/cputable.h
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/mm/hugetlbpage.c
arch/s390/include/asm/pci.h
arch/s390/kernel/entry.S
arch/s390/kernel/head64.S
arch/s390/kernel/setup.c
arch/s390/pci/pci.c
arch/sh/mm/kmap.c
arch/um/drivers/mconsole_kern.c
arch/x86/Kconfig
arch/x86/crypto/sha-mb/sha1_mb.c
arch/x86/entry/common.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/hugetlb.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/microcode.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/apic/vector.c
arch/x86/kernel/cpu/mcheck/mce-genpool.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_knc.c
arch/x86/kernel/ioport.c
arch/x86/kernel/process_64.c
arch/x86/kernel/sysfb_efi.c
arch/x86/kernel/tsc_msr.c
arch/x86/kvm/i8254.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/kmmio.c
arch/x86/mm/tlb.c
arch/x86/pci/common.c
arch/x86/pci/fixup.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/irq.c
arch/x86/xen/enlighten.c
arch/xtensa/kernel/head.S
arch/xtensa/mm/cache.c
arch/xtensa/platforms/iss/console.c
block/blk-core.c
block/partition-generic.c
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/x509_cert_parser.c
crypto/keywrap.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/bus.c
drivers/acpi/internal.h
drivers/acpi/pci_irq.c
drivers/acpi/resource.c
drivers/acpi/sleep.c
drivers/ata/ahci_platform.c
drivers/ata/ahci_xgene.c
drivers/ata/libahci.c
drivers/base/power/domain.c
drivers/base/power/opp/Makefile
drivers/base/power/opp/core.c
drivers/base/power/opp/cpu.c
drivers/base/power/opp/debugfs.c [new file with mode: 0644]
drivers/base/power/opp/opp.h
drivers/block/brd.c
drivers/block/loop.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/nbd.c
drivers/block/paride/pd.c
drivers/block/paride/pt.c
drivers/block/rbd.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/bus/imx-weim.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm_crb.c
drivers/char/tpm/tpm_eventlog.c
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/meson/clkc.c
drivers/clk/qcom/gcc-msm8960.c
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk.c
drivers/clk/versatile/clk-sp810.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq_interactive.c
drivers/cpufreq/intel_pstate.c
drivers/cpuidle/cpuidle-arm.c
drivers/crypto/atmel-aes.c
drivers/crypto/atmel-sha.c
drivers/crypto/atmel-tdes.c
drivers/crypto/ccp/ccp-crypto-aes-cmac.c
drivers/crypto/ccp/ccp-crypto-sha.c
drivers/crypto/ccp/ccp-crypto.h
drivers/crypto/marvell/cesa.c
drivers/crypto/talitos.c
drivers/crypto/ux500/cryp/cryp_core.c
drivers/crypto/ux500/hash/hash_core.c
drivers/dma/dw/core.c
drivers/dma/hsu/hsu.c
drivers/dma/hsu/hsu.h
drivers/dma/pxa_dma.c
drivers/edac/amd64_edac.c
drivers/edac/i7core_edac.c
drivers/edac/sb_edac.c
drivers/extcon/extcon-max77843.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm-stub.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/fdt.c
drivers/firmware/efi/libstub/random.c [new file with mode: 0644]
drivers/firmware/efi/vars.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_csr.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/nouveau/nvkm/core/ramht.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_reg.h
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/ipu-v3/ipu-common.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-multitouch.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/hwmon/max1111.c
drivers/hwtracing/stm/Kconfig
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-exynos5.c
drivers/idle/intel_idle.c
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/gyro/bmg160_core.c
drivers/iio/magnetometer/ak8975.c
drivers/iio/magnetometer/st_magn.h
drivers/infiniband/core/ucm.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/qib/qib_file_ops.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/misc/ati_remote2.c
drivers/input/misc/ims-pcu.c
drivers/input/misc/pmic8xxx-pwrkey.c
drivers/input/misc/powermate.c
drivers/input/mouse/synaptics.c
drivers/input/tablet/gtco.c
drivers/input/touchscreen/zforce_ts.c
drivers/iommu/amd_iommu.c
drivers/iommu/dma-iommu.c
drivers/iommu/iommu.c
drivers/irqchip/irq-mxs.c
drivers/irqchip/irq-sunxi-nmi.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/bcache/super.c
drivers/md/dm-cache-metadata.c
drivers/md/dm-cache-metadata.h
drivers/md/dm-cache-target.c
drivers/md/dm-snap.c
drivers/md/dm-table.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-verity-fec.c [new file with mode: 0644]
drivers/md/dm-verity-fec.h [new file with mode: 0644]
drivers/md/dm-verity-target.c [new file with mode: 0644]
drivers/md/dm-verity.c [deleted file]
drivers/md/dm-verity.h [new file with mode: 0644]
drivers/md/dm.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/i2c/adv7511.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/platform/coda/coda-bit.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/vsp1/vsp1_sru.c
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/au0828/au0828-input.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/au0828/au0828.h
drivers/media/usb/pwc/pwc-if.c
drivers/media/usb/usbvision/usbvision-video.c
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-memops.c
drivers/media/v4l2-core/videobuf2-v4l2.c
drivers/mfd/intel-lpss.c
drivers/misc/Kconfig
drivers/misc/ad525x_dpot.c
drivers/misc/cxl/irq.c
drivers/misc/mei/bus.c
drivers/misc/mic/scif/scif_rma.c
drivers/mmc/card/Kconfig
drivers/mmc/card/block.c
drivers/mmc/card/queue.h
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci.c
drivers/mmc/host/sh_mmcif.c
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/spi-nor/spi-nor.c
drivers/net/bonding/bond_main.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/jme.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/qualcomm/qca_spi.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/irda/irtty-sir.c
drivers/net/macvtap.c
drivers/net/ppp/ppp_generic.c
drivers/net/rionet.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/vrf.c
drivers/net/vxlan.c
drivers/net/wan/farsync.c
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/nvdimm/bus.c
drivers/nvdimm/pfn_devs.c
drivers/nvmem/mxs-ocotp.c
drivers/of/fdt.c
drivers/of/of_reserved_mem.c
drivers/pci/probe.c
drivers/pcmcia/db1xxx_ss.c
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-pistachio.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/sh-pfc/core.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.h
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/pwm/pwm-brcmstb.c
drivers/regulator/core.c
drivers/regulator/s5m8767.c
drivers/rtc/rtc-ds1685.c
drivers/rtc/rtc-hym8563.c
drivers/rtc/rtc-max77686.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-vr41xx.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/src.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/device_handler/Kconfig
drivers/scsi/ipr.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/scsi_common.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/sg.c
drivers/scsi/storvsc_drv.c
drivers/soc/rockchip/pm_domains.c
drivers/staging/android/ion/ion.c
drivers/staging/android/ion/ion_test.c
drivers/staging/comedi/drivers/ni_mio_common.c
drivers/staging/comedi/drivers/ni_tiocmd.c
drivers/staging/rdma/hfi1/TODO
drivers/staging/rdma/hfi1/file_ops.c
drivers/target/target_core_transport.c
drivers/thermal/thermal_core.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/sh-sci.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/driver.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hub.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/host/xhci-mem.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/iowarrior.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/mct_u232.c
drivers/usb/serial/option.c
drivers/usb/storage/uas.c
drivers/usb/storage/unusual_uas.h
drivers/usb/storage/usb.c
drivers/usb/usbip/usbip_common.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/da8xx-fb.c
drivers/virtio/virtio_pci_modern.c
drivers/watchdog/rc32434_wdt.c
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/evtchn.c
fs/btrfs/file.c
fs/btrfs/tree-log.c
fs/coredump.c
fs/dcache.c
fs/debugfs/inode.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/inode.c
fs/ext4/move_extent.c
fs/ext4/super.c
fs/ext4/truncate.h
fs/fhandle.c
fs/fs-writeback.c
fs/fuse/cuse.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/jbd2/journal.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs4file.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4xdr.c
fs/ocfs2/dlm/dlmconvert.c
fs/ocfs2/dlm/dlmrecovery.c
fs/open.c
fs/overlayfs/super.c
fs/pnode.c
fs/proc/base.c
fs/proc/task_mmu.c
fs/proc_namespace.c
fs/quota/dquot.c
fs/splice.c
fs/xfs/xfs_attr_list.c
include/asm-generic/bitops/lock.h
include/asm-generic/fixmap.h
include/asm-generic/futex.h
include/drm/drm_cache.h
include/linux/cgroup-defs.h
include/linux/compiler-gcc.h
include/linux/cpuset.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/efi.h
include/linux/filter.h
include/linux/fs.h
include/linux/hash.h
include/linux/hugetlb.h
include/linux/if_bridge.h
include/linux/kernel.h
include/linux/mlx5/device.h
include/linux/mm.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/platform_data/asoc-s3c.h
include/linux/pm_opp.h
include/linux/skbuff.h
include/linux/thermal.h
include/linux/tty.h
include/linux/usb_usual.h
include/media/videobuf2-core.h
include/net/bonding.h
include/net/ip_vs.h
include/rdma/ib.h
include/uapi/linux/v4l2-dv-timings.h
include/xen/page.h
kernel/bpf/helpers.c
kernel/cgroup.c
kernel/cpuset.c
kernel/events/core.c
kernel/futex.c
kernel/locking/mcs_spinlock.h
kernel/power/hibernate.c
kernel/sched/core.c
kernel/sched/cputime.c
kernel/sched/sched.h
kernel/sysctl_binary.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_printk.c
kernel/watchdog.c
kernel/workqueue.c
lib/assoc_array.c
lib/extable.c
lib/lz4/lz4defs.h
lib/mpi/mpicoder.c
lib/test-string_helpers.c
mm/compaction.c
mm/huge_memory.c
mm/memcontrol.c
mm/memory.c
mm/migrate.c
mm/mmap.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/slub.c
mm/vmscan.c
mm/zswap.c
net/ax25/ax25_ip.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/routing.c
net/batman-adv/send.c
net/batman-adv/soft-interface.c
net/bluetooth/mgmt.c
net/bridge/br_stp.c
net/core/filter.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dccp/ipv4.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/igmp.c
net/ipv4/ip_output.c
net/ipv4/ip_tunnel.c
net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/udp.c
net/ipv4/udp_tunnel.c
net/ipv6/exthdrs_core.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/mcast.c
net/ipv6/udp.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_ip6.c
net/mac80211/ibss.c
net/mac80211/iface.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mpls/af_mpls.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_pe_sip.c
net/netlink/af_netlink.c
net/packet/af_packet.c
net/sctp/ipv6.c
net/socket.c
net/sunrpc/cache.c
net/tipc/socket.c
net/wireless/nl80211.c
net/xfrm/xfrm_input.c
scripts/coccinelle/iterators/use_after_iter.cocci
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/package/mkspec
scripts/sortextable.c
sound/core/pcm_lib.c
sound/core/timer.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/intel8x0.c
sound/pci/pcxhr/pcxhr_core.c
sound/soc/codecs/ssm4567.c
sound/soc/samsung/ac97.c
sound/soc/samsung/dma.h
sound/soc/samsung/dmaengine.c
sound/soc/samsung/i2s.c
sound/soc/samsung/pcm.c
sound/soc/samsung/s3c-i2s-v2.c
sound/soc/samsung/s3c-i2s-v2.h
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/spdif.c
sound/soc/soc-dapm.c
sound/usb/clock.c
sound/usb/endpoint.c
sound/usb/mixer_maps.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks.c
sound/usb/stream.c
tools/hv/Makefile
tools/perf/Documentation/perf-stat.txt
tools/perf/ui/browsers/hists.c
tools/perf/util/event.c
tools/perf/util/evlist.c
tools/perf/util/intel-pt.c
tools/perf/util/parse-events.c
tools/perf/util/pmu.c
tools/perf/util/setup.py
virt/kvm/arm/arch_timer.c
virt/kvm/kvm_main.c

index 701d39d3171a74d8c2eb670c0b1be2931f326ee8..56d6d8b796db6dd3aadd252a85cc4b691f9e20f7 100644 (file)
@@ -109,7 +109,13 @@ Header notes:
                        1 - 4K
                        2 - 16K
                        3 - 64K
-  Bits 3-63:   Reserved.
+  Bit 3:       Kernel physical placement
+                       0 - 2MB aligned base should be as close as possible
+                           to the base of DRAM, since memory below it is not
+                           accessible via the linear mapping
+                       1 - 2MB aligned base may be anywhere in physical
+                           memory
+  Bits 4-63:   Reserved.
 
 - When image_size is zero, a bootloader should attempt to keep as much
   memory as possible free for use by the kernel immediately after the
@@ -117,14 +123,14 @@ Header notes:
   depending on selected features, and is effectively unbound.
 
 The Image must be placed text_offset bytes from a 2MB aligned base
-address near the start of usable system RAM and called there. Memory
-below that base address is currently unusable by Linux, and therefore it
-is strongly recommended that this location is the start of system RAM.
-The region between the 2 MB aligned base address and the start of the
-image has no special significance to the kernel, and may be used for
-other purposes.
+address anywhere in usable system RAM and called there. The region
+between the 2 MB aligned base address and the start of the image has no
+special significance to the kernel, and may be used for other purposes.
 At least image_size bytes from the start of the image must be free for
 use by the kernel.
+NOTE: versions prior to v4.6 cannot make use of memory below the
+physical offset of the Image so it is recommended that the Image be
+placed as close as possible to the start of system RAM.
 
 Any memory described to the kernel (even that below the start of the
 image) which is not marked as reserved from the kernel (e.g., with a
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
new file mode 100644 (file)
index 0000000..58b71dd
--- /dev/null
@@ -0,0 +1,58 @@
+                Silicon Errata and Software Workarounds
+                =======================================
+
+Author: Will Deacon <will.deacon@arm.com>
+Date  : 27 November 2015
+
+It is an unfortunate fact of life that hardware is often produced with
+so-called "errata", which can cause it to deviate from the architecture
+under specific circumstances.  For hardware produced by ARM, these
+errata are broadly classified into the following categories:
+
+  Category A: A critical error without a viable workaround.
+  Category B: A significant or critical error with an acceptable
+              workaround.
+  Category C: A minor error that is not expected to occur under normal
+              operation.
+
+For more information, consult one of the "Software Developers Errata
+Notice" documents available on infocenter.arm.com (registration
+required).
+
+As far as Linux is concerned, Category B errata may require some special
+treatment in the operating system. For example, avoiding a particular
+sequence of code, or configuring the processor in a particular way. A
+less common situation may require similar actions in order to declassify
+a Category A erratum into a Category C erratum. These are collectively
+known as "software workarounds" and are only required in the minority of
+cases (e.g. those cases that both require a non-secure workaround *and*
+can be triggered by Linux).
+
+For software workarounds that may adversely impact systems unaffected by
+the erratum in question, a Kconfig entry is added under "Kernel
+Features" -> "ARM errata workarounds via the alternatives framework".
+These are enabled by default and patched in at runtime when an affected
+CPU is detected. For less-intrusive workarounds, a Kconfig option is not
+available and the code is structured (preferably with a comment) in such
+a way that the erratum will not be hit.
+
+This approach can make it slightly onerous to determine exactly which
+errata are worked around in an arbitrary kernel source tree, so this
+file acts as a registry of software workarounds in the Linux Kernel and
+will be updated when new workarounds are committed and backported to
+stable kernels.
+
+| Implementor    | Component       | Erratum ID      | Kconfig                 |
++----------------+-----------------+-----------------+-------------------------+
+| ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319    |
+| ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319    |
+| ARM            | Cortex-A53      | #824069         | ARM64_ERRATUM_824069    |
+| ARM            | Cortex-A53      | #819472         | ARM64_ERRATUM_819472    |
+| ARM            | Cortex-A53      | #845719         | ARM64_ERRATUM_845719    |
+| ARM            | Cortex-A53      | #843419         | ARM64_ERRATUM_843419    |
+| ARM            | Cortex-A57      | #832075         | ARM64_ERRATUM_832075    |
+| ARM            | Cortex-A57      | #852523         | N/A                     |
+| ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220    |
+|                |                 |                 |                         |
+| Cavium         | ThunderX ITS    | #22375, #24313  | CAVIUM_ERRATUM_22375    |
+| Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154    |
index e840b47613f78f9f9efa6843cc90c997a36ccdce..bc5148757edb5db821cbdc42f20095a2097bcc13 100644 (file)
@@ -26,3 +26,9 @@ switching-sched.txt
        - Switching I/O schedulers at runtime
 writeback_cache_control.txt
        - Control of volatile write back caches
+mmc-max-speed.txt
+       - eMMC layer speed simulation, related to /sys/block/mmcblk*/
+          attributes:
+            max_read_speed
+            max_write_speed
+            cache_size
diff --git a/Documentation/block/mmc-max-speed.txt b/Documentation/block/mmc-max-speed.txt
new file mode 100644 (file)
index 0000000..3f052b9
--- /dev/null
@@ -0,0 +1,38 @@
+eMMC Block layer simulation speed controls in /sys/block/mmcblk*/
+===============================================
+
+Turned on with CONFIG_MMC_SIMULATE_MAX_SPEED which enables MMC device speed
+limiting. Used to test and simulate the behavior of the system when
+confronted with a slow MMC.
+
+Enables max_read_speed, max_write_speed and cache_size attributes and module
+default parameters to control the write or read maximum KB/second speed
+behaviors.
+
+NB: There is room for improving the algorithm for aspects tied directly to
+eMMC specific behavior. For instance, wear leveling and stalls from an
+exhausted erase pool. We would expect that if there was a need to provide
+similar speed simulation controls to other types of block devices, aspects of
+their behavior are modelled separately (e.g. head seek times, heat assist,
+shingling and rotational latency).
+
+/sys/block/mmcblk0/max_read_speed:
+
+Number of KB/second reads allowed to the block device. Used to test and
+simulate the behavior of the system when confronted with a slow reading MMC.
+Set to 0 or "off" to place no speed limit.
+
+/sys/block/mmcblk0/max_write_speed:
+
+Number of KB/second writes allowed to the block device. Used to test and
+simulate the behavior of the system when confronted with a slow writing MMC.
+Set to 0 or "off" to place no speed limit.
+
+/sys/block/mmcblk0/cache_size:
+
+Number of MB of high speed memory or high speed SLC cache expected on the
+eMMC device being simulated. Used to help simulate the write-back behavior
+more accurately. The assumption is the cache has no delay, but draws down
+in the background to the MLC/TLC primary store at the max_write_speed rate.
+Any write speed delays will show up when the cache is full, or when an I/O
+request to flush is issued.
index e15bc1a0fb98ab23563681210cc6ed1865234816..89fd8f9a259f69b9c9423da9bb16771ed0596cad 100644 (file)
@@ -18,11 +18,11 @@ Construction Parameters
 
     0 is the original format used in the Chromium OS.
       The salt is appended when hashing, digests are stored continuously and
-      the rest of the block is padded with zeros.
+      the rest of the block is padded with zeroes.
 
     1 is the current format that should be used for new devices.
       The salt is prepended when hashing and each digest is
-      padded with zeros to the power of two.
+      padded with zeroes to the power of two.
 
 <dev>
     This is the device containing data, the integrity of which needs to be
@@ -79,6 +79,37 @@ restart_on_corruption
     not compatible with ignore_corruption and requires user space support to
     avoid restart loops.
 
+ignore_zero_blocks
+    Do not verify blocks that are expected to contain zeroes and always return
+    zeroes instead. This may be useful if the partition contains unused blocks
+    that are not guaranteed to contain zeroes.
+
+use_fec_from_device <fec_dev>
+    Use forward error correction (FEC) to recover from corruption if hash
+    verification fails. Use encoding data from the specified device. This
+    may be the same device where data and hash blocks reside, in which case
+    fec_start must be outside data and hash areas.
+
+    If the encoding data covers additional metadata, it must be accessible
+    on the hash device after the hash blocks.
+
+    Note: block sizes for data and hash devices must match. Also, if the
+    verity <dev> is encrypted the <fec_dev> should be too.
+
+fec_roots <num>
+    Number of generator roots. This equals to the number of parity bytes in
+    the encoding data. For example, in RS(M, N) encoding, the number of roots
+    is M-N.
+
+fec_blocks <num>
+    The number of encoding data blocks on the FEC device. The block size for
+    the FEC device is <data_block_size>.
+
+fec_start <offset>
+    This is the offset, in <data_block_size> blocks, from the start of the
+    FEC device to the beginning of the encoding data.
+
+
 Theory of operation
 ===================
 
@@ -98,6 +129,11 @@ per-block basis. This allows for a lightweight hash computation on first read
 into the page cache. Block hashes are stored linearly, aligned to the nearest
 block size.
 
+If forward error correction (FEC) support is enabled any recovery of
+corrupted data will be verified using the cryptographic hash of the
+corresponding data. This is why combining error correction with
+integrity checking is essential.
+
 Hash Tree
 ---------
 
index c2340eeeb97ff072196dbcd49144897813b1573d..c000832a7fb93fbeb1b62d5c896b86eb3606054c 100644 (file)
@@ -30,6 +30,10 @@ Optional properties:
 - target-supply     : regulator for SATA target power
 - phys              : reference to the SATA PHY node
 - phy-names         : must be "sata-phy"
+- ports-implemented : Mask that indicates which ports that the HBA supports
+                     are available for software to use. Useful if PORTS_IMPL
+                     is not programmed by the BIOS, which is true with
+                     some embedded SOC's.
 
 Required properties when using sub-nodes:
 - #address-cells    : number of cells to encode an address
index 0cb44dc21f97ca7cfde5056ce7d44941d3439546..601256fe8c0dd99d2df3ff5a77b2cee23a852e5d 100644 (file)
@@ -45,21 +45,10 @@ Devices supporting OPPs must set their "operating-points-v2" property with
 phandle to a OPP table in their DT node. The OPP core will use this phandle to
 find the operating points for the device.
 
-Devices may want to choose OPP tables at runtime and so can provide a list of
-phandles here. But only *one* of them should be chosen at runtime. This must be
-accompanied by a corresponding "operating-points-names" property, to uniquely
-identify the OPP tables.
-
 If required, this can be extended for SoC vendor specfic bindings. Such bindings
 should be documented as Documentation/devicetree/bindings/power/<vendor>-opp.txt
 and should have a compatible description like: "operating-points-v2-<vendor>".
 
-Optional properties:
-- operating-points-names: Names of OPP tables (required if multiple OPP
-  tables are present), to uniquely identify them. The same list must be present
-  for all the CPUs which are sharing clock/voltage rails and hence the OPP
-  tables.
-
 * OPP Table Node
 
 This describes the OPPs belonging to a device. This node can have following
@@ -100,6 +89,14 @@ Optional properties:
   Entries for multiple regulators must be present in the same order as
   regulators are specified in device's DT node.
 
+- opp-microvolt-<name>: Named opp-microvolt property. This is exactly similar to
+  the above opp-microvolt property, but allows multiple voltage ranges to be
+  provided for the same OPP. At runtime, the platform can pick a <name> and
+  matching opp-microvolt-<name> property will be enabled for all OPPs. If the
+  platform doesn't pick a specific <name> or the <name> doesn't match with any
+  opp-microvolt-<name> properties, then opp-microvolt property shall be used, if
+  present.
+
 - opp-microamp: The maximum current drawn by the device in microamperes
   considering system specific parameters (such as transients, process, aging,
   maximum operating temperature range etc.) as necessary. This may be used to
@@ -112,6 +109,9 @@ Optional properties:
   for few regulators, then this should be marked as zero for them. If it isn't
   required for any regulator, then this property need not be present.
 
+- opp-microamp-<name>: Named opp-microamp property. Similar to
+  opp-microvolt-<name> property, but for microamp instead.
+
 - clock-latency-ns: Specifies the maximum possible transition latency (in
   nanoseconds) for switching to this OPP from any other OPP.
 
@@ -123,6 +123,26 @@ Optional properties:
 - opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in
   the table should have this.
 
+- opp-supported-hw: This enables us to select only a subset of OPPs from the
+  larger OPP table, based on what version of the hardware we are running on. We
+  still can't have multiple nodes with the same opp-hz value in OPP table.
+
+  It's an user defined array containing a hierarchy of hardware version numbers,
+  supported by the OPP. For example: a platform with hierarchy of three levels
+  of versions (A, B and C), this field should be like <X Y Z>, where X
+  corresponds to Version hierarchy A, Y corresponds to version hierarchy B and Z
+  corresponds to version hierarchy C.
+
+  Each level of hierarchy is represented by a 32 bit value, and so there can be
+  only 32 different supported version per hierarchy. i.e. 1 bit per version. A
+  value of 0xFFFFFFFF will enable the OPP for all versions for that hierarchy
+  level. And a value of 0x00000000 will disable the OPP completely, and so we
+  never want that to happen.
+
+  If 32 values aren't sufficient for a version hierarchy, than that version
+  hierarchy can be contained in multiple 32 bit values. i.e. <X Y Z1 Z2> in the
+  above example, Z1 & Z2 refer to the version hierarchy Z.
+
 - status: Marks the node enabled/disabled.
 
 Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together.
@@ -157,20 +177,20 @@ Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together.
                compatible = "operating-points-v2";
                opp-shared;
 
-               opp00 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
                        opp-microvolt = <970000 975000 985000>;
                        opp-microamp = <70000>;
                        clock-latency-ns = <300000>;
                        opp-suspend;
                };
-               opp01 {
+               opp@1100000000 {
                        opp-hz = /bits/ 64 <1100000000>;
                        opp-microvolt = <980000 1000000 1010000>;
                        opp-microamp = <80000>;
                        clock-latency-ns = <310000>;
                };
-               opp02 {
+               opp@1200000000 {
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <1025000>;
                        clock-latency-ns = <290000>;
@@ -236,20 +256,20 @@ independently.
                 * independently.
                 */
 
-               opp00 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
                        opp-microvolt = <970000 975000 985000>;
                        opp-microamp = <70000>;
                        clock-latency-ns = <300000>;
                        opp-suspend;
                };
-               opp01 {
+               opp@1100000000 {
                        opp-hz = /bits/ 64 <1100000000>;
                        opp-microvolt = <980000 1000000 1010000>;
                        opp-microamp = <80000>;
                        clock-latency-ns = <310000>;
                };
-               opp02 {
+               opp@1200000000 {
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <1025000>;
                        opp-microamp = <90000;
@@ -312,20 +332,20 @@ DVFS state together.
                compatible = "operating-points-v2";
                opp-shared;
 
-               opp00 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
                        opp-microvolt = <970000 975000 985000>;
                        opp-microamp = <70000>;
                        clock-latency-ns = <300000>;
                        opp-suspend;
                };
-               opp01 {
+               opp@1100000000 {
                        opp-hz = /bits/ 64 <1100000000>;
                        opp-microvolt = <980000 1000000 1010000>;
                        opp-microamp = <80000>;
                        clock-latency-ns = <310000>;
                };
-               opp02 {
+               opp@1200000000 {
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <1025000>;
                        opp-microamp = <90000>;
@@ -338,20 +358,20 @@ DVFS state together.
                compatible = "operating-points-v2";
                opp-shared;
 
-               opp10 {
+               opp@1300000000 {
                        opp-hz = /bits/ 64 <1300000000>;
                        opp-microvolt = <1045000 1050000 1055000>;
                        opp-microamp = <95000>;
                        clock-latency-ns = <400000>;
                        opp-suspend;
                };
-               opp11 {
+               opp@1400000000 {
                        opp-hz = /bits/ 64 <1400000000>;
                        opp-microvolt = <1075000>;
                        opp-microamp = <100000>;
                        clock-latency-ns = <400000>;
                };
-               opp12 {
+               opp@1500000000 {
                        opp-hz = /bits/ 64 <1500000000>;
                        opp-microvolt = <1010000 1100000 1110000>;
                        opp-microamp = <95000>;
@@ -378,7 +398,7 @@ Example 4: Handling multiple regulators
                compatible = "operating-points-v2";
                opp-shared;
 
-               opp00 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
                        opp-microvolt = <970000>, /* Supply 0 */
                                        <960000>, /* Supply 1 */
@@ -391,7 +411,7 @@ Example 4: Handling multiple regulators
 
                /* OR */
 
-               opp00 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
                        opp-microvolt = <970000 975000 985000>, /* Supply 0 */
                                        <960000 965000 975000>, /* Supply 1 */
@@ -404,7 +424,7 @@ Example 4: Handling multiple regulators
 
                /* OR */
 
-               opp00 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
                        opp-microvolt = <970000 975000 985000>, /* Supply 0 */
                                        <960000 965000 975000>, /* Supply 1 */
@@ -417,7 +437,8 @@ Example 4: Handling multiple regulators
        };
 };
 
-Example 5: Multiple OPP tables
+Example 5: opp-supported-hw
+(example: three level hierarchy of versions: cuts, substrate and process)
 
 / {
        cpus {
@@ -426,40 +447,73 @@ Example 5: Multiple OPP tables
                        ...
 
                        cpu-supply = <&cpu_supply>
-                       operating-points-v2 = <&cpu0_opp_table_slow>, <&cpu0_opp_table_fast>;
-                       operating-points-names = "slow", "fast";
+                       operating-points-v2 = <&cpu0_opp_table_slow>;
                };
        };
 
-       cpu0_opp_table_slow: opp_table_slow {
+       opp_table {
                compatible = "operating-points-v2";
                status = "okay";
                opp-shared;
 
-               opp00 {
+               opp@600000000 {
+                       /*
+                        * Supports all substrate and process versions for 0xF
+                        * cuts, i.e. only first four cuts.
+                        */
+                       opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF>
                        opp-hz = /bits/ 64 <600000000>;
+                       opp-microvolt = <900000 915000 925000>;
                        ...
                };
 
-               opp01 {
+               opp@800000000 {
+                       /*
+                        * Supports:
+                        * - cuts: only one, 6th cut (represented by 6th bit).
+                        * - substrate: supports 16 different substrate versions
+                        * - process: supports 9 different process versions
+                        */
+                       opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0>
                        opp-hz = /bits/ 64 <800000000>;
+                       opp-microvolt = <900000 915000 925000>;
                        ...
                };
        };
+};
+
+Example 6: opp-microvolt-<name>, opp-microamp-<name>:
+(example: device with two possible microvolt ranges: slow and fast)
 
-       cpu0_opp_table_fast: opp_table_fast {
+/ {
+       cpus {
+               cpu@0 {
+                       compatible = "arm,cortex-a7";
+                       ...
+
+                       operating-points-v2 = <&cpu0_opp_table>;
+               };
+       };
+
+       cpu0_opp_table: opp_table0 {
                compatible = "operating-points-v2";
-               status = "okay";
                opp-shared;
 
-               opp10 {
+               opp@1000000000 {
                        opp-hz = /bits/ 64 <1000000000>;
-                       ...
+                       opp-microvolt-slow = <900000 915000 925000>;
+                       opp-microvolt-fast = <970000 975000 985000>;
+                       opp-microamp-slow =  <70000>;
+                       opp-microamp-fast =  <71000>;
                };
 
-               opp11 {
-                       opp-hz = /bits/ 64 <1100000000>;
-                       ...
+               opp@1200000000 {
+                       opp-hz = /bits/ 64 <1200000000>;
+                       opp-microvolt-slow = <900000 915000 925000>, /* Supply vcc0 */
+                                             <910000 925000 935000>; /* Supply vcc1 */
+                       opp-microvolt-fast = <970000 975000 985000>, /* Supply vcc0 */
+                                            <960000 965000 975000>; /* Supply vcc1 */
+                       opp-microamp =  <70000>; /* Will be used for both slow/fast */
                };
        };
 };
index 08a4a32c8eb0db76b533259db2c740316e32a9a3..0326154c792548997457fe6f3252867bbd19a6b4 100644 (file)
@@ -134,12 +134,12 @@ mfio80            ddr_debug, mips_trace_data, mips_debug
 mfio81         dreq0, mips_trace_data, eth_debug
 mfio82         dreq1, mips_trace_data, eth_debug
 mfio83         mips_pll_lock, mips_trace_data, usb_debug
-mfio84         sys_pll_lock, mips_trace_data, usb_debug
-mfio85         wifi_pll_lock, mips_trace_data, sdhost_debug
-mfio86         bt_pll_lock, mips_trace_data, sdhost_debug
-mfio87         rpu_v_pll_lock, dreq2, socif_debug
-mfio88         rpu_l_pll_lock, dreq3, socif_debug
-mfio89         audio_pll_lock, dreq4, dreq5
+mfio84         audio_pll_lock, mips_trace_data, usb_debug
+mfio85         rpu_v_pll_lock, mips_trace_data, sdhost_debug
+mfio86         rpu_l_pll_lock, mips_trace_data, sdhost_debug
+mfio87         sys_pll_lock, dreq2, socif_debug
+mfio88         wifi_pll_lock, dreq3, socif_debug
+mfio89         bt_pll_lock, dreq4, dreq5
 tck
 trstn
 tdi
index e63316239938164be150d0a9d73dac94fa9b4b92..4199ffecc0ff06bde4b26fa5f09d1fd0a9a08601 100644 (file)
@@ -9,7 +9,7 @@
     |       alpha: |  ..  |
     |         arc: | TODO |
     |         arm: |  ok  |
-    |       arm64: |  ..  |
+    |       arm64: |  ok  |
     |       avr32: | TODO |
     |    blackfin: | TODO |
     |         c6x: | TODO |
index af6816bccb439d76a7f80d43f97f4a95e7d604c2..df1d1f3c9af290aa6ffaa1584f71ba6025e54c4e 100644 (file)
@@ -9,7 +9,7 @@
     |       alpha: | TODO |
     |         arc: | TODO |
     |         arm: | TODO |
-    |       arm64: | TODO |
+    |       arm64: |  ok  |
     |       avr32: | TODO |
     |    blackfin: | TODO |
     |         c6x: | TODO |
index 21cf76dbba90bac324ebbc2a5e08a94386205417..554f3844d4993549943caaccbf706bab7e063178 100644 (file)
@@ -3932,6 +3932,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                        sector if the number is odd);
                                i = IGNORE_DEVICE (don't bind to this
                                        device);
+                               j = NO_REPORT_LUNS (don't use report luns
+                                       command, uas only);
                                l = NOT_LOCKABLE (don't try to lock and
                                        unlock ejectable media);
                                m = MAX_SECTORS_64 (don't transfer more
index d826f1b9eb0270fc3f8e17d674360d769541ec52..ab65bbecb159279675cf5bb63e64f1feabf13f44 100644 (file)
@@ -230,13 +230,13 @@ F:        kernel/sys_ni.c
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/abituguru.c
 
 ABIT UGURU 3 HARDWARE MONITOR DRIVER
 M:     Alistair John Strachan <alistair@devzero.co.uk>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/abituguru3.c
 
@@ -373,14 +373,14 @@ S:        Maintained
 
 ADM1025 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/adm1025
 F:     drivers/hwmon/adm1025.c
 
 ADM1029 HARDWARE MONITOR DRIVER
 M:     Corentin Labbe <clabbe.montjoie@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/adm1029.c
 
@@ -425,7 +425,7 @@ F:  drivers/video/backlight/adp8860_bl.c
 
 ADS1015 HARDWARE MONITOR DRIVER
 M:     Dirk Eibach <eibach@gdsys.de>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ads1015
 F:     drivers/hwmon/ads1015.c
@@ -438,7 +438,7 @@ F:  drivers/macintosh/therm_adt746x.c
 
 ADT7475 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/adt7475
 F:     drivers/hwmon/adt7475.c
@@ -615,7 +615,7 @@ F:  include/linux/ccp.h
 
 AMD FAM15H PROCESSOR POWER MONITORING DRIVER
 M:     Andreas Herrmann <herrmann.der.user@googlemail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/fam15h_power
 F:     drivers/hwmon/fam15h_power.c
@@ -779,7 +779,7 @@ F:  drivers/input/mouse/bcm5974.c
 
 APPLE SMC DRIVER
 M:     Henrik Rydberg <rydberg@bitmath.org>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Odd fixes
 F:     drivers/hwmon/applesmc.c
 
@@ -1777,7 +1777,7 @@ F:        include/media/as3645a.h
 
 ASC7621 HARDWARE MONITOR DRIVER
 M:     George Joseph <george.joseph@fairview5.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/asc7621
 F:     drivers/hwmon/asc7621.c
@@ -1864,7 +1864,7 @@ F:        drivers/net/wireless/ath/carl9170/
 
 ATK0110 HWMON DRIVER
 M:     Luca Tettamanti <kronos.it@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/asus_atk0110.c
 
@@ -2984,7 +2984,7 @@ F:        mm/swap_cgroup.c
 
 CORETEMP HARDWARE MONITORING DRIVER
 M:     Fenghua Yu <fenghua.yu@intel.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/coretemp
 F:     drivers/hwmon/coretemp.c
@@ -3549,7 +3549,7 @@ T:        git git://git.infradead.org/users/vkoul/slave-dma.git
 
 DME1737 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/dme1737
 F:     drivers/hwmon/dme1737.c
@@ -4097,8 +4097,8 @@ F:        Documentation/efi-stub.txt
 F:     arch/ia64/kernel/efi.c
 F:     arch/x86/boot/compressed/eboot.[ch]
 F:     arch/x86/include/asm/efi.h
-F:     arch/x86/platform/efi/*
-F:     drivers/firmware/efi/*
+F:     arch/x86/platform/efi/
+F:     drivers/firmware/efi/
 F:     include/linux/efi*.h
 
 EFI VARIABLE FILESYSTEM
@@ -4262,7 +4262,7 @@ F:        include/video/exynos_mipi*
 
 F71805F HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/f71805f
 F:     drivers/hwmon/f71805f.c
@@ -4341,7 +4341,7 @@ F:        fs/*
 
 FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     Riku Voipio <riku.voipio@iki.fi>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/f75375s.c
 F:     include/linux/f75375s.h
@@ -4883,8 +4883,8 @@ F:        drivers/media/usb/hackrf/
 HARDWARE MONITORING
 M:     Jean Delvare <jdelvare@suse.com>
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
-W:     http://www.lm-sensors.org/
+L:     linux-hwmon@vger.kernel.org
+W:     http://hwmon.wiki.kernel.org/
 T:     quilt http://jdelvare.nerim.net/devel/linux/jdelvare-hwmon/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
@@ -5393,7 +5393,7 @@ F:        drivers/usb/atm/ueagle-atm.c
 
 INA209 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ina209
 F:     Documentation/devicetree/bindings/i2c/ina209.txt
@@ -5401,7 +5401,7 @@ F:        drivers/hwmon/ina209.c
 
 INA2XX HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ina2xx
 F:     drivers/hwmon/ina2xx.c
@@ -5884,7 +5884,7 @@ F:        drivers/isdn/hardware/eicon/
 
 IT87 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/it87
 F:     drivers/hwmon/it87.c
@@ -5920,7 +5920,7 @@ F:        drivers/media/dvb-frontends/ix2505v*
 
 JC42.4 TEMPERATURE SENSOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/jc42.c
 F:     Documentation/hwmon/jc42
@@ -5970,14 +5970,14 @@ F:      drivers/tty/serial/jsm/
 
 K10TEMP HARDWARE MONITORING DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/k10temp
 F:     drivers/hwmon/k10temp.c
 
 K8TEMP HARDWARE MONITORING DRIVER
 M:     Rudolf Marek <r.marek@assembler.cz>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/k8temp
 F:     drivers/hwmon/k8temp.c
@@ -6485,27 +6485,27 @@ F:      net/llc/
 
 LM73 HARDWARE MONITOR DRIVER
 M:     Guillaume Ligneul <guillaume.ligneul@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/lm73.c
 
 LM78 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm78
 F:     drivers/hwmon/lm78.c
 
 LM83 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm83
 F:     drivers/hwmon/lm83.c
 
 LM90 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm90
 F:     Documentation/devicetree/bindings/hwmon/lm90.txt
@@ -6513,7 +6513,7 @@ F:        drivers/hwmon/lm90.c
 
 LM95234 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/lm95234
 F:     drivers/hwmon/lm95234.c
@@ -6580,7 +6580,7 @@ F:        drivers/scsi/sym53c8xx_2/
 
 LTC4261 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/ltc4261
 F:     drivers/hwmon/ltc4261.c
@@ -6749,28 +6749,28 @@ F:      include/uapi/linux/matroxfb.h
 
 MAX16065 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max16065
 F:     drivers/hwmon/max16065.c
 
 MAX20751 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max20751
 F:     drivers/hwmon/max20751.c
 
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     "Hans J. Koch" <hjk@hansjkoch.de>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max6650
 F:     drivers/hwmon/max6650.c
 
 MAX6697 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max6697
 F:     Documentation/devicetree/bindings/i2c/max6697.txt
@@ -7303,7 +7303,7 @@ F:        drivers/scsi/NCR_D700.*
 
 NCT6775 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/nct6775
 F:     drivers/hwmon/nct6775.c
@@ -8064,7 +8064,7 @@ F:        drivers/video/logo/logo_parisc*
 
 PC87360 HARDWARE MONITORING DRIVER
 M:     Jim Cromie <jim.cromie@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/pc87360
 F:     drivers/hwmon/pc87360.c
@@ -8076,7 +8076,7 @@ F:        drivers/char/pc8736x_gpio.c
 
 PC87427 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/pc87427
 F:     drivers/hwmon/pc87427.c
@@ -8415,8 +8415,8 @@ F:        drivers/rtc/rtc-puv3.c
 
 PMBUS HARDWARE MONITORING DRIVERS
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
-W:     http://www.lm-sensors.org/
+L:     linux-hwmon@vger.kernel.org
+W:     http://hwmon.wiki.kernel.org/
 W:     http://www.roeck-us.net/linux/drivers/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
@@ -8610,7 +8610,7 @@ F:        drivers/media/usb/pwc/*
 
 PWM FAN DRIVER
 M:     Kamil Debski <k.debski@samsung.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/hwmon/pwm-fan.txt
 F:     Documentation/hwmon/pwm-fan
@@ -9882,28 +9882,28 @@ F:      Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
 
 SMM665 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/smm665
 F:     drivers/hwmon/smm665.c
 
 SMSC EMC2103 HARDWARE MONITOR DRIVER
 M:     Steve Glendinning <steve.glendinning@shawell.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/emc2103
 F:     drivers/hwmon/emc2103.c
 
 SMSC SCH5627 HARDWARE MONITOR DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Supported
 F:     Documentation/hwmon/sch5627
 F:     drivers/hwmon/sch5627.c
 
 SMSC47B397 HARDWARE MONITOR DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/smsc47b397
 F:     drivers/hwmon/smsc47b397.c
@@ -10830,7 +10830,7 @@ F:      include/linux/mmc/sh_mobile_sdhi.h
 
 TMP401 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/tmp401
 F:     drivers/hwmon/tmp401.c
@@ -11564,14 +11564,14 @@ F:    Documentation/networking/vrf.txt
 
 VT1211 HARDWARE MONITOR DRIVER
 M:     Juerg Haefliger <juergh@gmail.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/vt1211
 F:     drivers/hwmon/vt1211.c
 
 VT8231 HARDWARE MONITOR DRIVER
 M:     Roger Lucas <vt8231@hiddenengine.co.uk>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/vt8231.c
 
@@ -11590,21 +11590,21 @@ F:    drivers/w1/
 
 W83791D HARDWARE MONITORING DRIVER
 M:     Marc Hulsman <m.hulsman@tudelft.nl>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/w83791d
 F:     drivers/hwmon/w83791d.c
 
 W83793 HARDWARE MONITORING DRIVER
 M:     Rudolf Marek <r.marek@assembler.cz>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/w83793
 F:     drivers/hwmon/w83793.c
 
 W83795 HARDWARE MONITORING DRIVER
 M:     Jean Delvare <jdelvare@suse.com>
-L:     lm-sensors@lm-sensors.org
+L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     drivers/hwmon/w83795.c
 
index 96e9b02967fbe7521778cf4f592a300bd653606e..55b42efbad8762353df8657847971eaa09d57756 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 4
-SUBLEVEL = 6
+SUBLEVEL = 10
 EXTRAVERSION =
 NAME = Blurry Fish Butt
 
index a4cffb1840d7186a1d736e53131d3eeab3e59450..fa53af0c37ad72c28a569bfa3ccae52abffa4f61 100644 (file)
@@ -21,6 +21,7 @@ CONFIG_CGROUP_SCHED=y
 CONFIG_CP15_BARRIER_EMULATION=y
 CONFIG_DM_CRYPT=y
 CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
 CONFIG_EMBEDDED=y
 CONFIG_FB=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -28,6 +29,7 @@ CONFIG_INET6_AH=y
 CONFIG_INET6_ESP=y
 CONFIG_INET6_IPCOMP=y
 CONFIG_INET=y
+CONFIG_INET_DIAG_DESTROY=y
 CONFIG_INET_ESP=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_IP6_NF_FILTER=y
index 57c1f33844d44f1f9d16ed448ce0b13e87b88cea..0352fb8d21b998223b03e2bc327c3f4554df6ec5 100644 (file)
@@ -35,21 +35,6 @@ static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\
                                                                        \
        m += nr >> 5;                                                   \
                                                                        \
-       /*                                                              \
-        * ARC ISA micro-optimization:                                  \
-        *                                                              \
-        * Instructions dealing with bitpos only consider lower 5 bits  \
-        * e.g (x << 33) is handled like (x << 1) by ASL instruction    \
-        *  (mem pointer still needs adjustment to point to next word)  \
-        *                                                              \
-        * Hence the masking to clamp @nr arg can be elided in general. \
-        *                                                              \
-        * However if @nr is a constant (above assumed in a register),  \
-        * and greater than 31, gcc can optimize away (x << 33) to 0,   \
-        * as overflow, given the 32-bit ISA. Thus masking needs to be  \
-        * done for const @nr, but no code is generated due to gcc      \
-        * const prop.                                                  \
-        */                                                             \
        nr &= 0x1f;                                                     \
                                                                        \
        __asm__ __volatile__(                                           \
index 694ece8a024372bef7fd24b3ccb1e9dc323b4afe..cb69299a492e57fa781839148ee72b886f0cb4e6 100644 (file)
 #include <asm/byteorder.h>
 #include <asm/page.h>
 
+#ifdef CONFIG_ISA_ARCV2
+#include <asm/barrier.h>
+#define __iormb()              rmb()
+#define __iowmb()              wmb()
+#else
+#define __iormb()              do { } while (0)
+#define __iowmb()              do { } while (0)
+#endif
+
 extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
 extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
                                  unsigned long flags);
@@ -22,6 +31,15 @@ extern void iounmap(const void __iomem *addr);
 #define ioremap_wc(phy, sz)            ioremap(phy, sz)
 #define ioremap_wt(phy, sz)            ioremap(phy, sz)
 
+/*
+ * io{read,write}{16,32}be() macros
+ */
+#define ioread16be(p)          ({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32be(p)          ({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
+
+#define iowrite16be(v,p)       ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); })
+#define iowrite32be(v,p)       ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); })
+
 /* Change struct page to physical address */
 #define page_to_phys(page)             (page_to_pfn(page) << PAGE_SHIFT)
 
@@ -99,15 +117,6 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
 
 }
 
-#ifdef CONFIG_ISA_ARCV2
-#include <asm/barrier.h>
-#define __iormb()              rmb()
-#define __iowmb()              wmb()
-#else
-#define __iormb()              do { } while (0)
-#define __iowmb()              do { } while (0)
-#endif
-
 /*
  * MMIO can also get buffered/optimized in micro-arch, so barriers needed
  * Based on ARM model for the typical use case
@@ -129,15 +138,23 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
 #define writel(v,c)            ({ __iowmb(); writel_relaxed(v,c); })
 
 /*
- * Relaxed API for drivers which can handle any ordering themselves
+ * Relaxed API for drivers which can handle barrier ordering themselves
+ *
+ * Also these are defined to perform little endian accesses.
+ * To provide the typical device register semantics of fixed endian,
+ * swap the byte order for Big Endian
+ *
+ * http://lkml.kernel.org/r/201603100845.30602.arnd@arndb.de
  */
 #define readb_relaxed(c)       __raw_readb(c)
-#define readw_relaxed(c)       __raw_readw(c)
-#define readl_relaxed(c)       __raw_readl(c)
+#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
+                                       __raw_readw(c)); __r; })
+#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+                                       __raw_readl(c)); __r; })
 
 #define writeb_relaxed(v,c)    __raw_writeb(v,c)
-#define writew_relaxed(v,c)    __raw_writew(v,c)
-#define writel_relaxed(v,c)    __raw_writel(v,c)
+#define writew_relaxed(v,c)    __raw_writew((__force u16) cpu_to_le16(v),c)
+#define writel_relaxed(v,c)    __raw_writel((__force u32) cpu_to_le32(v),c)
 
 #include <asm-generic/io.h>
 
index 47954ed990f8be83c9aabe38b3878911d21f92a2..00707aac72fc4971d5c4148f512f7b816b48ce31 100644 (file)
        tx-num-evt = <32>;
        rx-num-evt = <32>;
 };
+
+&synctimer_32kclk {
+       assigned-clocks = <&mux_synctimer32k_ck>;
+       assigned-clock-parents = <&clkdiv32k_ick>;
+};
index 7ccce7529b0c8debe46f6d4d28c9d51b143738cf..cc952cf8ec3003b6339629161b40e2410ece51d4 100644 (file)
                        };
 
                        sata@a0000 {
-                               compatible = "marvell,orion-sata";
+                               compatible = "marvell,armada-370-sata";
                                reg = <0xa0000 0x5000>;
                                interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&gateclk 14>, <&gateclk 20>;
index 3710755c6d76b52fe339ea8f8f71d7dd8a1dc0ec..85d2c377c3322f6be3a612d85661534771896153 100644 (file)
                        };
 
                        /* USB part of the eSATA/USB 2.0 port */
-                       usb@50000 {
+                       usb@58000 {
                                status = "okay";
                        };
 
index ff888d21c786a69b1f56c768ea6a2219056b98dc..f3e2b96c06a361ed01f240797f299ae4a129249c 100644 (file)
                regulator-name = "mmc0-card-supply";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               regulator-always-on;
        };
 
        gpio_keys {
index 569026e8f96cadaf25eeb10ca207c02c7f175121..da84e65b56ef15f9f56675b4f3937fe04002e627 100644 (file)
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                vin-supply = <&vcc_3v3_reg>;
+               regulator-always-on;
        };
 };
index cf6998a0804d418be89e476de2645fe293845bab..564341af7e972e81fa04a1c5c187668a3744a0ea 100644 (file)
@@ -30,7 +30,7 @@
                        reg = <0x43100000 90>;
                        interrupts = <45>;
                        clocks = <&clks CLK_NAND>;
-                       dmas = <&pdma 97>;
+                       dmas = <&pdma 97 3>;
                        dma-names = "data";
                        #address-cells = <1>;
                        #size-cells = <1>;      
index 194c91b610ffecfd4071da89d16b923c614bf68d..c35c349da06983b5eee05bc8bca52e526ed1bc52 100644 (file)
@@ -79,6 +79,8 @@
 #define rr_lo_hi(a1, a2) a1, a2
 #endif
 
+#define kvm_ksym_ref(kva)      (kva)
+
 #ifndef __ASSEMBLY__
 struct kvm;
 struct kvm_vcpu;
index e06fd299de0846b44b72cd037eacd05b0b2cb051..70e6d557c75f696e537fe2a48bb4cc55721a6f8c 100644 (file)
@@ -969,7 +969,7 @@ static void cpu_init_hyp_mode(void *dummy)
        pgd_ptr = kvm_mmu_get_httbr();
        stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
        hyp_stack_ptr = stack_page + PAGE_SIZE;
-       vector_ptr = (unsigned long)__kvm_hyp_vector;
+       vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
 
        __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
 
@@ -1061,7 +1061,8 @@ static int init_hyp_mode(void)
        /*
         * Map the Hyp-code called directly from the host
         */
-       err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end);
+       err = create_hyp_mappings(kvm_ksym_ref(__kvm_hyp_code_start),
+                                 kvm_ksym_ref(__kvm_hyp_code_end));
        if (err) {
                kvm_err("Cannot map world-switch code\n");
                goto out_free_mappings;
index 47905a50e0757e94c1300ec98a3924d9a51b7a5b..318394ed5c7a97c2923c8c35134b88cb188ef238 100644 (file)
@@ -220,13 +220,13 @@ static void cns3xxx_write_config(struct cns3xxx_pcie *cnspci,
        u32 mask = (0x1ull << (size * 8)) - 1;
        int shift = (where % 4) * 8;
 
-       v = readl_relaxed(base + (where & 0xffc));
+       v = readl_relaxed(base);
 
        v &= ~(mask << shift);
        v |= (val & mask) << shift;
 
-       writel_relaxed(v, base + (where & 0xffc));
-       readl_relaxed(base + (where & 0xffc));
+       writel_relaxed(v, base);
+       readl_relaxed(base);
 }
 
 static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
index 3a10f1a8317ae7a053ed997da88a06ddd5311b57..bfd8bb3714773f89d7a4d705c9300047b6d7eeda 100644 (file)
@@ -26,6 +26,7 @@ menuconfig ARCH_EXYNOS
        select S5P_DEV_MFC
        select SRAM
        select THERMAL
+       select THERMAL_OF
        select MFD_SYSCON
        help
          Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
index 7c21760f590ffd0d4cd47fcafcbcaffe64a85952..875a2bab64f67b1a7dda20e216a264f01679f8a9 100644 (file)
@@ -92,7 +92,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
                        if (IS_ERR(pd->clk[i]))
                                break;
 
-                       if (IS_ERR(pd->clk[i]))
+                       if (IS_ERR(pd->pclk[i]))
                                continue; /* Skip on first power up */
                        if (clk_set_parent(pd->clk[i], pd->pclk[i]))
                                pr_err("%s: error setting parent to clock%d\n",
index aa7b379e266148fa8990165a8dae7ba3e09edcf7..2a3db0bd9e15c3d942199c5d4ac089868ca3e7bf 100644 (file)
@@ -34,6 +34,7 @@
 #include "pm.h"
 #include "control.h"
 #include "common.h"
+#include "soc.h"
 
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
@@ -315,6 +316,69 @@ static struct cpuidle_driver omap3_idle_driver = {
        .safe_state_index = 0,
 };
 
+/*
+ * Numbers based on measurements made in October 2009 for PM optimized kernel
+ * with CPU freq enabled on device Nokia N900. Assumes OPP2 (main idle OPP,
+ * and worst case latencies).
+ */
+static struct cpuidle_driver omap3430_idle_driver = {
+       .name             = "omap3430_idle",
+       .owner            = THIS_MODULE,
+       .states = {
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 110 + 162,
+                       .target_residency = 5,
+                       .name             = "C1",
+                       .desc             = "MPU ON + CORE ON",
+               },
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 106 + 180,
+                       .target_residency = 309,
+                       .name             = "C2",
+                       .desc             = "MPU ON + CORE ON",
+               },
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 107 + 410,
+                       .target_residency = 46057,
+                       .name             = "C3",
+                       .desc             = "MPU RET + CORE ON",
+               },
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 121 + 3374,
+                       .target_residency = 46057,
+                       .name             = "C4",
+                       .desc             = "MPU OFF + CORE ON",
+               },
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 855 + 1146,
+                       .target_residency = 46057,
+                       .name             = "C5",
+                       .desc             = "MPU RET + CORE RET",
+               },
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 7580 + 4134,
+                       .target_residency = 484329,
+                       .name             = "C6",
+                       .desc             = "MPU OFF + CORE RET",
+               },
+               {
+                       .enter            = omap3_enter_idle_bm,
+                       .exit_latency     = 7505 + 15274,
+                       .target_residency = 484329,
+                       .name             = "C7",
+                       .desc             = "MPU OFF + CORE OFF",
+               },
+       },
+       .state_count = ARRAY_SIZE(omap3_idle_data),
+       .safe_state_index = 0,
+};
+
 /* Public functions */
 
 /**
@@ -333,5 +397,8 @@ int __init omap3_idle_init(void)
        if (!mpu_pd || !core_pd || !per_pd || !cam_pd)
                return -ENODEV;
 
-       return cpuidle_register(&omap3_idle_driver, NULL);
+       if (cpu_is_omap3430())
+               return cpuidle_register(&omap3430_idle_driver, NULL);
+       else
+               return cpuidle_register(&omap3_idle_driver, NULL);
 }
index 3eaeaca5da05f95fffe03d8927bc0b9ec0f63ef5..3a911d8dea8baaf4b56a623ceda403b65a990d27 100644 (file)
@@ -368,6 +368,7 @@ void __init omap5_map_io(void)
 void __init dra7xx_map_io(void)
 {
        iotable_init(dra7xx_io_desc, ARRAY_SIZE(dra7xx_io_desc));
+       omap_barriers_init();
 }
 #endif
 /*
index 8e0bd5939e5a1874444117189ffc5c7ff9cb644a..147c90e70b2e040c559b13511bc03ad81e3d7b31 100644 (file)
@@ -1416,9 +1416,7 @@ static void _enable_sysc(struct omap_hwmod *oh)
            (sf & SYSC_HAS_CLOCKACTIVITY))
                _set_clockactivity(oh, oh->class->sysc->clockact, &v);
 
-       /* If the cached value is the same as the new value, skip the write */
-       if (oh->_sysc_cache != v)
-               _write_sysconfig(v, oh);
+       _write_sysconfig(v, oh);
 
        /*
         * Set the autoidle bit only after setting the smartidle bit
@@ -1481,7 +1479,9 @@ static void _idle_sysc(struct omap_hwmod *oh)
                _set_master_standbymode(oh, idlemode, &v);
        }
 
-       _write_sysconfig(v, oh);
+       /* If the cached value is the same as the new value, skip the write */
+       if (oh->_sysc_cache != v)
+               _write_sysconfig(v, oh);
 }
 
 /**
index 9ab8932403e5dede46f37dabfd5d8658b01a405e..56e55fd37d1335a4da9ca1fb4c9f6cb815e0a558 100644 (file)
@@ -1,6 +1,7 @@
 menuconfig ARCH_SIRF
        bool "CSR SiRF" if ARCH_MULTI_V7
        select ARCH_HAS_RESET_CONTROLLER
+       select RESET_CONTROLLER
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_IRQ_CHIP
        select NO_IOPORT_MAP
index ff780a8d8366fbe5463b665ea3d53c14d797a569..9a42736ef4ac9e3e3039b1a5ae31b1d66d020245 100644 (file)
@@ -54,12 +54,12 @@ static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
 
 static struct resource s3c64xx_iis0_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
-       [2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
 };
 
-static struct s3c_audio_pdata i2sv3_pdata = {
+static struct s3c_audio_pdata i2s0_pdata = {
        .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .dma_playback = DMACH_I2S0_OUT,
+       .dma_capture = DMACH_I2S0_IN,
 };
 
 struct platform_device s3c64xx_device_iis0 = {
@@ -68,15 +68,19 @@ struct platform_device s3c64xx_device_iis0 = {
        .num_resources    = ARRAY_SIZE(s3c64xx_iis0_resource),
        .resource         = s3c64xx_iis0_resource,
        .dev = {
-               .platform_data = &i2sv3_pdata,
+               .platform_data = &i2s0_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iis0);
 
 static struct resource s3c64xx_iis1_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
-       [2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
+};
+
+static struct s3c_audio_pdata i2s1_pdata = {
+       .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .dma_playback = DMACH_I2S1_OUT,
+       .dma_capture = DMACH_I2S1_IN,
 };
 
 struct platform_device s3c64xx_device_iis1 = {
@@ -85,19 +89,19 @@ struct platform_device s3c64xx_device_iis1 = {
        .num_resources    = ARRAY_SIZE(s3c64xx_iis1_resource),
        .resource         = s3c64xx_iis1_resource,
        .dev = {
-               .platform_data = &i2sv3_pdata,
+               .platform_data = &i2s1_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iis1);
 
 static struct resource s3c64xx_iisv4_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
-       [2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
 };
 
 static struct s3c_audio_pdata i2sv4_pdata = {
        .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .dma_playback = DMACH_HSI_I2SV40_TX,
+       .dma_capture = DMACH_HSI_I2SV40_RX,
        .type = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN,
@@ -142,12 +146,12 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
 
 static struct resource s3c64xx_pcm0_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
-       [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm0_pdata = {
        .cfg_gpio = s3c64xx_pcm_cfg_gpio,
+       .dma_capture = DMACH_PCM0_RX,
+       .dma_playback = DMACH_PCM0_TX,
 };
 
 struct platform_device s3c64xx_device_pcm0 = {
@@ -163,12 +167,12 @@ EXPORT_SYMBOL(s3c64xx_device_pcm0);
 
 static struct resource s3c64xx_pcm1_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
-       [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
 };
 
 static struct s3c_audio_pdata s3c_pcm1_pdata = {
        .cfg_gpio = s3c64xx_pcm_cfg_gpio,
+       .dma_playback = DMACH_PCM1_TX,
+       .dma_capture = DMACH_PCM1_RX,
 };
 
 struct platform_device s3c64xx_device_pcm1 = {
@@ -196,13 +200,14 @@ static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev)
 
 static struct resource s3c64xx_ac97_resource[] = {
        [0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
-       [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
-       [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
-       [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
-       [4] = DEFINE_RES_IRQ(IRQ_AC97),
+       [1] = DEFINE_RES_IRQ(IRQ_AC97),
 };
 
-static struct s3c_audio_pdata s3c_ac97_pdata;
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+       .dma_playback = DMACH_AC97_PCMOUT,
+       .dma_capture = DMACH_AC97_PCMIN,
+       .dma_capture_mic = DMACH_AC97_MICIN,
+};
 
 static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
 
index 096e14073bd9225f9218550ee5a9ce13053f4717..9c739eafe95c48a111721e9539907ee8bd8b95a4 100644 (file)
 #define S3C64XX_DMA_CHAN(name)         ((unsigned long)(name))
 
 /* DMA0/SDMA0 */
-#define DMACH_UART0            S3C64XX_DMA_CHAN("uart0_tx")
-#define DMACH_UART0_SRC2       S3C64XX_DMA_CHAN("uart0_rx")
-#define DMACH_UART1            S3C64XX_DMA_CHAN("uart1_tx")
-#define DMACH_UART1_SRC2       S3C64XX_DMA_CHAN("uart1_rx")
-#define DMACH_UART2            S3C64XX_DMA_CHAN("uart2_tx")
-#define DMACH_UART2_SRC2       S3C64XX_DMA_CHAN("uart2_rx")
-#define DMACH_UART3            S3C64XX_DMA_CHAN("uart3_tx")
-#define DMACH_UART3_SRC2       S3C64XX_DMA_CHAN("uart3_rx")
-#define DMACH_PCM0_TX          S3C64XX_DMA_CHAN("pcm0_tx")
-#define DMACH_PCM0_RX          S3C64XX_DMA_CHAN("pcm0_rx")
-#define DMACH_I2S0_OUT         S3C64XX_DMA_CHAN("i2s0_tx")
-#define DMACH_I2S0_IN          S3C64XX_DMA_CHAN("i2s0_rx")
+#define DMACH_UART0            "uart0_tx"
+#define DMACH_UART0_SRC2       "uart0_rx"
+#define DMACH_UART1            "uart1_tx"
+#define DMACH_UART1_SRC2       "uart1_rx"
+#define DMACH_UART2            "uart2_tx"
+#define DMACH_UART2_SRC2       "uart2_rx"
+#define DMACH_UART3            "uart3_tx"
+#define DMACH_UART3_SRC2       "uart3_rx"
+#define DMACH_PCM0_TX          "pcm0_tx"
+#define DMACH_PCM0_RX          "pcm0_rx"
+#define DMACH_I2S0_OUT         "i2s0_tx"
+#define DMACH_I2S0_IN          "i2s0_rx"
 #define DMACH_SPI0_TX          S3C64XX_DMA_CHAN("spi0_tx")
 #define DMACH_SPI0_RX          S3C64XX_DMA_CHAN("spi0_rx")
-#define DMACH_HSI_I2SV40_TX    S3C64XX_DMA_CHAN("i2s2_tx")
-#define DMACH_HSI_I2SV40_RX    S3C64XX_DMA_CHAN("i2s2_rx")
+#define DMACH_HSI_I2SV40_TX    "i2s2_tx"
+#define DMACH_HSI_I2SV40_RX    "i2s2_rx"
 
 /* DMA1/SDMA1 */
-#define DMACH_PCM1_TX          S3C64XX_DMA_CHAN("pcm1_tx")
-#define DMACH_PCM1_RX          S3C64XX_DMA_CHAN("pcm1_rx")
-#define DMACH_I2S1_OUT         S3C64XX_DMA_CHAN("i2s1_tx")
-#define DMACH_I2S1_IN          S3C64XX_DMA_CHAN("i2s1_rx")
+#define DMACH_PCM1_TX          "pcm1_tx"
+#define DMACH_PCM1_RX          "pcm1_rx"
+#define DMACH_I2S1_OUT         "i2s1_tx"
+#define DMACH_I2S1_IN          "i2s1_rx"
 #define DMACH_SPI1_TX          S3C64XX_DMA_CHAN("spi1_tx")
 #define DMACH_SPI1_RX          S3C64XX_DMA_CHAN("spi1_rx")
-#define DMACH_AC97_PCMOUT      S3C64XX_DMA_CHAN("ac97_out")
-#define DMACH_AC97_PCMIN       S3C64XX_DMA_CHAN("ac97_in")
-#define DMACH_AC97_MICIN       S3C64XX_DMA_CHAN("ac97_mic")
-#define DMACH_PWM              S3C64XX_DMA_CHAN("pwm")
-#define DMACH_IRDA             S3C64XX_DMA_CHAN("irda")
-#define DMACH_EXTERNAL         S3C64XX_DMA_CHAN("external")
-#define DMACH_SECURITY_RX      S3C64XX_DMA_CHAN("sec_rx")
-#define DMACH_SECURITY_TX      S3C64XX_DMA_CHAN("sec_tx")
+#define DMACH_AC97_PCMOUT      "ac97_out"
+#define DMACH_AC97_PCMIN       "ac97_in"
+#define DMACH_AC97_MICIN       "ac97_mic"
+#define DMACH_PWM              "pwm"
+#define DMACH_IRDA             "irda"
+#define DMACH_EXTERNAL         "external"
+#define DMACH_SECURITY_RX      "sec_rx"
+#define DMACH_SECURITY_TX      "sec_tx"
 
 enum dma_ch {
        DMACH_MAX = 32
index 5d94b7a2fb108dc1bc1c5fcdd4edfa80ab2c0c7f..c160fa3007e943be451b82318149a69dce4d7e54 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/assembler.h>
 
        .arch   armv7-a
+       .arm
 
 ENTRY(secondary_trampoline)
        /* CPU1 will always fetch from 0x0 when it is brought out of reset.
index 82074625de5cebfc7681f72c931c90d1b7e951ac..e212f9d804bd7bd4e17838894e11ee4697c35d8c 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/platform_data/usb-ohci-s3c2410.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-spi.h>
+#include <linux/platform_data/asoc-s3c.h>
 #include <linux/platform_data/spi-s3c64xx.h>
 
 static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -74,9 +75,12 @@ static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
 static struct resource s3c_ac97_resource[] = {
        [0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97),
        [1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97),
-       [2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"),
-       [3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"),
-       [4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"),
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+       .dma_playback = (void *)DMACH_PCM_OUT,
+       .dma_capture = (void *)DMACH_PCM_IN,
+       .dma_capture_mic = (void *)DMACH_MIC_IN,
 };
 
 struct platform_device s3c_device_ac97 = {
@@ -87,6 +91,7 @@ struct platform_device s3c_device_ac97 = {
        .dev            = {
                .dma_mask               = &samsung_device_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &s3c_ac97_pdata,
        }
 };
 #endif /* CONFIG_CPU_S3C2440 */
index 579ab688312de4a74ea186d4ba644d19058b8108..b1d8af794678a6245a373a6e3a6c166d116cd9e2 100644 (file)
@@ -13,6 +13,7 @@ config ARM64
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        select ARCH_WANT_FRAME_POINTERS
+       select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARM_AMBA
        select ARM_ARCH_TIMER
        select ARM_GIC
@@ -48,6 +49,7 @@ config ARM64
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_BITREVERSE
+       select HAVE_ARCH_HUGE_VMAP
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48)
        select HAVE_ARCH_KGDB
@@ -72,6 +74,7 @@ config ARM64
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
+       select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_MEMBLOCK
        select HAVE_PATA_PLATFORM
        select HAVE_PERF_EVENTS
@@ -395,6 +398,7 @@ config ARM64_ERRATUM_843419
        bool "Cortex-A53: 843419: A load or store might access an incorrect address"
        depends on MODULES
        default y
+       select ARM64_MODULE_CMODEL_LARGE
        help
          This option builds kernel modules using the large memory model in
          order to avoid the use of the ADRP instruction, which can cause
@@ -539,6 +543,9 @@ config HOTPLUG_CPU
 source kernel/Kconfig.preempt
 source kernel/Kconfig.hz
 
+config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       def_bool y
+
 config ARCH_HAS_HOLES_MEMORYMODEL
        def_bool y if SPARSEMEM
 
@@ -562,9 +569,6 @@ config HW_PERF_EVENTS
 config SYS_SUPPORTS_HUGETLBFS
        def_bool y
 
-config ARCH_WANT_GENERAL_HUGETLB
-       def_bool y
-
 config ARCH_WANT_HUGE_PMD_SHARE
        def_bool y if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
 
@@ -737,10 +741,93 @@ config ARM64_LSE_ATOMICS
 
 endmenu
 
+config ARM64_UAO
+       bool "Enable support for User Access Override (UAO)"
+       default y
+       help
+         User Access Override (UAO; part of the ARMv8.2 Extensions)
+         causes the 'unprivileged' variant of the load/store instructions to
+         be overriden to be privileged.
+
+         This option changes get_user() and friends to use the 'unprivileged'
+         variant of the load/store instructions. This ensures that user-space
+         really did have access to the supplied memory. When addr_limit is
+         set to kernel memory the UAO bit will be set, allowing privileged
+         access to kernel memory.
+
+         Choosing this option will cause copy_to_user() et al to use user-space
+         memory permissions.
+
+         The feature is detected at runtime, the kernel will use the
+         regular load/store instructions if the cpu does not implement the
+         feature.
+
+config ARM64_MODULE_CMODEL_LARGE
+       bool
+
+config ARM64_MODULE_PLTS
+       bool
+       select ARM64_MODULE_CMODEL_LARGE
+       select HAVE_MOD_ARCH_SPECIFIC
+
+config RELOCATABLE
+       bool
+       help
+         This builds the kernel as a Position Independent Executable (PIE),
+         which retains all relocation metadata required to relocate the
+         kernel binary at runtime to a different virtual address than the
+         address it was linked at.
+         Since AArch64 uses the RELA relocation format, this requires a
+         relocation pass at runtime even if the kernel is loaded at the
+         same address it was linked at.
+
+config RANDOMIZE_BASE
+       bool "Randomize the address of the kernel image"
+       select ARM64_MODULE_PLTS
+       select RELOCATABLE
+       help
+         Randomizes the virtual address at which the kernel image is
+         loaded, as a security feature that deters exploit attempts
+         relying on knowledge of the location of kernel internals.
+
+         It is the bootloader's job to provide entropy, by passing a
+         random u64 value in /chosen/kaslr-seed at kernel entry.
+
+         When booting via the UEFI stub, it will invoke the firmware's
+         EFI_RNG_PROTOCOL implementation (if available) to supply entropy
+         to the kernel proper. In addition, it will randomise the physical
+         location of the kernel Image as well.
+
+         If unsure, say N.
+
+config RANDOMIZE_MODULE_REGION_FULL
+       bool "Randomize the module region independently from the core kernel"
+       depends on RANDOMIZE_BASE
+       default y
+       help
+         Randomizes the location of the module region without considering the
+         location of the core kernel. This way, it is impossible for modules
+         to leak information about the location of core kernel data structures
+         but it does imply that function calls between modules and the core
+         kernel will need to be resolved via veneers in the module PLT.
+
+         When this option is not set, the module region will be randomized over
+         a limited range that contains the [_stext, _etext] interval of the
+         core kernel, so branch relocations are always in range.
+
 endmenu
 
 menu "Boot options"
 
+config ARM64_ACPI_PARKING_PROTOCOL
+       bool "Enable support for the ARM64 ACPI parking protocol"
+       depends on ACPI
+       help
+         Enable support for the ARM64 ACPI parking protocol. If disabled
+         the kernel will not allow booting through the ARM64 ACPI parking
+         protocol even if the corresponding data is present in the ACPI
+         MADT table.
+
 config CMDLINE
        string "Default kernel command string"
        default ""
index e2cfcc8af6483162a0be3acadf65ec01bb532544..d3f03c6752b96bcc70c5226d97b535dc0962b618 100644 (file)
@@ -15,6 +15,10 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 OBJCOPYFLAGS   :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 GZFLAGS                :=-9
 
+ifneq ($(CONFIG_RELOCATABLE),)
+LDFLAGS_vmlinux                += -pie
+endif
+
 KBUILD_DEFCONFIG := defconfig
 
 # Check for binutils support for specific extensions
@@ -29,6 +33,7 @@ endif
 KBUILD_CFLAGS  += -mgeneral-regs-only $(lseinstr)
 KBUILD_CFLAGS  += -fno-pic
 KBUILD_CFLAGS  += $(call cc-option, -mpc-relative-literal-loads)
+KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables
 KBUILD_AFLAGS  += $(lseinstr)
 
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
@@ -43,10 +48,14 @@ endif
 
 CHECKFLAGS     += -D__aarch64__
 
-ifeq ($(CONFIG_ARM64_ERRATUM_843419), y)
+ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y)
 KBUILD_CFLAGS_MODULE   += -mcmodel=large
 endif
 
+ifeq ($(CONFIG_ARM64_MODULE_PLTS),y)
+KBUILD_LDFLAGS_MODULE  += -T $(srctree)/arch/arm64/kernel/module.lds
+endif
+
 # Default value
 head-y         := arch/arm64/kernel/head.o
 
index caafd63b8092d8102401112d811b1055f4cc3524..aee323b13802ad143e9774d2076a4b1c63731ece 100644 (file)
@@ -87,9 +87,26 @@ void __init acpi_init_cpus(void);
 static inline void acpi_init_cpus(void) { }
 #endif /* CONFIG_ACPI */
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+bool acpi_parking_protocol_valid(int cpu);
+void __init
+acpi_set_mailbox_entry(int cpu, struct acpi_madt_generic_interrupt *processor);
+#else
+static inline bool acpi_parking_protocol_valid(int cpu) { return false; }
+static inline void
+acpi_set_mailbox_entry(int cpu, struct acpi_madt_generic_interrupt *processor)
+{}
+#endif
+
 static inline const char *acpi_get_enable_method(int cpu)
 {
-       return acpi_psci_present() ? "psci" : NULL;
+       if (acpi_psci_present())
+               return "psci";
+
+       if (acpi_parking_protocol_valid(cpu))
+               return "parking-protocol";
+
+       return NULL;
 }
 
 #ifdef CONFIG_ACPI_APEI
index d56ec07151570e6e498e9bf35b2fd9ccaed335fe..beccbdefa106a4ba0dd7d98537427a37d2c26517 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_ALTERNATIVE_H
 #define __ASM_ALTERNATIVE_H
 
+#include <asm/cpufeature.h>
+
 #ifndef __ASSEMBLY__
 
 #include <linux/init.h>
@@ -19,7 +21,6 @@ struct alt_instr {
 
 void __init apply_alternatives_all(void);
 void apply_alternatives(void *start, size_t length);
-void free_alternatives_memory(void);
 
 #define ALTINSTR_ENTRY(feature)                                                      \
        " .word 661b - .\n"                             /* label           */ \
@@ -64,6 +65,8 @@ void free_alternatives_memory(void);
 
 #else
 
+#include <asm/assembler.h>
+
 .macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
        .word \orig_offset - .
        .word \alt_offset - .
@@ -137,6 +140,65 @@ void free_alternatives_memory(void);
        alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
 
 
+/*
+ * Generate the assembly for UAO alternatives with exception table entries.
+ * This is complicated as there is no post-increment or pair versions of the
+ * unprivileged instructions, and USER() only works for single instructions.
+ */
+#ifdef CONFIG_ARM64_UAO
+       .macro uao_ldp l, reg1, reg2, addr, post_inc
+               alternative_if_not ARM64_HAS_UAO
+8888:                  ldp     \reg1, \reg2, [\addr], \post_inc;
+8889:                  nop;
+                       nop;
+               alternative_else
+                       ldtr    \reg1, [\addr];
+                       ldtr    \reg2, [\addr, #8];
+                       add     \addr, \addr, \post_inc;
+               alternative_endif
+
+               _asm_extable    8888b,\l;
+               _asm_extable    8889b,\l;
+       .endm
+
+       .macro uao_stp l, reg1, reg2, addr, post_inc
+               alternative_if_not ARM64_HAS_UAO
+8888:                  stp     \reg1, \reg2, [\addr], \post_inc;
+8889:                  nop;
+                       nop;
+               alternative_else
+                       sttr    \reg1, [\addr];
+                       sttr    \reg2, [\addr, #8];
+                       add     \addr, \addr, \post_inc;
+               alternative_endif
+
+               _asm_extable    8888b,\l;
+               _asm_extable    8889b,\l;
+       .endm
+
+       .macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
+               alternative_if_not ARM64_HAS_UAO
+8888:                  \inst   \reg, [\addr], \post_inc;
+                       nop;
+               alternative_else
+                       \alt_inst       \reg, [\addr];
+                       add             \addr, \addr, \post_inc;
+               alternative_endif
+
+               _asm_extable    8888b,\l;
+       .endm
+#else
+       .macro uao_ldp l, reg1, reg2, addr, post_inc
+               USER(\l, ldp \reg1, \reg2, [\addr], \post_inc)
+       .endm
+       .macro uao_stp l, reg1, reg2, addr, post_inc
+               USER(\l, stp \reg1, \reg2, [\addr], \post_inc)
+       .endm
+       .macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
+               USER(\l, \inst \reg, [\addr], \post_inc)
+       .endm
+#endif
+
 #endif  /*  __ASSEMBLY__  */
 
 /*
index 12eff928ef8b38dd18ae3bd157b12eb918f797a6..70f7b9e04598bdf953b56d40794f1ab5aaf966ca 100644 (file)
        dmb     \opt
        .endm
 
+/*
+ * Emit an entry into the exception table
+ */
+       .macro          _asm_extable, from, to
+       .pushsection    __ex_table, "a"
+       .align          3
+       .long           (\from - .), (\to - .)
+       .popsection
+       .endm
+
 #define USER(l, x...)                          \
 9999:  x;                                      \
-       .section __ex_table,"a";                \
-       .align  3;                              \
-       .quad   9999b,l;                        \
-       .previous
+       _asm_extable    9999b, l
 
 /*
  * Register aliases.
@@ -193,6 +200,17 @@ lr .req    x30             // link register
        str     \src, [\tmp, :lo12:\sym]
        .endm
 
+       /*
+        * @sym: The name of the per-cpu variable
+        * @reg: Result of per_cpu(sym, smp_processor_id())
+        * @tmp: scratch register
+        */
+       .macro this_cpu_ptr, sym, reg, tmp
+       adr_l   \reg, \sym
+       mrs     \tmp, tpidr_el1
+       add     \reg, \reg, \tmp
+       .endm
+
 /*
  * Annotate a function as position independent, i.e., safe to be called before
  * the kernel virtual mapping is activated.
@@ -204,4 +222,15 @@ lr .req    x30             // link register
        .size   __pi_##x, . - x;        \
        ENDPROC(x)
 
+       /*
+        * Emit a 64-bit absolute little endian symbol reference in a way that
+        * ensures that it will be resolved at build time, even when building a
+        * PIE binary. This requires cooperation from the linker script, which
+        * must emit the lo32/hi32 halves individually.
+        */
+       .macro  le64sym, sym
+       .long   \sym\()_lo32
+       .long   \sym\()_hi32
+       .endm
+
 #endif /* __ASM_ASSEMBLER_H */
index 197e06afbf71947eb505a893e53b73be73543be9..39c1d340fec59136b8ddd6e3ac3f39354289189f 100644 (file)
@@ -36,7 +36,7 @@ static inline void atomic_andnot(int i, atomic_t *v)
        "       stclr   %w[i], %[v]\n")
        : [i] "+r" (w0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic_or(int i, atomic_t *v)
@@ -48,7 +48,7 @@ static inline void atomic_or(int i, atomic_t *v)
        "       stset   %w[i], %[v]\n")
        : [i] "+r" (w0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic_xor(int i, atomic_t *v)
@@ -60,7 +60,7 @@ static inline void atomic_xor(int i, atomic_t *v)
        "       steor   %w[i], %[v]\n")
        : [i] "+r" (w0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic_add(int i, atomic_t *v)
@@ -72,7 +72,7 @@ static inline void atomic_add(int i, atomic_t *v)
        "       stadd   %w[i], %[v]\n")
        : [i] "+r" (w0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 #define ATOMIC_OP_ADD_RETURN(name, mb, cl...)                          \
@@ -90,7 +90,7 @@ static inline int atomic_add_return##name(int i, atomic_t *v)         \
        "       add     %w[i], %w[i], w30")                             \
        : [i] "+r" (w0), [v] "+Q" (v->counter)                          \
        : "r" (x1)                                                      \
-       : "x30" , ##cl);                                                \
+       : __LL_SC_CLOBBERS, ##cl);                                      \
                                                                        \
        return w0;                                                      \
 }
@@ -116,7 +116,7 @@ static inline void atomic_and(int i, atomic_t *v)
        "       stclr   %w[i], %[v]")
        : [i] "+r" (w0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic_sub(int i, atomic_t *v)
@@ -133,7 +133,7 @@ static inline void atomic_sub(int i, atomic_t *v)
        "       stadd   %w[i], %[v]")
        : [i] "+r" (w0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 #define ATOMIC_OP_SUB_RETURN(name, mb, cl...)                          \
@@ -153,7 +153,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v)               \
        "       add     %w[i], %w[i], w30")                             \
        : [i] "+r" (w0), [v] "+Q" (v->counter)                          \
        : "r" (x1)                                                      \
-       : "x30" , ##cl);                                                \
+       : __LL_SC_CLOBBERS , ##cl);                                     \
                                                                        \
        return w0;                                                      \
 }
@@ -177,7 +177,7 @@ static inline void atomic64_andnot(long i, atomic64_t *v)
        "       stclr   %[i], %[v]\n")
        : [i] "+r" (x0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic64_or(long i, atomic64_t *v)
@@ -189,7 +189,7 @@ static inline void atomic64_or(long i, atomic64_t *v)
        "       stset   %[i], %[v]\n")
        : [i] "+r" (x0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic64_xor(long i, atomic64_t *v)
@@ -201,7 +201,7 @@ static inline void atomic64_xor(long i, atomic64_t *v)
        "       steor   %[i], %[v]\n")
        : [i] "+r" (x0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic64_add(long i, atomic64_t *v)
@@ -213,7 +213,7 @@ static inline void atomic64_add(long i, atomic64_t *v)
        "       stadd   %[i], %[v]\n")
        : [i] "+r" (x0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...)                                \
@@ -231,7 +231,7 @@ static inline long atomic64_add_return##name(long i, atomic64_t *v) \
        "       add     %[i], %[i], x30")                               \
        : [i] "+r" (x0), [v] "+Q" (v->counter)                          \
        : "r" (x1)                                                      \
-       : "x30" , ##cl);                                                \
+       : __LL_SC_CLOBBERS, ##cl);                                      \
                                                                        \
        return x0;                                                      \
 }
@@ -257,7 +257,7 @@ static inline void atomic64_and(long i, atomic64_t *v)
        "       stclr   %[i], %[v]")
        : [i] "+r" (x0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 static inline void atomic64_sub(long i, atomic64_t *v)
@@ -274,7 +274,7 @@ static inline void atomic64_sub(long i, atomic64_t *v)
        "       stadd   %[i], %[v]")
        : [i] "+r" (x0), [v] "+Q" (v->counter)
        : "r" (x1)
-       : "x30");
+       : __LL_SC_CLOBBERS);
 }
 
 #define ATOMIC64_OP_SUB_RETURN(name, mb, cl...)                                \
@@ -294,7 +294,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \
        "       add     %[i], %[i], x30")                               \
        : [i] "+r" (x0), [v] "+Q" (v->counter)                          \
        : "r" (x1)                                                      \
-       : "x30" , ##cl);                                                \
+       : __LL_SC_CLOBBERS, ##cl);                                      \
                                                                        \
        return x0;                                                      \
 }
@@ -330,7 +330,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
        "2:")
        : [ret] "+&r" (x0), [v] "+Q" (v->counter)
        :
-       : "x30", "cc", "memory");
+       : __LL_SC_CLOBBERS, "cc", "memory");
 
        return x0;
 }
@@ -359,7 +359,7 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr,       \
        "       mov     %" #w "[ret], " #w "30")                        \
        : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr)             \
        : [old] "r" (x1), [new] "r" (x2)                                \
-       : "x30" , ##cl);                                                \
+       : __LL_SC_CLOBBERS, ##cl);                                      \
                                                                        \
        return x0;                                                      \
 }
@@ -416,7 +416,7 @@ static inline long __cmpxchg_double##name(unsigned long old1,               \
          [v] "+Q" (*(unsigned long *)ptr)                              \
        : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),             \
          [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)              \
-       : "x30" , ##cl);                                                \
+       : __LL_SC_CLOBBERS, ##cl);                                      \
                                                                        \
        return x0;                                                      \
 }
index 81151b67b26bf61fd756540f5643d8b5ab6882c7..ebf2481889c34848be0b34158647a4f60b770090 100644 (file)
 #define MIN_FDT_ALIGN          8
 #define MAX_FDT_SIZE           SZ_2M
 
+/*
+ * arm64 requires the kernel image to placed
+ * TEXT_OFFSET bytes beyond a 2 MB aligned base
+ */
+#define MIN_KIMG_ALIGN         SZ_2M
+
 #endif
diff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h
new file mode 100644 (file)
index 0000000..ed693c5
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_BRK_IMM_H
+#define __ASM_BRK_IMM_H
+
+/*
+ * #imm16 values used for BRK instruction generation
+ * Allowed values for kgdb are 0x400 - 0x7ff
+ * 0x100: for triggering a fault on purpose (reserved)
+ * 0x400: for dynamic BRK instruction
+ * 0x401: for compile time BRK instruction
+ * 0x800: kernel-mode BUG() and WARN() traps
+ */
+#define FAULT_BRK_IMM                  0x100
+#define KGDB_DYN_DBG_BRK_IMM           0x400
+#define KGDB_COMPILED_DBG_BRK_IMM      0x401
+#define BUG_BRK_IMM                    0x800
+
+#endif
index 4a748ce9ba1a71241c8f13834e488cef9753dc38..561190d1588136b1f7bc207ebfd04251694ea552 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef _ARCH_ARM64_ASM_BUG_H
 #define _ARCH_ARM64_ASM_BUG_H
 
-#include <asm/debug-monitors.h>
+#include <asm/brk-imm.h>
 
 #ifdef CONFIG_GENERIC_BUG
 #define HAVE_ARCH_BUG
index ca3b7841e1c6fad2f20ea0cd0caaa26230ac8282..22dda613f9c91bd3bcfe3a8aad435f7384795401 100644 (file)
@@ -68,6 +68,7 @@
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void __flush_dcache_area(void *addr, size_t len);
+extern void __clean_dcache_area_pou(void *addr, size_t len);
 extern long __flush_cache_user_range(unsigned long start, unsigned long end);
 
 static inline void flush_cache_mm(struct mm_struct *mm)
index 9ea611ea69df739009d0a6d432bbbedcab05284b..510c7b4044547f82750ca9295e6d35bdeb0b67bf 100644 (file)
@@ -19,7 +19,6 @@
 #define __ASM_CMPXCHG_H
 
 #include <linux/bug.h>
-#include <linux/mmdebug.h>
 
 #include <asm/atomic.h>
 #include <asm/barrier.h>
index b5e9cee4b5f81a3498a67b934dc9157e2d4cf45b..13a6103130cd7036b889250889264847b6871249 100644 (file)
@@ -36,6 +36,7 @@ struct cpuinfo_arm64 {
        u64             reg_id_aa64isar1;
        u64             reg_id_aa64mmfr0;
        u64             reg_id_aa64mmfr1;
+       u64             reg_id_aa64mmfr2;
        u64             reg_id_aa64pfr0;
        u64             reg_id_aa64pfr1;
 
index 8f271b83f9106c7c9753ce2601d3b59e1ffbdfc5..37a53fc6b384eadb7d5b755066ec9fe67717167c 100644 (file)
 #define ARM64_HAS_LSE_ATOMICS                  5
 #define ARM64_WORKAROUND_CAVIUM_23154          6
 #define ARM64_WORKAROUND_834220                        7
+#define ARM64_HAS_NO_HW_PREFETCH               8
+#define ARM64_HAS_UAO                          9
+#define ARM64_ALT_PAN_NOT_UAO                  10
 
-#define ARM64_NCAPS                            8
+#define ARM64_NCAPS                            11
 
 #ifndef __ASSEMBLY__
 
@@ -176,7 +179,7 @@ u64 read_system_reg(u32 id);
 
 static inline bool cpu_supports_mixed_endian_el0(void)
 {
-       return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
+       return id_aa64mmfr0_mixed_endian_el0(read_cpuid(SYS_ID_AA64MMFR0_EL1));
 }
 
 static inline bool system_supports_mixed_endian_el0(void)
index 1a5949364ed0f43eee2be4b61c3497fe4fdbbb7b..b3a83da152a7c75d3ae3964bebb143efadcff6e2 100644 (file)
 #define MPIDR_AFFINITY_LEVEL(mpidr, level) \
        ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)
 
-#define read_cpuid(reg) ({                                             \
-       u64 __val;                                                      \
-       asm("mrs        %0, " #reg : "=r" (__val));                     \
-       __val;                                                          \
-})
-
 #define MIDR_REVISION_MASK     0xf
 #define MIDR_REVISION(midr)    ((midr) & MIDR_REVISION_MASK)
 #define MIDR_PARTNUM_SHIFT     4
 #define MIDR_IMPLEMENTOR(midr) \
        (((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
 
-#define MIDR_CPU_PART(imp, partnum) \
+#define MIDR_CPU_MODEL(imp, partnum) \
        (((imp)                 << MIDR_IMPLEMENTOR_SHIFT) | \
        (0xf                    << MIDR_ARCHITECTURE_SHIFT) | \
        ((partnum)              << MIDR_PARTNUM_SHIFT))
 
+#define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
+                            MIDR_ARCHITECTURE_MASK)
+
+#define MIDR_IS_CPU_MODEL_RANGE(midr, model, rv_min, rv_max)           \
+({                                                                     \
+       u32 _model = (midr) & MIDR_CPU_MODEL_MASK;                      \
+       u32 rv = (midr) & (MIDR_REVISION_MASK | MIDR_VARIANT_MASK);     \
+                                                                       \
+       _model == (model) && rv >= (rv_min) && rv <= (rv_max);          \
+ })
+
 #define ARM_CPU_IMP_ARM                        0x41
 #define ARM_CPU_IMP_APM                        0x50
 #define ARM_CPU_IMP_CAVIUM             0x43
 
 #define CAVIUM_CPU_PART_THUNDERX       0x0A1
 
+#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
+#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
+#define MIDR_THUNDERX  MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
+
 #ifndef __ASSEMBLY__
 
+#include <asm/sysreg.h>
+
+#define read_cpuid(reg) ({                                             \
+       u64 __val;                                                      \
+       asm("mrs_s      %0, " __stringify(reg) : "=r" (__val));         \
+       __val;                                                          \
+})
+
 /*
  * The CPU ID never changes at run time, so we might as well tell the
  * compiler that it's constant.  Use this function to read the CPU ID
  */
 static inline u32 __attribute_const__ read_cpuid_id(void)
 {
-       return read_cpuid(MIDR_EL1);
+       return read_cpuid(SYS_MIDR_EL1);
 }
 
 static inline u64 __attribute_const__ read_cpuid_mpidr(void)
 {
-       return read_cpuid(MPIDR_EL1);
+       return read_cpuid(SYS_MPIDR_EL1);
 }
 
 static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
@@ -104,7 +121,7 @@ static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
 
 static inline u32 __attribute_const__ read_cpuid_cachetype(void)
 {
-       return read_cpuid(CTR_EL0);
+       return read_cpuid(SYS_CTR_EL0);
 }
 #endif /* __ASSEMBLY__ */
 
index 279c85b5ec091eafaa37fbb10d4ff59e2092a605..2fcb9b7c876c06d67c220f1eefcd0b61ef715a1c 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <asm/brk-imm.h>
 #include <asm/esr.h>
 #include <asm/insn.h>
 #include <asm/ptrace.h>
  */
 #define BREAK_INSTR_SIZE               AARCH64_INSN_SIZE
 
-/*
- * #imm16 values used for BRK instruction generation
- * Allowed values for kgbd are 0x400 - 0x7ff
- * 0x100: for triggering a fault on purpose (reserved)
- * 0x400: for dynamic BRK instruction
- * 0x401: for compile time BRK instruction
- * 0x800: kernel-mode BUG() and WARN() traps
- */
-#define FAULT_BRK_IMM                  0x100
-#define KGDB_DYN_DBG_BRK_IMM           0x400
-#define KGDB_COMPILED_DBG_BRK_IMM      0x401
-#define BUG_BRK_IMM                    0x800
-
 /*
  * BRK instruction encoding
  * The #imm16 value should be placed at bits[20:5] within BRK ins
index faad6df49e5b00a49f2b82f06dc48b735662e55c..24ed037f09fd32385b9ccfb0e8d380b5c0d5c7ed 100644 (file)
 #include <asm/ptrace.h>
 #include <asm/user.h>
 
-typedef unsigned long elf_greg_t;
-
-#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
-#define ELF_CORE_COPY_REGS(dest, regs) \
-       *(struct user_pt_regs *)&(dest) = (regs)->user_regs;
-
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-typedef struct user_fpsimd_state elf_fpregset_t;
-
 /*
  * AArch64 static relocation types.
  */
@@ -86,6 +77,8 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 #define R_AARCH64_MOVW_PREL_G2_NC      292
 #define R_AARCH64_MOVW_PREL_G3         293
 
+#define R_AARCH64_RELATIVE             1027
+
 /*
  * These are used to set parameters in the core dumps.
  */
@@ -127,6 +120,17 @@ typedef struct user_fpsimd_state elf_fpregset_t;
  */
 #define ELF_ET_DYN_BASE        (2 * TASK_SIZE_64 / 3)
 
+#ifndef __ASSEMBLY__
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
+#define ELF_CORE_COPY_REGS(dest, regs) \
+       *(struct user_pt_regs *)&(dest) = (regs)->user_regs;
+
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+typedef struct user_fpsimd_state elf_fpregset_t;
+
 /*
  * When the program starts, a1 contains a pointer to a function to be
  * registered with atexit, as per the SVR4 ABI.  A value of 0 means we have no
@@ -186,4 +190,6 @@ extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
 
 #endif /* CONFIG_COMPAT */
 
+#endif /* !__ASSEMBLY__ */
+
 #endif
index 309704544d22763d6348095814fbdce935172c1b..1a617d46fce93247cf42fd0cda36a1355fc89aa9 100644 (file)
@@ -62,6 +62,16 @@ enum fixed_addresses {
 
        FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
        FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
+
+       /*
+        * Used for kernel page table creation, so unmapped memory may be used
+        * for tables.
+        */
+       FIX_PTE,
+       FIX_PMD,
+       FIX_PUD,
+       FIX_PGD,
+
        __end_of_fixed_addresses
 };
 
index c5534facf9416fefbec606ad8f320f023f662ce7..3c60f37e48ab51998db2c5870fe2df4427949b37 100644 (file)
@@ -28,6 +28,8 @@ struct dyn_arch_ftrace {
 
 extern unsigned long ftrace_graph_call;
 
+extern void return_to_handler(void);
+
 static inline unsigned long ftrace_call_adjust(unsigned long addr)
 {
        /*
index 007a69fc4f408d5f2f7e58f4070b6cb354a5e022..f2585cdd32c29832566718e99d7b5fd9c61d2322 100644 (file)
 "4:    mov     %w0, %w5\n"                                             \
 "      b       3b\n"                                                   \
 "      .popsection\n"                                                  \
-"      .pushsection __ex_table,\"a\"\n"                                \
-"      .align  3\n"                                                    \
-"      .quad   1b, 4b, 2b, 4b\n"                                       \
-"      .popsection\n"                                                  \
+       _ASM_EXTABLE(1b, 4b)                                            \
+       _ASM_EXTABLE(2b, 4b)                                            \
        ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,            \
                    CONFIG_ARM64_PAN)                                   \
        : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp)       \
@@ -121,6 +119,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                return -EFAULT;
 
        asm volatile("// futex_atomic_cmpxchg_inatomic\n"
+ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
 "      prfm    pstl1strm, %2\n"
 "1:    ldxr    %w1, %2\n"
 "      sub     %w3, %w1, %w4\n"
@@ -133,10 +132,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 "4:    mov     %w0, %w6\n"
 "      b       3b\n"
 "      .popsection\n"
-"      .pushsection __ex_table,\"a\"\n"
-"      .align  3\n"
-"      .quad   1b, 4b, 2b, 4b\n"
-"      .popsection\n"
+       _ASM_EXTABLE(1b, 4b)
+       _ASM_EXTABLE(2b, 4b)
+ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
        : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
        : "r" (oldval), "r" (newval), "Ir" (-EFAULT)
        : "memory");
index a57601f9d17cdffb1122e2864ae5353273eb59ee..8740297dac775dac5bac2bb9260fca62df7d0fb9 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/threads.h>
 #include <asm/irq.h>
 
-#define NR_IPI 5
+#define NR_IPI 6
 
 typedef struct {
        unsigned int __softirq_pending;
index bb4052e85dbac913c1670fd622f66a6c47909fd8..bbc1e35aa6014c8ea83a1c06acbea83da250121d 100644 (file)
@@ -26,36 +26,7 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
        return *ptep;
 }
 
-static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-                                  pte_t *ptep, pte_t pte)
-{
-       set_pte_at(mm, addr, ptep, pte);
-}
-
-static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
-                                        unsigned long addr, pte_t *ptep)
-{
-       ptep_clear_flush(vma, addr, ptep);
-}
-
-static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
-                                          unsigned long addr, pte_t *ptep)
-{
-       ptep_set_wrprotect(mm, addr, ptep);
-}
 
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
-                                           unsigned long addr, pte_t *ptep)
-{
-       return ptep_get_and_clear(mm, addr, ptep);
-}
-
-static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
-                                            unsigned long addr, pte_t *ptep,
-                                            pte_t pte, int dirty)
-{
-       return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
-}
 
 static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
                                          unsigned long addr, unsigned long end,
@@ -97,4 +68,19 @@ static inline void arch_clear_hugepage_flags(struct page *page)
        clear_bit(PG_dcache_clean, &page->flags);
 }
 
+extern pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+                               struct page *page, int writable);
+#define arch_make_huge_pte arch_make_huge_pte
+extern void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                           pte_t *ptep, pte_t pte);
+extern int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+                                     unsigned long addr, pte_t *ptep,
+                                     pte_t pte, int dirty);
+extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+                                    unsigned long addr, pte_t *ptep);
+extern void huge_ptep_set_wrprotect(struct mm_struct *mm,
+                                   unsigned long addr, pte_t *ptep);
+extern void huge_ptep_clear_flush(struct vm_area_struct *vma,
+                                 unsigned long addr, pte_t *ptep);
+
 #endif /* __ASM_HUGETLB_H */
index 8e8d30684392b1065b0c5d1f65e7715e4028331c..b77197d941fc442c4bad04b185d5cf786ca9fea5 100644 (file)
@@ -1,10 +1,45 @@
 #ifndef __ASM_IRQ_H
 #define __ASM_IRQ_H
 
+#define IRQ_STACK_SIZE                 THREAD_SIZE
+#define IRQ_STACK_START_SP             THREAD_START_SP
+
+#ifndef __ASSEMBLER__
+
+#include <linux/percpu.h>
+
 #include <asm-generic/irq.h>
+#include <asm/thread_info.h>
 
 struct pt_regs;
 
+DECLARE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack);
+
+/*
+ * The highest address on the stack, and the first to be used. Used to
+ * find the dummy-stack frame put down by el?_irq() in entry.S, which
+ * is structured as follows:
+ *
+ *       ------------
+ *       |          |  <- irq_stack_ptr
+ *   top ------------
+ *       |   x19    | <- irq_stack_ptr - 0x08
+ *       ------------
+ *       |   x29    | <- irq_stack_ptr - 0x10
+ *       ------------
+ *
+ * where x19 holds a copy of the task stack pointer where the struct pt_regs
+ * from kernel_entry can be found.
+ *
+ */
+#define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP)
+
+/*
+ * The offset from irq_stack_ptr where entry.S will store the original
+ * stack pointer. Used by unwind_frame() and dump_backtrace().
+ */
+#define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08)))
+
 extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
 
 static inline int nr_legacy_irqs(void)
@@ -12,4 +47,14 @@ static inline int nr_legacy_irqs(void)
        return 0;
 }
 
+static inline bool on_irq_stack(unsigned long sp, int cpu)
+{
+       /* variable names the same as kernel/stacktrace.c */
+       unsigned long low = (unsigned long)per_cpu(irq_stack, cpu);
+       unsigned long high = low + IRQ_STACK_START_SP;
+
+       return (low <= sp && sp <= high);
+}
+
+#endif /* !__ASSEMBLER__ */
 #endif
index 2774fa384c47f27b4e936644cef0e980f7fbcfe7..71ad0f93eb7153226a43d78e909d3e7c3690bf92 100644 (file)
@@ -7,13 +7,14 @@
 
 #include <linux/linkage.h>
 #include <asm/memory.h>
+#include <asm/pgtable-types.h>
 
 /*
  * KASAN_SHADOW_START: beginning of the kernel virtual addresses.
  * KASAN_SHADOW_END: KASAN_SHADOW_START + 1/8 of kernel virtual addresses.
  */
 #define KASAN_SHADOW_START      (VA_START)
-#define KASAN_SHADOW_END        (KASAN_SHADOW_START + (1UL << (VA_BITS - 3)))
+#define KASAN_SHADOW_END        (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
 
 /*
  * This value is used to map an address to the corresponding shadow
 #define KASAN_SHADOW_OFFSET     (KASAN_SHADOW_END - (1ULL << (64 - 3)))
 
 void kasan_init(void);
+void kasan_copy_shadow(pgd_t *pgdir);
 asmlinkage void kasan_early_init(void);
 
 #else
 static inline void kasan_init(void) { }
+static inline void kasan_copy_shadow(pgd_t *pgdir) { }
 #endif
 
 #endif
index a459714ee29e38fbf81f2061026933736ed1cbfc..5c6375d8528bb8ddd313bfa2911f7a0d77819028 100644 (file)
 #define SWAPPER_MM_MMUFLAGS    (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS)
 #endif
 
+/*
+ * To make optimal use of block mappings when laying out the linear
+ * mapping, round down the base of physical memory to a size that can
+ * be mapped efficiently, i.e., either PUD_SIZE (4k granule) or PMD_SIZE
+ * (64k granule), or a multiple that can be mapped using contiguous bits
+ * in the page tables: 32 * PMD_SIZE (16k granule)
+ */
+#ifdef CONFIG_ARM64_64K_PAGES
+#define ARM64_MEMSTART_ALIGN   SZ_512M
+#else
+#define ARM64_MEMSTART_ALIGN   SZ_1G
+#endif
 
 #endif /* __ASM_KERNEL_PGTABLE_H */
index 5e377101f91948f9ee711bea3f7659c86010301c..419bc6661b5c44198f03a7f2b80c59a3f17e8fb3 100644 (file)
 #define KVM_ARM64_DEBUG_DIRTY_SHIFT    0
 #define KVM_ARM64_DEBUG_DIRTY          (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
 
+#define kvm_ksym_ref(sym)              phys_to_virt((u64)&sym - kimage_voffset)
+
 #ifndef __ASSEMBLY__
 struct kvm;
 struct kvm_vcpu;
index a35ce7266aac3688fa6460bace61f90477448aa6..90c6368ad7c859bbc101d88f5273d33380c8d35a 100644 (file)
@@ -222,7 +222,7 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
 struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
 struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
 
-u64 kvm_call_hyp(void *hypfn, ...);
+u64 __kvm_call_hyp(void *hypfn, ...);
 void force_vm_exit(const cpumask_t *mask);
 void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
 
@@ -243,8 +243,8 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
         * Call initialization code, and switch to the full blown
         * HYP code.
         */
-       kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr,
-                    hyp_stack_ptr, vector_ptr);
+       __kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr,
+                      hyp_stack_ptr, vector_ptr);
 }
 
 static inline void kvm_arch_hardware_disable(void) {}
@@ -258,4 +258,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
 void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
 void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
 
+#define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__)
+
 #endif /* __ARM64_KVM_HOST_H__ */
index 3de42d68611df91ba6d46e32c197f700bb52bf52..23acc00be32d019a9f0f71b75153b5b32996b083 100644 (file)
@@ -26,6 +26,7 @@ __asm__(".arch_extension      lse");
 
 /* Macro for constructing calls to out-of-line ll/sc atomics */
 #define __LL_SC_CALL(op)       "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n"
+#define __LL_SC_CLOBBERS       "x16", "x17", "x30"
 
 /* In-line patching at runtime */
 #define ARM64_LSE_ATOMIC_INSN(llsc, lse)                               \
index 853953cd1f0813fd562b68b7cdddd95582f1e392..12f8a00fb3f1767a645a04358dcaca08fd4f6b43 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/compiler.h>
 #include <linux/const.h>
 #include <linux/types.h>
+#include <asm/bug.h>
 #include <asm/sizes.h>
 
 /*
  * VA_START - the first kernel virtual address.
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
- * The module space lives between the addresses given by TASK_SIZE
- * and PAGE_OFFSET - it must be within 128MB of the kernel text.
  */
 #define VA_BITS                        (CONFIG_ARM64_VA_BITS)
 #define VA_START               (UL(0xffffffffffffffff) << VA_BITS)
 #define PAGE_OFFSET            (UL(0xffffffffffffffff) << (VA_BITS - 1))
-#define MODULES_END            (PAGE_OFFSET)
-#define MODULES_VADDR          (MODULES_END - SZ_64M)
-#define PCI_IO_END             (MODULES_VADDR - SZ_2M)
+#define KIMAGE_VADDR           (MODULES_END)
+#define MODULES_END            (MODULES_VADDR + MODULES_VSIZE)
+#define MODULES_VADDR          (VA_START + KASAN_SHADOW_SIZE)
+#define MODULES_VSIZE          (SZ_128M)
+#define PCI_IO_END             (PAGE_OFFSET - SZ_2M)
 #define PCI_IO_START           (PCI_IO_END - PCI_IO_SIZE)
 #define FIXADDR_TOP            (PCI_IO_START - SZ_2M)
 #define TASK_SIZE_64           (UL(1) << VA_BITS)
 
 #define TASK_UNMAPPED_BASE     (PAGE_ALIGN(TASK_SIZE / 4))
 
+/*
+ * The size of the KASAN shadow region. This should be 1/8th of the
+ * size of the entire kernel virtual address space.
+ */
+#ifdef CONFIG_KASAN
+#define KASAN_SHADOW_SIZE      (UL(1) << (VA_BITS - 3))
+#else
+#define KASAN_SHADOW_SIZE      (0)
+#endif
+
 /*
  * Physical vs virtual RAM address space conversion.  These are
  * private definitions which should NOT be used outside memory.h
  * files.  Use virt_to_phys/phys_to_virt/__pa/__va instead.
  */
-#define __virt_to_phys(x)      (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
-#define __phys_to_virt(x)      ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
+#define __virt_to_phys(x) ({                                           \
+       phys_addr_t __x = (phys_addr_t)(x);                             \
+       __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET :   \
+                                (__x - kimage_voffset); })
+
+#define __phys_to_virt(x)      ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
+#define __phys_to_kimg(x)      ((unsigned long)((x) + kimage_voffset))
 
 /*
  * Convert a page to/from a physical address
 #define MT_S2_NORMAL           0xf
 #define MT_S2_DEVICE_nGnRE     0x1
 
+#ifdef CONFIG_ARM64_4K_PAGES
+#define IOREMAP_MAX_ORDER      (PUD_SHIFT)
+#else
+#define IOREMAP_MAX_ORDER      (PMD_SHIFT)
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+#define __early_init_dt_declare_initrd(__start, __end)                 \
+       do {                                                            \
+               initrd_start = (__start);                               \
+               initrd_end = (__end);                                   \
+       } while (0)
+#endif
+
 #ifndef __ASSEMBLY__
 
-extern phys_addr_t             memstart_addr;
+#include <linux/bitops.h>
+#include <linux/mmdebug.h>
+
+extern s64                     memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
-#define PHYS_OFFSET            ({ memstart_addr; })
+#define PHYS_OFFSET            ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
+
+/* the virtual base of the kernel image (minus TEXT_OFFSET) */
+extern u64                     kimage_vaddr;
+
+/* the offset between the kernel virtual and physical mappings */
+extern u64                     kimage_voffset;
 
 /*
- * The maximum physical address that the linear direct mapping
- * of system RAM can cover. (PAGE_OFFSET can be interpreted as
- * a 2's complement signed quantity and negated to derive the
- * maximum size of the linear mapping.)
+ * Allow all memory at the discovery stage. We will clip it later.
  */
-#define MAX_MEMBLOCK_ADDR      ({ memstart_addr - PAGE_OFFSET - 1; })
+#define MIN_MEMBLOCK_ADDR      0
+#define MAX_MEMBLOCK_ADDR      U64_MAX
 
 /*
  * PFNs are used to describe any physical page; this means
index 24165784b8038b732ea568d1e74fd8c0a699b914..a00f7cf35bbd4d80ce045bfeb0cbb6bd061aeaaa 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm-generic/mm_hooks.h>
 #include <asm/cputype.h>
 #include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 
 #ifdef CONFIG_PID_IN_CONTEXTIDR
 static inline void contextidr_thread_switch(struct task_struct *next)
@@ -48,7 +49,7 @@ static inline void contextidr_thread_switch(struct task_struct *next)
  */
 static inline void cpu_set_reserved_ttbr0(void)
 {
-       unsigned long ttbr = page_to_phys(empty_zero_page);
+       unsigned long ttbr = virt_to_phys(empty_zero_page);
 
        asm(
        "       msr     ttbr0_el1, %0                   // set TTBR0\n"
@@ -73,7 +74,7 @@ static inline bool __cpu_uses_extended_idmap(void)
 /*
  * Set TCR.T0SZ to its default value (based on VA_BITS)
  */
-static inline void cpu_set_default_tcr_t0sz(void)
+static inline void __cpu_set_tcr_t0sz(unsigned long t0sz)
 {
        unsigned long tcr;
 
@@ -86,7 +87,62 @@ static inline void cpu_set_default_tcr_t0sz(void)
        "       msr     tcr_el1, %0     ;"
        "       isb"
        : "=&r" (tcr)
-       : "r"(TCR_T0SZ(VA_BITS)), "I"(TCR_T0SZ_OFFSET), "I"(TCR_TxSZ_WIDTH));
+       : "r"(t0sz), "I"(TCR_T0SZ_OFFSET), "I"(TCR_TxSZ_WIDTH));
+}
+
+#define cpu_set_default_tcr_t0sz()     __cpu_set_tcr_t0sz(TCR_T0SZ(VA_BITS))
+#define cpu_set_idmap_tcr_t0sz()       __cpu_set_tcr_t0sz(idmap_t0sz)
+
+/*
+ * Remove the idmap from TTBR0_EL1 and install the pgd of the active mm.
+ *
+ * The idmap lives in the same VA range as userspace, but uses global entries
+ * and may use a different TCR_EL1.T0SZ. To avoid issues resulting from
+ * speculative TLB fetches, we must temporarily install the reserved page
+ * tables while we invalidate the TLBs and set up the correct TCR_EL1.T0SZ.
+ *
+ * If current is a not a user task, the mm covers the TTBR1_EL1 page tables,
+ * which should not be installed in TTBR0_EL1. In this case we can leave the
+ * reserved page tables in place.
+ */
+static inline void cpu_uninstall_idmap(void)
+{
+       struct mm_struct *mm = current->active_mm;
+
+       cpu_set_reserved_ttbr0();
+       local_flush_tlb_all();
+       cpu_set_default_tcr_t0sz();
+
+       if (mm != &init_mm)
+               cpu_switch_mm(mm->pgd, mm);
+}
+
+static inline void cpu_install_idmap(void)
+{
+       cpu_set_reserved_ttbr0();
+       local_flush_tlb_all();
+       cpu_set_idmap_tcr_t0sz();
+
+       cpu_switch_mm(idmap_pg_dir, &init_mm);
+}
+
+/*
+ * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
+ * avoiding the possibility of conflicting TLB entries being allocated.
+ */
+static inline void cpu_replace_ttbr1(pgd_t *pgd)
+{
+       typedef void (ttbr_replace_func)(phys_addr_t);
+       extern ttbr_replace_func idmap_cpu_replace_ttbr1;
+       ttbr_replace_func *replace_phys;
+
+       phys_addr_t pgd_phys = virt_to_phys(pgd);
+
+       replace_phys = (void *)virt_to_phys(idmap_cpu_replace_ttbr1);
+
+       cpu_install_idmap();
+       replace_phys(pgd_phys);
+       cpu_uninstall_idmap();
 }
 
 /*
index e80e232b730e2d29f77dba57bfa91ad4439f9781..e12af6754634b3d2aa031ae23ce25228dc766cfb 100644 (file)
 
 #define MODULE_ARCH_VERMAGIC   "aarch64"
 
+#ifdef CONFIG_ARM64_MODULE_PLTS
+struct mod_arch_specific {
+       struct elf64_shdr       *plt;
+       int                     plt_num_entries;
+       int                     plt_max_entries;
+};
+#endif
+
+u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
+                         Elf64_Sym *sym);
+
+#ifdef CONFIG_RANDOMIZE_BASE
+extern u64 module_alloc_base;
+#else
+#define module_alloc_base      ((u64)_etext - MODULES_VSIZE)
+#endif
+
 #endif /* __ASM_MODULE_H */
index 4e603ea36ad3f687ab0c84fd5f127dfe7c5fd8a0..123f45d92cd1fe568a29f8e0fe421e6d953a291d 100644 (file)
@@ -1 +1,5 @@
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define CONFIG_CPU_ENDIAN_BE8 CONFIG_CPU_BIG_ENDIAN
+#endif
+
 #include <../../arm/include/asm/opcodes.h>
index c15053902942e0a3a34ba4882545c5b6d163c23c..ff98585d085aa5737c9c17478555f22b11261f2f 100644 (file)
@@ -42,11 +42,20 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
        free_page((unsigned long)pmd);
 }
 
-static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot)
 {
-       set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
+       set_pud(pud, __pud(pmd | prot));
 }
 
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+       __pud_populate(pud, __pa(pmd), PMD_TYPE_TABLE);
+}
+#else
+static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot)
+{
+       BUILD_BUG();
+}
 #endif /* CONFIG_PGTABLE_LEVELS > 2 */
 
 #if CONFIG_PGTABLE_LEVELS > 3
@@ -62,11 +71,20 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
        free_page((unsigned long)pud);
 }
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
+static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot)
 {
-       set_pgd(pgd, __pgd(__pa(pud) | PUD_TYPE_TABLE));
+       set_pgd(pgdp, __pgd(pud | prot));
 }
 
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
+{
+       __pgd_populate(pgd, __pa(pud), PUD_TYPE_TABLE);
+}
+#else
+static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot)
+{
+       BUILD_BUG();
+}
 #endif /* CONFIG_PGTABLE_LEVELS > 3 */
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
index d6739e836f7bb919a7e49b7e14fc43d2454f46de..5c25b831273dbfaa183a769a108331df43a9c498 100644 (file)
 /*
  * Contiguous page definitions.
  */
-#define CONT_PTES              (_AC(1, UL) << CONT_SHIFT)
+#ifdef CONFIG_ARM64_64K_PAGES
+#define CONT_PTE_SHIFT         5
+#define CONT_PMD_SHIFT         5
+#elif defined(CONFIG_ARM64_16K_PAGES)
+#define CONT_PTE_SHIFT         7
+#define CONT_PMD_SHIFT         5
+#else
+#define CONT_PTE_SHIFT         4
+#define CONT_PMD_SHIFT         4
+#endif
+
+#define CONT_PTES              (1 << CONT_PTE_SHIFT)
+#define CONT_PTE_SIZE          (CONT_PTES * PAGE_SIZE)
+#define CONT_PTE_MASK          (~(CONT_PTE_SIZE - 1))
+#define CONT_PMDS              (1 << CONT_PMD_SHIFT)
+#define CONT_PMD_SIZE          (CONT_PMDS * PMD_SIZE)
+#define CONT_PMD_MASK          (~(CONT_PMD_SIZE - 1))
 /* the the numerical offset of the PTE within a range of CONT_PTES */
 #define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_PTES-1))
 
index eaa9cabf4066e758eb0a0aa9e8bffb7f8611d878..c3c2518eecfe29c41ea9f05ba814036d9fa2f0cc 100644 (file)
  *
  * VMEMAP_SIZE: allows the whole linear region to be covered by a struct page array
  *     (rounded up to PUD_SIZE).
- * VMALLOC_START: beginning of the kernel VA space
+ * VMALLOC_START: beginning of the kernel vmalloc space
  * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space,
  *     fixed mappings and modules
  */
 #define VMEMMAP_SIZE           ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
 
-#ifndef CONFIG_KASAN
-#define VMALLOC_START          (VA_START)
-#else
-#include <asm/kasan.h>
-#define VMALLOC_START          (KASAN_SHADOW_END + SZ_64K)
-#endif
-
+#define VMALLOC_START          (MODULES_END)
 #define VMALLOC_END            (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 
 #define VMEMMAP_START          (VMALLOC_END + SZ_64K)
@@ -59,6 +53,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <asm/fixmap.h>
 #include <linux/mmdebug.h>
 
 extern void __pte_error(const char *file, int line, unsigned long val);
@@ -69,11 +64,11 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 #define PROT_DEFAULT           (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define PROT_SECT_DEFAULT      (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
-#define PROT_DEVICE_nGnRnE     (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
-#define PROT_DEVICE_nGnRE      (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
-#define PROT_NORMAL_NC         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC))
-#define PROT_NORMAL_WT         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_WT))
-#define PROT_NORMAL            (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL))
+#define PROT_DEVICE_nGnRnE     (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
+#define PROT_DEVICE_nGnRE      (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
+#define PROT_NORMAL_NC         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC))
+#define PROT_NORMAL_WT         (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT))
+#define PROT_NORMAL            (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL))
 
 #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
 #define PROT_SECT_NORMAL       (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
@@ -83,7 +78,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 
 #define PAGE_KERNEL            __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_RO         __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
-#define PAGE_KERNEL_ROX        __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
+#define PAGE_KERNEL_ROX                __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
 #define PAGE_KERNEL_EXEC       __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
 #define PAGE_KERNEL_EXEC_CONT  __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
 
@@ -123,8 +118,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern struct page *empty_zero_page;
-#define ZERO_PAGE(vaddr)       (empty_zero_page)
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr)       virt_to_page(empty_zero_page)
 
 #define pte_ERROR(pte)         __pte_error(__FILE__, __LINE__, pte_val(pte))
 
@@ -136,16 +131,6 @@ extern struct page *empty_zero_page;
 #define pte_clear(mm,addr,ptep)        set_pte(ptep, __pte(0))
 #define pte_page(pte)          (pfn_to_page(pte_pfn(pte)))
 
-/* Find an entry in the third-level page table. */
-#define pte_index(addr)                (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-
-#define pte_offset_kernel(dir,addr)    (pmd_page_vaddr(*(dir)) + pte_index(addr))
-
-#define pte_offset_map(dir,addr)       pte_offset_kernel((dir), (addr))
-#define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir), (addr))
-#define pte_unmap(pte)                 do { } while (0)
-#define pte_unmap_nested(pte)          do { } while (0)
-
 /*
  * The following only work if pte_present(). Undefined behaviour otherwise.
  */
@@ -155,6 +140,7 @@ extern struct page *empty_zero_page;
 #define pte_write(pte)         (!!(pte_val(pte) & PTE_WRITE))
 #define pte_exec(pte)          (!(pte_val(pte) & PTE_UXN))
 #define pte_cont(pte)          (!!(pte_val(pte) & PTE_CONT))
+#define pte_user(pte)          (!!(pte_val(pte) & PTE_USER))
 
 #ifdef CONFIG_ARM64_HW_AFDBM
 #define pte_hw_dirty(pte)      (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
@@ -165,10 +151,18 @@ extern struct page *empty_zero_page;
 #define pte_dirty(pte)         (pte_sw_dirty(pte) || pte_hw_dirty(pte))
 
 #define pte_valid(pte)         (!!(pte_val(pte) & PTE_VALID))
-#define pte_valid_user(pte) \
-       ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 #define pte_valid_not_user(pte) \
        ((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
+#define pte_valid_young(pte) \
+       ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
+
+/*
+ * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
+ * so that we don't erroneously return false for pages that have been
+ * remapped as PROT_NONE but are yet to be flushed from the TLB.
+ */
+#define pte_accessible(mm, pte)        \
+       (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
 
 static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
@@ -219,7 +213,8 @@ static inline pte_t pte_mkspecial(pte_t pte)
 
 static inline pte_t pte_mkcont(pte_t pte)
 {
-       return set_pte_bit(pte, __pgprot(PTE_CONT));
+       pte = set_pte_bit(pte, __pgprot(PTE_CONT));
+       return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
 }
 
 static inline pte_t pte_mknoncont(pte_t pte)
@@ -227,6 +222,11 @@ static inline pte_t pte_mknoncont(pte_t pte)
        return clear_pte_bit(pte, __pgprot(PTE_CONT));
 }
 
+static inline pmd_t pmd_mkcont(pmd_t pmd)
+{
+       return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
+}
+
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
        *ptep = pte;
@@ -264,13 +264,13 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
-       if (pte_valid_user(pte)) {
-               if (!pte_special(pte) && pte_exec(pte))
-                       __sync_icache_dcache(pte, addr);
+       if (pte_present(pte)) {
                if (pte_sw_dirty(pte) && pte_write(pte))
                        pte_val(pte) &= ~PTE_RDONLY;
                else
                        pte_val(pte) |= PTE_RDONLY;
+               if (pte_user(pte) && pte_exec(pte) && !pte_special(pte))
+                       __sync_icache_dcache(pte, addr);
        }
 
        /*
@@ -300,7 +300,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 /*
  * Hugetlb definitions.
  */
-#define HUGE_MAX_HSTATE                2
+#define HUGE_MAX_HSTATE                4
 #define HPAGE_SHIFT            PMD_SHIFT
 #define HPAGE_SIZE             (_AC(1, UL) << HPAGE_SHIFT)
 #define HPAGE_MASK             (~(HPAGE_SIZE - 1))
@@ -354,6 +354,7 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
 #define pmd_mksplitting(pmd)   pte_pmd(pte_mkspecial(pmd_pte(pmd)))
 #define pmd_mkold(pmd)         pte_pmd(pte_mkold(pmd_pte(pmd)))
 #define pmd_mkwrite(pmd)       pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+#define pmd_mkclean(pmd)       pte_pmd(pte_mkclean(pmd_pte(pmd)))
 #define pmd_mkdirty(pmd)       pte_pmd(pte_mkdirty(pmd_pte(pmd)))
 #define pmd_mkyoung(pmd)       pte_pmd(pte_mkyoung(pmd_pte(pmd)))
 #define pmd_mknotpresent(pmd)  (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
@@ -426,13 +427,31 @@ static inline void pmd_clear(pmd_t *pmdp)
        set_pmd(pmdp, __pmd(0));
 }
 
-static inline pte_t *pmd_page_vaddr(pmd_t pmd)
+static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
 {
-       return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK);
+       return pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK;
 }
 
+/* Find an entry in the third-level page table. */
+#define pte_index(addr)                (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+
+#define pte_offset_phys(dir,addr)      (pmd_page_paddr(*(dir)) + pte_index(addr) * sizeof(pte_t))
+#define pte_offset_kernel(dir,addr)    ((pte_t *)__va(pte_offset_phys((dir), (addr))))
+
+#define pte_offset_map(dir,addr)       pte_offset_kernel((dir), (addr))
+#define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir), (addr))
+#define pte_unmap(pte)                 do { } while (0)
+#define pte_unmap_nested(pte)          do { } while (0)
+
+#define pte_set_fixmap(addr)           ((pte_t *)set_fixmap_offset(FIX_PTE, addr))
+#define pte_set_fixmap_offset(pmd, addr)       pte_set_fixmap(pte_offset_phys(pmd, addr))
+#define pte_clear_fixmap()             clear_fixmap(FIX_PTE)
+
 #define pmd_page(pmd)          pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
 
+/* use ONLY for statically allocated translation tables */
+#define pte_offset_kimg(dir,addr)      ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -459,21 +478,37 @@ static inline void pud_clear(pud_t *pudp)
        set_pud(pudp, __pud(0));
 }
 
-static inline pmd_t *pud_page_vaddr(pud_t pud)
+static inline phys_addr_t pud_page_paddr(pud_t pud)
 {
-       return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK);
+       return pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK;
 }
 
 /* Find an entry in the second-level page table. */
 #define pmd_index(addr)                (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
 
-static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
-{
-       return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
-}
+#define pmd_offset_phys(dir, addr)     (pud_page_paddr(*(dir)) + pmd_index(addr) * sizeof(pmd_t))
+#define pmd_offset(dir, addr)          ((pmd_t *)__va(pmd_offset_phys((dir), (addr))))
+
+#define pmd_set_fixmap(addr)           ((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
+#define pmd_set_fixmap_offset(pud, addr)       pmd_set_fixmap(pmd_offset_phys(pud, addr))
+#define pmd_clear_fixmap()             clear_fixmap(FIX_PMD)
 
 #define pud_page(pud)          pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
 
+/* use ONLY for statically allocated translation tables */
+#define pmd_offset_kimg(dir,addr)      ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
+
+#else
+
+#define pud_page_paddr(pud)    ({ BUILD_BUG(); 0; })
+
+/* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */
+#define pmd_set_fixmap(addr)           NULL
+#define pmd_set_fixmap_offset(pudp, addr)      ((pmd_t *)pudp)
+#define pmd_clear_fixmap()
+
+#define pmd_offset_kimg(dir,addr)      ((pmd_t *)dir)
+
 #endif /* CONFIG_PGTABLE_LEVELS > 2 */
 
 #if CONFIG_PGTABLE_LEVELS > 3
@@ -495,21 +530,37 @@ static inline void pgd_clear(pgd_t *pgdp)
        set_pgd(pgdp, __pgd(0));
 }
 
-static inline pud_t *pgd_page_vaddr(pgd_t pgd)
+static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
 {
-       return __va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK);
+       return pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK;
 }
 
 /* Find an entry in the frst-level page table. */
 #define pud_index(addr)                (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
 
-static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
-{
-       return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr);
-}
+#define pud_offset_phys(dir, addr)     (pgd_page_paddr(*(dir)) + pud_index(addr) * sizeof(pud_t))
+#define pud_offset(dir, addr)          ((pud_t *)__va(pud_offset_phys((dir), (addr))))
+
+#define pud_set_fixmap(addr)           ((pud_t *)set_fixmap_offset(FIX_PUD, addr))
+#define pud_set_fixmap_offset(pgd, addr)       pud_set_fixmap(pud_offset_phys(pgd, addr))
+#define pud_clear_fixmap()             clear_fixmap(FIX_PUD)
 
 #define pgd_page(pgd)          pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
 
+/* use ONLY for statically allocated translation tables */
+#define pud_offset_kimg(dir,addr)      ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
+
+#else
+
+#define pgd_page_paddr(pgd)    ({ BUILD_BUG(); 0;})
+
+/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
+#define pud_set_fixmap(addr)           NULL
+#define pud_set_fixmap_offset(pgdp, addr)      ((pud_t *)pgdp)
+#define pud_clear_fixmap()
+
+#define pud_offset_kimg(dir,addr)      ((pud_t *)dir)
+
 #endif  /* CONFIG_PGTABLE_LEVELS > 3 */
 
 #define pgd_ERROR(pgd)         __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
@@ -517,11 +568,16 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
 /* to find an entry in a page-table-directory */
 #define pgd_index(addr)                (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
 
-#define pgd_offset(mm, addr)   ((mm)->pgd+pgd_index(addr))
+#define pgd_offset_raw(pgd, addr)      ((pgd) + pgd_index(addr))
+
+#define pgd_offset(mm, addr)   (pgd_offset_raw((mm)->pgd, (addr)))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(addr)     pgd_offset(&init_mm, addr)
 
+#define pgd_set_fixmap(addr)   ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
+#define pgd_clear_fixmap()     clear_fixmap(FIX_PGD)
+
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
@@ -641,6 +697,7 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
  *     bits 0-1:       present (must be zero)
  *     bits 2-7:       swap type
  *     bits 8-57:      swap offset
+ *     bit  58:        PTE_PROT_NONE (must be zero)
  */
 #define __SWP_TYPE_SHIFT       2
 #define __SWP_TYPE_BITS                6
@@ -666,7 +723,8 @@ extern int kern_addr_valid(unsigned long addr);
 
 #include <asm-generic/pgtable.h>
 
-#define pgtable_cache_init() do { } while (0)
+void pgd_cache_init(void);
+#define pgtable_cache_init     pgd_cache_init
 
 /*
  * On AArch64, the cache coherency is handled via the set_pte_at() function.
index 4acb7ca94fcd9c05569f3103ab09097c19ea72d5..cef1cf398356f1f61ceea854fc564f6df1d316cc 100644 (file)
 
 #include <linux/string.h>
 
+#include <asm/alternative.h>
 #include <asm/fpsimd.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/lse.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
@@ -177,9 +179,11 @@ static inline void prefetchw(const void *ptr)
 }
 
 #define ARCH_HAS_SPINLOCK_PREFETCH
-static inline void spin_lock_prefetch(const void *x)
+static inline void spin_lock_prefetch(const void *ptr)
 {
-       prefetchw(x);
+       asm volatile(ARM64_LSE_ATOMIC_INSN(
+                    "prfm pstl1strm, %a0",
+                    "nop") : : "p" (ptr));
 }
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
@@ -187,5 +191,6 @@ static inline void spin_lock_prefetch(const void *x)
 #endif
 
 void cpu_enable_pan(void *__unused);
+void cpu_enable_uao(void *__unused);
 
 #endif /* __ASM_PROCESSOR_H */
index 4df608a8459e27c657055edd5ca519b34e755b80..e368a55ebd22d0c3dab4a690afdd33d62c76ef73 100644 (file)
@@ -21,7 +21,7 @@
  * alignment value. Since we don't have aliasing D-caches, the rest of
  * the time we can safely use PAGE_SIZE.
  */
-#define COMPAT_SHMLBA  0x4000
+#define COMPAT_SHMLBA  (4 * PAGE_SIZE)
 
 #include <asm-generic/shmparam.h>
 
index d9c3d6a6100ac5d68e9b412113daccd1e43d8371..2013a4dc5124a55c5c304306b41908f16a0e5d64 100644 (file)
@@ -64,6 +64,15 @@ extern void secondary_entry(void);
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
+#else
+static inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+       BUILD_BUG();
+}
+#endif
+
 extern int __cpu_disable(void);
 
 extern void __cpu_die(unsigned int cpu);
index c85e96d174a5fbd4764adb748b9bc11c70479617..fc9682bfe0020caebf99412131fb760d5b8b870d 100644 (file)
  * The memory barriers are implicit with the load-acquire and store-release
  * instructions.
  */
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       unsigned int tmp;
+       arch_spinlock_t lockval;
 
-#define arch_spin_unlock_wait(lock) \
-       do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
+       asm volatile(
+"      sevl\n"
+"1:    wfe\n"
+"2:    ldaxr   %w0, %2\n"
+"      eor     %w1, %w0, %w0, ror #16\n"
+"      cbnz    %w1, 1b\n"
+       ARM64_LSE_ATOMIC_INSN(
+       /* LL/SC */
+"      stxr    %w1, %w0, %2\n"
+"      cbnz    %w1, 2b\n", /* Serialise against any concurrent lockers */
+       /* LSE atomics */
+"      nop\n"
+"      nop\n")
+       : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
+       :
+       : "memory");
+}
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
index 7318f6d54aa949ca906a990cce357a4cdd1358db..801a16dbbdf622d5239cf61be4f67eccab5c1e09 100644 (file)
 #ifndef __ASM_STACKTRACE_H
 #define __ASM_STACKTRACE_H
 
+struct task_struct;
+
 struct stackframe {
        unsigned long fp;
        unsigned long sp;
        unsigned long pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       unsigned int graph;
+#endif
 };
 
-extern int unwind_frame(struct stackframe *frame);
-extern void walk_stackframe(struct stackframe *frame,
+extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
+extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
                            int (*fn)(struct stackframe *, void *), void *data);
 
 #endif /* __ASM_STACKTRACE_H */
index d48ab5b41f521c23819c0b3927a9ea0f73db242c..b9fd8ec790336569ee8fdedb4573e25b3045c29b 100644 (file)
 
 #define SYS_ID_AA64MMFR0_EL1           sys_reg(3, 0, 0, 7, 0)
 #define SYS_ID_AA64MMFR1_EL1           sys_reg(3, 0, 0, 7, 1)
+#define SYS_ID_AA64MMFR2_EL1           sys_reg(3, 0, 0, 7, 2)
 
 #define SYS_CNTFRQ_EL0                 sys_reg(3, 3, 14, 0, 0)
 #define SYS_CTR_EL0                    sys_reg(3, 3, 0, 0, 1)
 #define SYS_DCZID_EL0                  sys_reg(3, 3, 0, 0, 7)
 
 #define REG_PSTATE_PAN_IMM             sys_reg(0, 0, 4, 0, 4)
+#define REG_PSTATE_UAO_IMM             sys_reg(0, 0, 4, 0, 3)
 
 #define SET_PSTATE_PAN(x) __inst_arm(0xd5000000 | REG_PSTATE_PAN_IMM |\
                                     (!!x)<<8 | 0x1f)
+#define SET_PSTATE_UAO(x) __inst_arm(0xd5000000 | REG_PSTATE_UAO_IMM |\
+                                    (!!x)<<8 | 0x1f)
 
 /* SCTLR_EL1 */
 #define SCTLR_EL1_CP15BEN      (0x1 << 5)
 #define ID_AA64MMFR1_VMIDBITS_SHIFT    4
 #define ID_AA64MMFR1_HADBS_SHIFT       0
 
+/* id_aa64mmfr2 */
+#define ID_AA64MMFR2_UAO_SHIFT         4
+
 /* id_aa64dfr0 */
 #define ID_AA64DFR0_CTX_CMPS_SHIFT     28
 #define ID_AA64DFR0_WRPS_SHIFT         20
 #ifdef __ASSEMBLY__
 
        .irp    num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
-       .equ    __reg_num_x\num, \num
+       .equ    .L__reg_num_x\num, \num
        .endr
-       .equ    __reg_num_xzr, 31
+       .equ    .L__reg_num_xzr, 31
 
        .macro  mrs_s, rt, sreg
-       .inst   0xd5200000|(\sreg)|(__reg_num_\rt)
+       .inst   0xd5200000|(\sreg)|(.L__reg_num_\rt)
        .endm
 
        .macro  msr_s, sreg, rt
-       .inst   0xd5000000|(\sreg)|(__reg_num_\rt)
+       .inst   0xd5000000|(\sreg)|(.L__reg_num_\rt)
        .endm
 
 #else
 
 asm(
 "      .irp    num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
-"      .equ    __reg_num_x\\num, \\num\n"
+"      .equ    .L__reg_num_x\\num, \\num\n"
 "      .endr\n"
-"      .equ    __reg_num_xzr, 31\n"
+"      .equ    .L__reg_num_xzr, 31\n"
 "\n"
 "      .macro  mrs_s, rt, sreg\n"
-"      .inst   0xd5200000|(\\sreg)|(__reg_num_\\rt)\n"
+"      .inst   0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n"
 "      .endm\n"
 "\n"
 "      .macro  msr_s, sreg, rt\n"
-"      .inst   0xd5000000|(\\sreg)|(__reg_num_\\rt)\n"
+"      .inst   0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n"
 "      .endm\n"
 );
 
index 90c7ff233735d7691bf3b34b7075dffd07dbf939..abd64bd1f6d9f0160a3122555cf23be1a30f87eb 100644 (file)
@@ -73,10 +73,16 @@ register unsigned long current_stack_pointer asm ("sp");
  */
 static inline struct thread_info *current_thread_info(void) __attribute_const__;
 
+/*
+ * struct thread_info can be accessed directly via sp_el0.
+ */
 static inline struct thread_info *current_thread_info(void)
 {
-       return (struct thread_info *)
-               (current_stack_pointer & ~(THREAD_SIZE - 1));
+       unsigned long sp_el0;
+
+       asm ("mrs %0, sp_el0" : "=r" (sp_el0));
+
+       return (struct thread_info *)sp_el0;
 }
 
 #define thread_saved_pc(tsk)   \
index b2ede967fe7d49258c56af51e73786efb5d1a420..0685d74572af788b05d44658c7dba7e4fc3742ba 100644 (file)
 #define VERIFY_WRITE 1
 
 /*
- * 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.
+ * The exception table consists of pairs of relative offsets: the first
+ * is the relative offset to an instruction that is allowed to fault,
+ * and the second is the relative offset 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,
 
 struct exception_table_entry
 {
-       unsigned long insn, fixup;
+       int insn, fixup;
 };
 
+#define ARCH_HAS_RELATIVE_EXTABLE
+
 extern int fixup_exception(struct pt_regs *regs);
 
 #define KERNEL_DS      (-1UL)
@@ -64,6 +66,16 @@ extern int fixup_exception(struct pt_regs *regs);
 static inline void set_fs(mm_segment_t fs)
 {
        current_thread_info()->addr_limit = fs;
+
+       /*
+        * Enable/disable UAO so that copy_to_user() etc can access
+        * kernel memory with the unprivileged instructions.
+        */
+       if (IS_ENABLED(CONFIG_ARM64_UAO) && fs == KERNEL_DS)
+               asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
+       else
+               asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO,
+                               CONFIG_ARM64_UAO));
 }
 
 #define segment_eq(a, b)       ((a) == (b))
@@ -105,6 +117,12 @@ static inline void set_fs(mm_segment_t fs)
 #define access_ok(type, addr, size)    __range_ok(addr, size)
 #define user_addr_max                  get_fs
 
+#define _ASM_EXTABLE(from, to)                                         \
+       "       .pushsection    __ex_table, \"a\"\n"                    \
+       "       .align          3\n"                                    \
+       "       .long           (" #from " - .), (" #to " - .)\n"       \
+       "       .popsection\n"
+
 /*
  * The "__xxx" versions of the user access functions do not verify the address
  * space - it must have been done previously with a separate "access_ok()"
@@ -113,9 +131,10 @@ static inline void set_fs(mm_segment_t fs)
  * The "__xxx_error" versions set the third argument to -EFAULT if an error
  * occurs, and leave it unchanged on success.
  */
-#define __get_user_asm(instr, reg, x, addr, err)                       \
+#define __get_user_asm(instr, alt_instr, reg, x, addr, err, feature)   \
        asm volatile(                                                   \
-       "1:     " instr "       " reg "1, [%2]\n"                       \
+       "1:"ALTERNATIVE(instr "     " reg "1, [%2]\n",                  \
+                       alt_instr " " reg "1, [%2]\n", feature)         \
        "2:\n"                                                          \
        "       .section .fixup, \"ax\"\n"                              \
        "       .align  2\n"                                            \
@@ -123,10 +142,7 @@ static inline void set_fs(mm_segment_t fs)
        "       mov     %1, #0\n"                                       \
        "       b       2b\n"                                           \
        "       .previous\n"                                            \
-       "       .section __ex_table,\"a\"\n"                            \
-       "       .align  3\n"                                            \
-       "       .quad   1b, 3b\n"                                       \
-       "       .previous"                                              \
+       _ASM_EXTABLE(1b, 3b)                                            \
        : "+r" (err), "=&r" (x)                                         \
        : "r" (addr), "i" (-EFAULT))
 
@@ -134,26 +150,30 @@ static inline void set_fs(mm_segment_t fs)
 do {                                                                   \
        unsigned long __gu_val;                                         \
        __chk_user_ptr(ptr);                                            \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,        \
+       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\
                        CONFIG_ARM64_PAN));                             \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
-               __get_user_asm("ldrb", "%w", __gu_val, (ptr), (err));   \
+               __get_user_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr),  \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 2:                                                         \
-               __get_user_asm("ldrh", "%w", __gu_val, (ptr), (err));   \
+               __get_user_asm("ldrh", "ldtrh", "%w", __gu_val, (ptr),  \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 4:                                                         \
-               __get_user_asm("ldr", "%w", __gu_val, (ptr), (err));    \
+               __get_user_asm("ldr", "ldtr", "%w", __gu_val, (ptr),    \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 8:                                                         \
-               __get_user_asm("ldr", "%",  __gu_val, (ptr), (err));    \
+               __get_user_asm("ldr", "ldtr", "%",  __gu_val, (ptr),    \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        default:                                                        \
                BUILD_BUG();                                            \
        }                                                               \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,        \
+       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\
                        CONFIG_ARM64_PAN));                             \
 } while (0)
 
@@ -181,19 +201,17 @@ do {                                                                      \
                ((x) = 0, -EFAULT);                                     \
 })
 
-#define __put_user_asm(instr, reg, x, addr, err)                       \
+#define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature)   \
        asm volatile(                                                   \
-       "1:     " instr "       " reg "1, [%2]\n"                       \
+       "1:"ALTERNATIVE(instr "     " reg "1, [%2]\n",                  \
+                       alt_instr " " reg "1, [%2]\n", feature)         \
        "2:\n"                                                          \
        "       .section .fixup,\"ax\"\n"                               \
        "       .align  2\n"                                            \
        "3:     mov     %w0, %3\n"                                      \
        "       b       2b\n"                                           \
        "       .previous\n"                                            \
-       "       .section __ex_table,\"a\"\n"                            \
-       "       .align  3\n"                                            \
-       "       .quad   1b, 3b\n"                                       \
-       "       .previous"                                              \
+       _ASM_EXTABLE(1b, 3b)                                            \
        : "+r" (err)                                                    \
        : "r" (x), "r" (addr), "i" (-EFAULT))
 
@@ -201,25 +219,29 @@ do {                                                                      \
 do {                                                                   \
        __typeof__(*(ptr)) __pu_val = (x);                              \
        __chk_user_ptr(ptr);                                            \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,        \
+       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\
                        CONFIG_ARM64_PAN));                             \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
-               __put_user_asm("strb", "%w", __pu_val, (ptr), (err));   \
+               __put_user_asm("strb", "sttrb", "%w", __pu_val, (ptr),  \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 2:                                                         \
-               __put_user_asm("strh", "%w", __pu_val, (ptr), (err));   \
+               __put_user_asm("strh", "sttrh", "%w", __pu_val, (ptr),  \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 4:                                                         \
-               __put_user_asm("str",  "%w", __pu_val, (ptr), (err));   \
+               __put_user_asm("str", "sttr", "%w", __pu_val, (ptr),    \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        case 8:                                                         \
-               __put_user_asm("str",  "%", __pu_val, (ptr), (err));    \
+               __put_user_asm("str", "sttr", "%", __pu_val, (ptr),     \
+                              (err), ARM64_HAS_UAO);                   \
                break;                                                  \
        default:                                                        \
                BUILD_BUG();                                            \
        }                                                               \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,        \
+       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\
                        CONFIG_ARM64_PAN));                             \
 } while (0)
 
index aab5bf09e9d902f7bdf3d09e61fcd97db748c505..2b79b8a89457bd70e20e24ba33c8029195e3284c 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __ASM_WORD_AT_A_TIME_H
 #define __ASM_WORD_AT_A_TIME_H
 
+#include <asm/uaccess.h>
+
 #ifndef __AARCH64EB__
 
 #include <linux/kernel.h>
@@ -81,10 +83,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
 #endif
        "       b       2b\n"
        "       .popsection\n"
-       "       .pushsection __ex_table,\"a\"\n"
-       "       .align  3\n"
-       "       .quad   1b, 3b\n"
-       "       .popsection"
+       _ASM_EXTABLE(1b, 3b)
        : "=&r" (ret), "=&r" (offset)
        : "r" (addr), "Q" (*(unsigned long *)addr));
 
index 208db3df135a48d1b7118da22697ad24cd75706e..b5c3933ed44163b2fb489a00553195afc1ff6806 100644 (file)
@@ -45,6 +45,7 @@
 #define PSR_A_BIT      0x00000100
 #define PSR_D_BIT      0x00000200
 #define PSR_PAN_BIT    0x00400000
+#define PSR_UAO_BIT    0x00800000
 #define PSR_Q_BIT      0x08000000
 #define PSR_V_BIT      0x10000000
 #define PSR_C_BIT      0x20000000
index 474691f8b13ab893cf403b8c1737a91aeff87bc0..49a2430b0786e6df6e8bd39a3d12811783eead7d 100644 (file)
@@ -30,6 +30,7 @@ arm64-obj-$(CONFIG_COMPAT)            += sys32.o kuser32.o signal32.o         \
                                           ../../arm/kernel/opcodes.o
 arm64-obj-$(CONFIG_FUNCTION_TRACER)    += ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)            += arm64ksyms.o module.o
+arm64-obj-$(CONFIG_ARM64_MODULE_PLTS)  += module-plts.o
 arm64-obj-$(CONFIG_PERF_EVENTS)                += perf_regs.o perf_callchain.o
 arm64-obj-$(CONFIG_HW_PERF_EVENTS)     += perf_event.o
 arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
@@ -41,6 +42,8 @@ arm64-obj-$(CONFIG_EFI)                       += efi.o efi-entry.stub.o
 arm64-obj-$(CONFIG_PCI)                        += pci.o
 arm64-obj-$(CONFIG_ARMV8_DEPRECATED)   += armv8_deprecated.o
 arm64-obj-$(CONFIG_ACPI)               += acpi.o
+arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL)        += acpi_parking_protocol.o
+arm64-obj-$(CONFIG_RANDOMIZE_BASE)     += kaslr.o
 
 obj-y                                  += $(arm64-obj-y) vdso/
 obj-m                                  += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/acpi_parking_protocol.c b/arch/arm64/kernel/acpi_parking_protocol.c
new file mode 100644 (file)
index 0000000..4b1e5a7
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * ARM64 ACPI Parking Protocol implementation
+ *
+ * Authors: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *         Mark Salter <msalter@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/acpi.h>
+#include <linux/types.h>
+
+#include <asm/cpu_ops.h>
+
+struct cpu_mailbox_entry {
+       phys_addr_t mailbox_addr;
+       u8 version;
+       u8 gic_cpu_id;
+};
+
+static struct cpu_mailbox_entry cpu_mailbox_entries[NR_CPUS];
+
+void __init acpi_set_mailbox_entry(int cpu,
+                                  struct acpi_madt_generic_interrupt *p)
+{
+       struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+
+       cpu_entry->mailbox_addr = p->parked_address;
+       cpu_entry->version = p->parking_version;
+       cpu_entry->gic_cpu_id = p->cpu_interface_number;
+}
+
+bool acpi_parking_protocol_valid(int cpu)
+{
+       struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+
+       return cpu_entry->mailbox_addr && cpu_entry->version;
+}
+
+static int acpi_parking_protocol_cpu_init(unsigned int cpu)
+{
+       pr_debug("%s: ACPI parked addr=%llx\n", __func__,
+                 cpu_mailbox_entries[cpu].mailbox_addr);
+
+       return 0;
+}
+
+static int acpi_parking_protocol_cpu_prepare(unsigned int cpu)
+{
+       return 0;
+}
+
+struct parking_protocol_mailbox {
+       __le32 cpu_id;
+       __le32 reserved;
+       __le64 entry_point;
+};
+
+static int acpi_parking_protocol_cpu_boot(unsigned int cpu)
+{
+       struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+       struct parking_protocol_mailbox __iomem *mailbox;
+       __le32 cpu_id;
+
+       /*
+        * Map mailbox memory with attribute device nGnRE (ie ioremap -
+        * this deviates from the parking protocol specifications since
+        * the mailboxes are required to be mapped nGnRnE; the attribute
+        * discrepancy is harmless insofar as the protocol specification
+        * is concerned).
+        * If the mailbox is mistakenly allocated in the linear mapping
+        * by FW ioremap will fail since the mapping will be prevented
+        * by the kernel (it clashes with the linear mapping attributes
+        * specifications).
+        */
+       mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox));
+       if (!mailbox)
+               return -EIO;
+
+       cpu_id = readl_relaxed(&mailbox->cpu_id);
+       /*
+        * Check if firmware has set-up the mailbox entry properly
+        * before kickstarting the respective cpu.
+        */
+       if (cpu_id != ~0U) {
+               iounmap(mailbox);
+               return -ENXIO;
+       }
+
+       /*
+        * We write the entry point and cpu id as LE regardless of the
+        * native endianness of the kernel. Therefore, any boot-loaders
+        * that read this address need to convert this address to the
+        * Boot-Loader's endianness before jumping.
+        */
+       writeq_relaxed(__pa(secondary_entry), &mailbox->entry_point);
+       writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
+
+       arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+       iounmap(mailbox);
+
+       return 0;
+}
+
+static void acpi_parking_protocol_cpu_postboot(void)
+{
+       int cpu = smp_processor_id();
+       struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
+       struct parking_protocol_mailbox __iomem *mailbox;
+       __le64 entry_point;
+
+       /*
+        * Map mailbox memory with attribute device nGnRE (ie ioremap -
+        * this deviates from the parking protocol specifications since
+        * the mailboxes are required to be mapped nGnRnE; the attribute
+        * discrepancy is harmless insofar as the protocol specification
+        * is concerned).
+        * If the mailbox is mistakenly allocated in the linear mapping
+        * by FW ioremap will fail since the mapping will be prevented
+        * by the kernel (it clashes with the linear mapping attributes
+        * specifications).
+        */
+       mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox));
+       if (!mailbox)
+               return;
+
+       entry_point = readl_relaxed(&mailbox->entry_point);
+       /*
+        * Check if firmware has cleared the entry_point as expected
+        * by the protocol specification.
+        */
+       WARN_ON(entry_point);
+
+       iounmap(mailbox);
+}
+
+const struct cpu_operations acpi_parking_protocol_ops = {
+       .name           = "parking-protocol",
+       .cpu_init       = acpi_parking_protocol_cpu_init,
+       .cpu_prepare    = acpi_parking_protocol_cpu_prepare,
+       .cpu_boot       = acpi_parking_protocol_cpu_boot,
+       .cpu_postboot   = acpi_parking_protocol_cpu_postboot
+};
index ab9db0e9818c0caa52aa040b7c01aa83183d774e..d2ee1b21a10ddd1bcce1718210c6ce7b7725cfe3 100644 (file)
@@ -158,9 +158,3 @@ void apply_alternatives(void *start, size_t length)
 
        __apply_alternatives(&region);
 }
-
-void free_alternatives_memory(void)
-{
-       free_reserved_area(__alt_instructions, __alt_instructions_end,
-                          0, "alternatives");
-}
index 937f5e58a4d340a27234c76b5a84fedcf9aa6373..c37202c0c838d01a71d56b05d114cd0b419ff480 100644 (file)
@@ -62,7 +62,7 @@ struct insn_emulation {
 };
 
 static LIST_HEAD(insn_emulation);
-static int nr_insn_emulated;
+static int nr_insn_emulated __initdata;
 static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
 
 static void register_emulation_hooks(struct insn_emulation_ops *ops)
@@ -173,7 +173,7 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
        return ret;
 }
 
-static void register_insn_emulation(struct insn_emulation_ops *ops)
+static void __init register_insn_emulation(struct insn_emulation_ops *ops)
 {
        unsigned long flags;
        struct insn_emulation *insn;
@@ -237,7 +237,7 @@ static struct ctl_table ctl_abi[] = {
        { }
 };
 
-static void register_insn_emulation_sysctl(struct ctl_table *table)
+static void __init register_insn_emulation_sysctl(struct ctl_table *table)
 {
        unsigned long flags;
        int i = 0;
@@ -297,11 +297,8 @@ static void register_insn_emulation_sysctl(struct ctl_table *table)
        "4:     mov             %w0, %w5\n"                     \
        "       b               3b\n"                           \
        "       .popsection"                                    \
-       "       .pushsection     __ex_table,\"a\"\n"            \
-       "       .align          3\n"                            \
-       "       .quad           0b, 4b\n"                       \
-       "       .quad           1b, 4b\n"                       \
-       "       .popsection\n"                                  \
+       _ASM_EXTABLE(0b, 4b)                                    \
+       _ASM_EXTABLE(1b, 4b)                                    \
        ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,    \
                CONFIG_ARM64_PAN)                               \
        : "=&r" (res), "+r" (data), "=&r" (temp)                \
index feb6b4efa6414846d5598ccb0913a544ba0cf441..e6bc988e8dbf0f69fc4b1a48f9a7b4a89ee713f3 100644 (file)
 #include <asm/cputype.h>
 #include <asm/cpufeature.h>
 
-#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
-#define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
-#define MIDR_THUNDERX  MIDR_CPU_PART(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
-
-#define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
-                       MIDR_ARCHITECTURE_MASK)
-
 static bool __maybe_unused
 is_affected_midr_range(const struct arm64_cpu_capabilities *entry)
 {
-       u32 midr = read_cpuid_id();
-
-       if ((midr & CPU_MODEL_MASK) != entry->midr_model)
-               return false;
-
-       midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
-
-       return (midr >= entry->midr_range_min && midr <= entry->midr_range_max);
+       return MIDR_IS_CPU_MODEL_RANGE(read_cpuid_id(), entry->midr_model,
+                                      entry->midr_range_min,
+                                      entry->midr_range_max);
 }
 
 #define MIDR_RANGE(model, min, max) \
index b6bd7d4477683393fb34dc6b055b07382e8ab050..c7cfb8fe06f94c7f5113abf0cb624980e4227127 100644 (file)
 #include <asm/smp_plat.h>
 
 extern const struct cpu_operations smp_spin_table_ops;
+extern const struct cpu_operations acpi_parking_protocol_ops;
 extern const struct cpu_operations cpu_psci_ops;
 
 const struct cpu_operations *cpu_ops[NR_CPUS];
 
-static const struct cpu_operations *supported_cpu_ops[] __initconst = {
+static const struct cpu_operations *dt_supported_cpu_ops[] __initconst = {
        &smp_spin_table_ops,
        &cpu_psci_ops,
        NULL,
 };
 
+static const struct cpu_operations *acpi_supported_cpu_ops[] __initconst = {
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+       &acpi_parking_protocol_ops,
+#endif
+       &cpu_psci_ops,
+       NULL,
+};
+
 static const struct cpu_operations * __init cpu_get_ops(const char *name)
 {
-       const struct cpu_operations **ops = supported_cpu_ops;
+       const struct cpu_operations **ops;
+
+       ops = acpi_disabled ? dt_supported_cpu_ops : acpi_supported_cpu_ops;
 
        while (*ops) {
                if (!strcmp(name, (*ops)->name))
@@ -75,8 +86,16 @@ static const char *__init cpu_read_enable_method(int cpu)
                }
        } else {
                enable_method = acpi_get_enable_method(cpu);
-               if (!enable_method)
-                       pr_err("Unsupported ACPI enable-method\n");
+               if (!enable_method) {
+                       /*
+                        * In ACPI systems the boot CPU does not require
+                        * checking the enable method since for some
+                        * boot protocol (ie parking protocol) it need not
+                        * be initialized. Don't warn spuriously.
+                        */
+                       if (cpu != 0)
+                               pr_err("Unsupported ACPI enable-method\n");
+               }
        }
 
        return enable_method;
index 0669c63281ea01a93ef9794f9731b424b6afd28e..7566cad9fa1da5a882ada85b5801a8ae33f4da0c 100644 (file)
@@ -67,6 +67,10 @@ DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
                .width = 0,                             \
        }
 
+/* meta feature for alternatives */
+static bool __maybe_unused
+cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry);
+
 static struct arm64_ftr_bits ftr_id_aa64isar0[] = {
        ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
        ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64ISAR0_RDM_SHIFT, 4, 0),
@@ -123,6 +127,11 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
        ARM64_FTR_END,
 };
 
+static struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
+       ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64MMFR2_UAO_SHIFT, 4, 0),
+       ARM64_FTR_END,
+};
+
 static struct arm64_ftr_bits ftr_ctr[] = {
        U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1),      /* RAO */
        ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0),
@@ -284,6 +293,7 @@ static struct arm64_ftr_reg arm64_ftr_regs[] = {
        /* Op1 = 0, CRn = 0, CRm = 7 */
        ARM64_FTR_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0),
        ARM64_FTR_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1),
+       ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2),
 
        /* Op1 = 3, CRn = 0, CRm = 0 */
        ARM64_FTR_REG(SYS_CTR_EL0, ftr_ctr),
@@ -408,6 +418,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
        init_cpu_ftr_reg(SYS_ID_AA64ISAR1_EL1, info->reg_id_aa64isar1);
        init_cpu_ftr_reg(SYS_ID_AA64MMFR0_EL1, info->reg_id_aa64mmfr0);
        init_cpu_ftr_reg(SYS_ID_AA64MMFR1_EL1, info->reg_id_aa64mmfr1);
+       init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
        init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0);
        init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
        init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
@@ -517,6 +528,8 @@ void update_cpu_features(int cpu,
                                      info->reg_id_aa64mmfr0, boot->reg_id_aa64mmfr0);
        taint |= check_update_ftr_reg(SYS_ID_AA64MMFR1_EL1, cpu,
                                      info->reg_id_aa64mmfr1, boot->reg_id_aa64mmfr1);
+       taint |= check_update_ftr_reg(SYS_ID_AA64MMFR2_EL1, cpu,
+                                     info->reg_id_aa64mmfr2, boot->reg_id_aa64mmfr2);
 
        /*
         * EL3 is not our concern.
@@ -621,6 +634,18 @@ static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry)
        return has_sre;
 }
 
+static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry)
+{
+       u32 midr = read_cpuid_id();
+       u32 rv_min, rv_max;
+
+       /* Cavium ThunderX pass 1.x and 2.x */
+       rv_min = 0;
+       rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
+
+       return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
+}
+
 static const struct arm64_cpu_capabilities arm64_features[] = {
        {
                .desc = "GIC system register CPU interface",
@@ -651,6 +676,28 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .min_field_value = 2,
        },
 #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
+       {
+               .desc = "Software prefetching using PRFM",
+               .capability = ARM64_HAS_NO_HW_PREFETCH,
+               .matches = has_no_hw_prefetch,
+       },
+#ifdef CONFIG_ARM64_UAO
+       {
+               .desc = "User Access Override",
+               .capability = ARM64_HAS_UAO,
+               .matches = has_cpuid_feature,
+               .sys_reg = SYS_ID_AA64MMFR2_EL1,
+               .field_pos = ID_AA64MMFR2_UAO_SHIFT,
+               .min_field_value = 1,
+               .enable = cpu_enable_uao,
+       },
+#endif /* CONFIG_ARM64_UAO */
+#ifdef CONFIG_ARM64_PAN
+       {
+               .capability = ARM64_ALT_PAN_NOT_UAO,
+               .matches = cpufeature_pan_not_uao,
+       },
+#endif /* CONFIG_ARM64_PAN */
        {},
 };
 
@@ -684,7 +731,7 @@ static const struct arm64_cpu_capabilities arm64_hwcaps[] = {
        {},
 };
 
-static void cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
+static void __init cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
 {
        switch (cap->hwcap_type) {
        case CAP_HWCAP:
@@ -729,12 +776,12 @@ static bool __maybe_unused cpus_have_hwcap(const struct arm64_cpu_capabilities *
        return rc;
 }
 
-static void setup_cpu_hwcaps(void)
+static void __init setup_cpu_hwcaps(void)
 {
        int i;
        const struct arm64_cpu_capabilities *hwcaps = arm64_hwcaps;
 
-       for (i = 0; hwcaps[i].desc; i++)
+       for (i = 0; hwcaps[i].matches; i++)
                if (hwcaps[i].matches(&hwcaps[i]))
                        cap_set_hwcap(&hwcaps[i]);
 }
@@ -744,11 +791,11 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
 {
        int i;
 
-       for (i = 0; caps[i].desc; i++) {
+       for (i = 0; caps[i].matches; i++) {
                if (!caps[i].matches(&caps[i]))
                        continue;
 
-               if (!cpus_have_cap(caps[i].capability))
+               if (!cpus_have_cap(caps[i].capability) && caps[i].desc)
                        pr_info("%s %s\n", info, caps[i].desc);
                cpus_set_cap(caps[i].capability);
        }
@@ -758,11 +805,12 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
  * Run through the enabled capabilities and enable() it on all active
  * CPUs
  */
-static void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
+static void __init
+enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
 {
        int i;
 
-       for (i = 0; caps[i].desc; i++)
+       for (i = 0; caps[i].matches; i++)
                if (caps[i].enable && cpus_have_cap(caps[i].capability))
                        on_each_cpu(caps[i].enable, NULL, true);
 }
@@ -790,35 +838,36 @@ static inline void set_sys_caps_initialised(void)
 static u64 __raw_read_system_reg(u32 sys_id)
 {
        switch (sys_id) {
-       case SYS_ID_PFR0_EL1:           return (u64)read_cpuid(ID_PFR0_EL1);
-       case SYS_ID_PFR1_EL1:           return (u64)read_cpuid(ID_PFR1_EL1);
-       case SYS_ID_DFR0_EL1:           return (u64)read_cpuid(ID_DFR0_EL1);
-       case SYS_ID_MMFR0_EL1:          return (u64)read_cpuid(ID_MMFR0_EL1);
-       case SYS_ID_MMFR1_EL1:          return (u64)read_cpuid(ID_MMFR1_EL1);
-       case SYS_ID_MMFR2_EL1:          return (u64)read_cpuid(ID_MMFR2_EL1);
-       case SYS_ID_MMFR3_EL1:          return (u64)read_cpuid(ID_MMFR3_EL1);
-       case SYS_ID_ISAR0_EL1:          return (u64)read_cpuid(ID_ISAR0_EL1);
-       case SYS_ID_ISAR1_EL1:          return (u64)read_cpuid(ID_ISAR1_EL1);
-       case SYS_ID_ISAR2_EL1:          return (u64)read_cpuid(ID_ISAR2_EL1);
-       case SYS_ID_ISAR3_EL1:          return (u64)read_cpuid(ID_ISAR3_EL1);
-       case SYS_ID_ISAR4_EL1:          return (u64)read_cpuid(ID_ISAR4_EL1);
-       case SYS_ID_ISAR5_EL1:          return (u64)read_cpuid(ID_ISAR4_EL1);
-       case SYS_MVFR0_EL1:             return (u64)read_cpuid(MVFR0_EL1);
-       case SYS_MVFR1_EL1:             return (u64)read_cpuid(MVFR1_EL1);
-       case SYS_MVFR2_EL1:             return (u64)read_cpuid(MVFR2_EL1);
-
-       case SYS_ID_AA64PFR0_EL1:       return (u64)read_cpuid(ID_AA64PFR0_EL1);
-       case SYS_ID_AA64PFR1_EL1:       return (u64)read_cpuid(ID_AA64PFR0_EL1);
-       case SYS_ID_AA64DFR0_EL1:       return (u64)read_cpuid(ID_AA64DFR0_EL1);
-       case SYS_ID_AA64DFR1_EL1:       return (u64)read_cpuid(ID_AA64DFR0_EL1);
-       case SYS_ID_AA64MMFR0_EL1:      return (u64)read_cpuid(ID_AA64MMFR0_EL1);
-       case SYS_ID_AA64MMFR1_EL1:      return (u64)read_cpuid(ID_AA64MMFR1_EL1);
-       case SYS_ID_AA64ISAR0_EL1:      return (u64)read_cpuid(ID_AA64ISAR0_EL1);
-       case SYS_ID_AA64ISAR1_EL1:      return (u64)read_cpuid(ID_AA64ISAR1_EL1);
-
-       case SYS_CNTFRQ_EL0:            return (u64)read_cpuid(CNTFRQ_EL0);
-       case SYS_CTR_EL0:               return (u64)read_cpuid(CTR_EL0);
-       case SYS_DCZID_EL0:             return (u64)read_cpuid(DCZID_EL0);
+       case SYS_ID_PFR0_EL1:           return read_cpuid(SYS_ID_PFR0_EL1);
+       case SYS_ID_PFR1_EL1:           return read_cpuid(SYS_ID_PFR1_EL1);
+       case SYS_ID_DFR0_EL1:           return read_cpuid(SYS_ID_DFR0_EL1);
+       case SYS_ID_MMFR0_EL1:          return read_cpuid(SYS_ID_MMFR0_EL1);
+       case SYS_ID_MMFR1_EL1:          return read_cpuid(SYS_ID_MMFR1_EL1);
+       case SYS_ID_MMFR2_EL1:          return read_cpuid(SYS_ID_MMFR2_EL1);
+       case SYS_ID_MMFR3_EL1:          return read_cpuid(SYS_ID_MMFR3_EL1);
+       case SYS_ID_ISAR0_EL1:          return read_cpuid(SYS_ID_ISAR0_EL1);
+       case SYS_ID_ISAR1_EL1:          return read_cpuid(SYS_ID_ISAR1_EL1);
+       case SYS_ID_ISAR2_EL1:          return read_cpuid(SYS_ID_ISAR2_EL1);
+       case SYS_ID_ISAR3_EL1:          return read_cpuid(SYS_ID_ISAR3_EL1);
+       case SYS_ID_ISAR4_EL1:          return read_cpuid(SYS_ID_ISAR4_EL1);
+       case SYS_ID_ISAR5_EL1:          return read_cpuid(SYS_ID_ISAR4_EL1);
+       case SYS_MVFR0_EL1:             return read_cpuid(SYS_MVFR0_EL1);
+       case SYS_MVFR1_EL1:             return read_cpuid(SYS_MVFR1_EL1);
+       case SYS_MVFR2_EL1:             return read_cpuid(SYS_MVFR2_EL1);
+
+       case SYS_ID_AA64PFR0_EL1:       return read_cpuid(SYS_ID_AA64PFR0_EL1);
+       case SYS_ID_AA64PFR1_EL1:       return read_cpuid(SYS_ID_AA64PFR0_EL1);
+       case SYS_ID_AA64DFR0_EL1:       return read_cpuid(SYS_ID_AA64DFR0_EL1);
+       case SYS_ID_AA64DFR1_EL1:       return read_cpuid(SYS_ID_AA64DFR0_EL1);
+       case SYS_ID_AA64MMFR0_EL1:      return read_cpuid(SYS_ID_AA64MMFR0_EL1);
+       case SYS_ID_AA64MMFR1_EL1:      return read_cpuid(SYS_ID_AA64MMFR1_EL1);
+       case SYS_ID_AA64MMFR2_EL1:      return read_cpuid(SYS_ID_AA64MMFR2_EL1);
+       case SYS_ID_AA64ISAR0_EL1:      return read_cpuid(SYS_ID_AA64ISAR0_EL1);
+       case SYS_ID_AA64ISAR1_EL1:      return read_cpuid(SYS_ID_AA64ISAR1_EL1);
+
+       case SYS_CNTFRQ_EL0:            return read_cpuid(SYS_CNTFRQ_EL0);
+       case SYS_CTR_EL0:               return read_cpuid(SYS_CTR_EL0);
+       case SYS_DCZID_EL0:             return read_cpuid(SYS_DCZID_EL0);
        default:
                BUG();
                return 0;
@@ -868,7 +917,7 @@ void verify_local_cpu_capabilities(void)
                return;
 
        caps = arm64_features;
-       for (i = 0; caps[i].desc; i++) {
+       for (i = 0; caps[i].matches; i++) {
                if (!cpus_have_cap(caps[i].capability) || !caps[i].sys_reg)
                        continue;
                /*
@@ -881,7 +930,7 @@ void verify_local_cpu_capabilities(void)
                        caps[i].enable(NULL);
        }
 
-       for (i = 0, caps = arm64_hwcaps; caps[i].desc; i++) {
+       for (i = 0, caps = arm64_hwcaps; caps[i].matches; i++) {
                if (!cpus_have_hwcap(&caps[i]))
                        continue;
                if (!feature_matches(__raw_read_system_reg(caps[i].sys_reg), &caps[i]))
@@ -897,7 +946,7 @@ static inline void set_sys_caps_initialised(void)
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static void setup_feature_capabilities(void)
+static void __init setup_feature_capabilities(void)
 {
        update_cpu_capabilities(arm64_features, "detected feature:");
        enable_cpu_capabilities(arm64_features);
@@ -927,3 +976,9 @@ void __init setup_cpu_features(void)
                pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n",
                        L1_CACHE_BYTES, cls);
 }
+
+static bool __maybe_unused
+cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry)
+{
+       return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO));
+}
index 212ae6361d8be45d6d73d197284a1ca587599342..966fbd52550bab44c720368fd3bda3092b0acb96 100644 (file)
@@ -201,35 +201,36 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
 {
        info->reg_cntfrq = arch_timer_get_cntfrq();
        info->reg_ctr = read_cpuid_cachetype();
-       info->reg_dczid = read_cpuid(DCZID_EL0);
+       info->reg_dczid = read_cpuid(SYS_DCZID_EL0);
        info->reg_midr = read_cpuid_id();
 
-       info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
-       info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
-       info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
-       info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
-       info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
-       info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
-       info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
-       info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
-
-       info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
-       info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
-       info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
-       info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
-       info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
-       info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
-       info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
-       info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
-       info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
-       info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
-       info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
-       info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
-       info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
-
-       info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
-       info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
-       info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
+       info->reg_id_aa64dfr0 = read_cpuid(SYS_ID_AA64DFR0_EL1);
+       info->reg_id_aa64dfr1 = read_cpuid(SYS_ID_AA64DFR1_EL1);
+       info->reg_id_aa64isar0 = read_cpuid(SYS_ID_AA64ISAR0_EL1);
+       info->reg_id_aa64isar1 = read_cpuid(SYS_ID_AA64ISAR1_EL1);
+       info->reg_id_aa64mmfr0 = read_cpuid(SYS_ID_AA64MMFR0_EL1);
+       info->reg_id_aa64mmfr1 = read_cpuid(SYS_ID_AA64MMFR1_EL1);
+       info->reg_id_aa64mmfr2 = read_cpuid(SYS_ID_AA64MMFR2_EL1);
+       info->reg_id_aa64pfr0 = read_cpuid(SYS_ID_AA64PFR0_EL1);
+       info->reg_id_aa64pfr1 = read_cpuid(SYS_ID_AA64PFR1_EL1);
+
+       info->reg_id_dfr0 = read_cpuid(SYS_ID_DFR0_EL1);
+       info->reg_id_isar0 = read_cpuid(SYS_ID_ISAR0_EL1);
+       info->reg_id_isar1 = read_cpuid(SYS_ID_ISAR1_EL1);
+       info->reg_id_isar2 = read_cpuid(SYS_ID_ISAR2_EL1);
+       info->reg_id_isar3 = read_cpuid(SYS_ID_ISAR3_EL1);
+       info->reg_id_isar4 = read_cpuid(SYS_ID_ISAR4_EL1);
+       info->reg_id_isar5 = read_cpuid(SYS_ID_ISAR5_EL1);
+       info->reg_id_mmfr0 = read_cpuid(SYS_ID_MMFR0_EL1);
+       info->reg_id_mmfr1 = read_cpuid(SYS_ID_MMFR1_EL1);
+       info->reg_id_mmfr2 = read_cpuid(SYS_ID_MMFR2_EL1);
+       info->reg_id_mmfr3 = read_cpuid(SYS_ID_MMFR3_EL1);
+       info->reg_id_pfr0 = read_cpuid(SYS_ID_PFR0_EL1);
+       info->reg_id_pfr1 = read_cpuid(SYS_ID_PFR1_EL1);
+
+       info->reg_mvfr0 = read_cpuid(SYS_MVFR0_EL1);
+       info->reg_mvfr1 = read_cpuid(SYS_MVFR1_EL1);
+       info->reg_mvfr2 = read_cpuid(SYS_MVFR2_EL1);
 
        cpuinfo_detect_icache_policy(info);
 
index 8aee3aeec3e687edde6f5be67233299e7a4f7d4f..c1492ba1f6d14e71c263fa26904fab9980439b4f 100644 (file)
@@ -186,20 +186,21 @@ static void clear_regs_spsr_ss(struct pt_regs *regs)
 
 /* EL1 Single Step Handler hooks */
 static LIST_HEAD(step_hook);
-static DEFINE_RWLOCK(step_hook_lock);
+static DEFINE_SPINLOCK(step_hook_lock);
 
 void register_step_hook(struct step_hook *hook)
 {
-       write_lock(&step_hook_lock);
-       list_add(&hook->node, &step_hook);
-       write_unlock(&step_hook_lock);
+       spin_lock(&step_hook_lock);
+       list_add_rcu(&hook->node, &step_hook);
+       spin_unlock(&step_hook_lock);
 }
 
 void unregister_step_hook(struct step_hook *hook)
 {
-       write_lock(&step_hook_lock);
-       list_del(&hook->node);
-       write_unlock(&step_hook_lock);
+       spin_lock(&step_hook_lock);
+       list_del_rcu(&hook->node);
+       spin_unlock(&step_hook_lock);
+       synchronize_rcu();
 }
 
 /*
@@ -213,15 +214,15 @@ static int call_step_hook(struct pt_regs *regs, unsigned int esr)
        struct step_hook *hook;
        int retval = DBG_HOOK_ERROR;
 
-       read_lock(&step_hook_lock);
+       rcu_read_lock();
 
-       list_for_each_entry(hook, &step_hook, node)     {
+       list_for_each_entry_rcu(hook, &step_hook, node) {
                retval = hook->fn(regs, esr);
                if (retval == DBG_HOOK_HANDLED)
                        break;
        }
 
-       read_unlock(&step_hook_lock);
+       rcu_read_unlock();
 
        return retval;
 }
index a773db92908b03d325c26dba0dc5ea9c287ef49d..f82036e02485a0abe27349e3ec76a00a491f7450 100644 (file)
@@ -61,7 +61,7 @@ ENTRY(entry)
         */
        mov     x20, x0         // DTB address
        ldr     x0, [sp, #16]   // relocated _text address
-       ldr     x21, =stext_offset
+       movz    x21, #:abs_g0:stext_offset
        add     x21, x0, x21
 
        /*
index 7ed3d75f630418b56a1add8c91b308b48cd69774..1f7f5a2b61bf0de999d80e6ced16bec120f716b6 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/cpufeature.h>
 #include <asm/errno.h>
 #include <asm/esr.h>
+#include <asm/irq.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
 
 
        .if     \el == 0
        mrs     x21, sp_el0
-       get_thread_info tsk                     // Ensure MDSCR_EL1.SS is clear,
+       mov     tsk, sp
+       and     tsk, tsk, #~(THREAD_SIZE - 1)   // Ensure MDSCR_EL1.SS is clear,
        ldr     x19, [tsk, #TI_FLAGS]           // since we can unmask debug
        disable_step_tsk x19, x20               // exceptions when scheduling.
+
+       mov     x29, xzr                        // fp pointed to user-space
        .else
        add     x21, sp, #S_FRAME_SIZE
        .endif
        str     x21, [sp, #S_SYSCALLNO]
        .endif
 
+       /*
+        * Set sp_el0 to current thread_info.
+        */
+       .if     \el == 0
+       msr     sp_el0, tsk
+       .endif
+
        /*
         * Registers that may be useful after this macro is invoked:
         *
@@ -164,8 +175,44 @@ alternative_endif
        .endm
 
        .macro  get_thread_info, rd
-       mov     \rd, sp
-       and     \rd, \rd, #~(THREAD_SIZE - 1)   // top of stack
+       mrs     \rd, sp_el0
+       .endm
+
+       .macro  irq_stack_entry
+       mov     x19, sp                 // preserve the original sp
+
+       /*
+        * Compare sp with the current thread_info, if the top
+        * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and
+        * should switch to the irq stack.
+        */
+       and     x25, x19, #~(THREAD_SIZE - 1)
+       cmp     x25, tsk
+       b.ne    9998f
+
+       this_cpu_ptr irq_stack, x25, x26
+       mov     x26, #IRQ_STACK_START_SP
+       add     x26, x25, x26
+
+       /* switch to the irq stack */
+       mov     sp, x26
+
+       /*
+        * Add a dummy stack frame, this non-standard format is fixed up
+        * by unwind_frame()
+        */
+       stp     x29, x19, [sp, #-16]!
+       mov     x29, sp
+
+9998:
+       .endm
+
+       /*
+        * x19 should be preserved between irq_stack_entry and
+        * irq_stack_exit.
+        */
+       .macro  irq_stack_exit
+       mov     sp, x19
        .endm
 
 /*
@@ -183,10 +230,11 @@ tsk       .req    x28             // current thread_info
  * Interrupt handling.
  */
        .macro  irq_handler
-       adrp    x1, handle_arch_irq
-       ldr     x1, [x1, #:lo12:handle_arch_irq]
+       ldr_l   x1, handle_arch_irq
        mov     x0, sp
+       irq_stack_entry
        blr     x1
+       irq_stack_exit
        .endm
 
        .text
@@ -358,10 +406,10 @@ el1_irq:
        bl      trace_hardirqs_off
 #endif
 
+       get_thread_info tsk
        irq_handler
 
 #ifdef CONFIG_PREEMPT
-       get_thread_info tsk
        ldr     w24, [tsk, #TI_PREEMPT]         // get preempt count
        cbnz    w24, 1f                         // preempt count != 0
        ldr     x0, [tsk, #TI_FLAGS]            // get flags
@@ -599,6 +647,8 @@ ENTRY(cpu_switch_to)
        ldp     x29, x9, [x8], #16
        ldr     lr, [x8]
        mov     sp, x9
+       and     x9, x9, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x9
        ret
 ENDPROC(cpu_switch_to)
 
@@ -626,14 +676,14 @@ ret_fast_syscall_trace:
 work_pending:
        tbnz    x1, #TIF_NEED_RESCHED, work_resched
        /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */
-       ldr     x2, [sp, #S_PSTATE]
        mov     x0, sp                          // 'regs'
-       tst     x2, #PSR_MODE_MASK              // user mode regs?
-       b.ne    no_work_pending                 // returning to kernel
        enable_irq                              // enable interrupts for do_notify_resume()
        bl      do_notify_resume
        b       ret_to_user
 work_resched:
+#ifdef CONFIG_TRACE_IRQFLAGS
+       bl      trace_hardirqs_off              // the IRQs are off here, inform the tracing code
+#endif
        bl      schedule
 
 /*
@@ -645,7 +695,6 @@ ret_to_user:
        and     x2, x1, #_TIF_WORK_MASK
        cbnz    x2, work_pending
        enable_step_tsk x1, x2
-no_work_pending:
        kernel_exit 0
 ENDPROC(ret_to_user)
 
index 4c46c54a3ad7ad817b8ba410565b8eff47cd3c08..acc1afd5c749a62b7c0bae5a14d2fd7dbc33adf2 100644 (file)
@@ -289,7 +289,7 @@ static struct notifier_block fpsimd_cpu_pm_notifier_block = {
        .notifier_call = fpsimd_cpu_pm_notifier,
 };
 
-static void fpsimd_pm_init(void)
+static void __init fpsimd_pm_init(void)
 {
        cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block);
 }
index c851be795080336938f4826cc0608234b0e34bfa..ebecf9aa33d12da8a564ea0314f59a71b89e64a0 100644 (file)
@@ -29,12 +29,11 @@ static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
 
        /*
         * Note:
-        * Due to modules and __init, code can disappear and change,
-        * we need to protect against faulting as well as code changing.
-        * We do this by aarch64_insn_*() which use the probe_kernel_*().
-        *
-        * No lock is held here because all the modifications are run
-        * through stop_machine().
+        * We are paranoid about modifying text, as if a bug were to happen, it
+        * could cause us to read or write to someplace that could cause harm.
+        * Carefully read and modify the code with aarch64_insn_*() which uses
+        * probe_kernel_*(), and make sure what we read is what we expected it
+        * to be before modifying it.
         */
        if (validate) {
                if (aarch64_insn_read((void *)pc, &replaced))
@@ -93,6 +92,11 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
        return ftrace_modify_code(pc, old, new, true);
 }
 
+void arch_ftrace_update_code(int command)
+{
+       ftrace_modify_all_code(command);
+}
+
 int __init ftrace_dyn_arch_init(void)
 {
        return 0;
@@ -125,23 +129,20 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
         * on other archs. It's unlikely on AArch64.
         */
        old = *parent;
-       *parent = return_hooker;
 
        trace.func = self_addr;
        trace.depth = current->curr_ret_stack + 1;
 
        /* Only trace if the calling function expects to */
-       if (!ftrace_graph_entry(&trace)) {
-               *parent = old;
+       if (!ftrace_graph_entry(&trace))
                return;
-       }
 
        err = ftrace_push_return_trace(old, self_addr, &trace.depth,
                                       frame_pointer);
-       if (err == -EBUSY) {
-               *parent = old;
+       if (err == -EBUSY)
                return;
-       }
+       else
+               *parent = return_hooker;
 }
 
 #ifdef CONFIG_DYNAMIC_FTRACE
index b685257926f0b0472550036f6d3ba34d17af7f62..a88a15447c3bb382970a940b39fb9d6e0e6b9529 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
 #include <asm/cputype.h>
+#include <asm/elf.h>
 #include <asm/kernel-pgtable.h>
 #include <asm/memory.h>
 #include <asm/pgtable-hwdef.h>
  * in the entry routines.
  */
        __HEAD
-
+_head:
        /*
         * DO NOT MODIFY. Image header expected by Linux boot-loaders.
         */
 #ifdef CONFIG_EFI
-efi_head:
        /*
         * This add instruction has no meaningful effect except that
         * its opcode forms the magic "MZ" signature required by UEFI.
@@ -83,9 +83,9 @@ efi_head:
        b       stext                           // branch to kernel start, magic
        .long   0                               // reserved
 #endif
-       .quad   _kernel_offset_le               // Image load offset from start of RAM, little-endian
-       .quad   _kernel_size_le                 // Effective size of kernel image, little-endian
-       .quad   _kernel_flags_le                // Informative flags, little-endian
+       le64sym _kernel_offset_le               // Image load offset from start of RAM, little-endian
+       le64sym _kernel_size_le                 // Effective size of kernel image, little-endian
+       le64sym _kernel_flags_le                // Informative flags, little-endian
        .quad   0                               // reserved
        .quad   0                               // reserved
        .quad   0                               // reserved
@@ -94,14 +94,14 @@ efi_head:
        .byte   0x4d
        .byte   0x64
 #ifdef CONFIG_EFI
-       .long   pe_header - efi_head            // Offset to the PE header.
+       .long   pe_header - _head               // Offset to the PE header.
 #else
        .word   0                               // reserved
 #endif
 
 #ifdef CONFIG_EFI
        .globl  __efistub_stext_offset
-       .set    __efistub_stext_offset, stext - efi_head
+       .set    __efistub_stext_offset, stext - _head
        .align 3
 pe_header:
        .ascii  "PE"
@@ -124,7 +124,7 @@ optional_header:
        .long   _end - stext                    // SizeOfCode
        .long   0                               // SizeOfInitializedData
        .long   0                               // SizeOfUninitializedData
-       .long   __efistub_entry - efi_head      // AddressOfEntryPoint
+       .long   __efistub_entry - _head         // AddressOfEntryPoint
        .long   __efistub_stext_offset          // BaseOfCode
 
 extra_header_fields:
@@ -139,7 +139,7 @@ extra_header_fields:
        .short  0                               // MinorSubsystemVersion
        .long   0                               // Win32VersionValue
 
-       .long   _end - efi_head                 // SizeOfImage
+       .long   _end - _head                    // SizeOfImage
 
        // Everything before the kernel image is considered part of the header
        .long   __efistub_stext_offset          // SizeOfHeaders
@@ -210,6 +210,7 @@ section_table:
 ENTRY(stext)
        bl      preserve_boot_args
        bl      el2_setup                       // Drop to EL1, w20=cpu_boot_mode
+       mov     x23, xzr                        // KASLR offset, defaults to 0
        adrp    x24, __PHYS_OFFSET
        bl      set_cpu_boot_mode_flag
        bl      __create_page_tables            // x25=TTBR0, x26=TTBR1
@@ -219,11 +220,13 @@ ENTRY(stext)
         * On return, the CPU will be ready for the MMU to be turned on and
         * the TCR will have been set.
         */
-       ldr     x27, =__mmap_switched           // address to jump to after
+       ldr     x27, 0f                         // address to jump to after
                                                // MMU has been enabled
        adr_l   lr, __enable_mmu                // return (PIC) address
        b       __cpu_setup                     // initialise processor
 ENDPROC(stext)
+       .align  3
+0:     .quad   __mmap_switched - (_head - TEXT_OFFSET) + KIMAGE_VADDR
 
 /*
  * Preserve the arguments passed by the bootloader in x0 .. x3
@@ -311,7 +314,7 @@ ENDPROC(preserve_boot_args)
 __create_page_tables:
        adrp    x25, idmap_pg_dir
        adrp    x26, swapper_pg_dir
-       mov     x27, lr
+       mov     x28, lr
 
        /*
         * Invalidate the idmap and swapper page tables to avoid potential
@@ -389,9 +392,11 @@ __create_page_tables:
         * Map the kernel image (starting with PHYS_OFFSET).
         */
        mov     x0, x26                         // swapper_pg_dir
-       mov     x5, #PAGE_OFFSET
+       ldr     x5, =KIMAGE_VADDR
+       add     x5, x5, x23                     // add KASLR displacement
        create_pgd_entry x0, x5, x3, x6
-       ldr     x6, =KERNEL_END                 // __va(KERNEL_END)
+       ldr     w6, kernel_img_size
+       add     x6, x6, x5
        mov     x3, x24                         // phys offset
        create_block_map x0, x7, x3, x5, x6
 
@@ -405,9 +410,11 @@ __create_page_tables:
        dmb     sy
        bl      __inval_cache_range
 
-       mov     lr, x27
-       ret
+       ret     x28
 ENDPROC(__create_page_tables)
+
+kernel_img_size:
+       .long   _end - (_head - TEXT_OFFSET)
        .ltorg
 
 /*
@@ -415,20 +422,80 @@ ENDPROC(__create_page_tables)
  */
        .set    initial_sp, init_thread_union + THREAD_START_SP
 __mmap_switched:
-       adr_l   x6, __bss_start
-       adr_l   x7, __bss_stop
+       mov     x28, lr                         // preserve LR
+       adr_l   x8, vectors                     // load VBAR_EL1 with virtual
+       msr     vbar_el1, x8                    // vector table address
+       isb
 
-1:     cmp     x6, x7
+       // Clear BSS
+       adr_l   x0, __bss_start
+       mov     x1, xzr
+       adr_l   x2, __bss_stop
+       sub     x2, x2, x0
+       bl      __pi_memset
+       dsb     ishst                           // Make zero page visible to PTW
+
+#ifdef CONFIG_RELOCATABLE
+
+       /*
+        * Iterate over each entry in the relocation table, and apply the
+        * relocations in place.
+        */
+       adr_l   x8, __dynsym_start              // start of symbol table
+       adr_l   x9, __reloc_start               // start of reloc table
+       adr_l   x10, __reloc_end                // end of reloc table
+
+0:     cmp     x9, x10
        b.hs    2f
-       str     xzr, [x6], #8                   // Clear BSS
-       b       1b
-2:
+       ldp     x11, x12, [x9], #24
+       ldr     x13, [x9, #-8]
+       cmp     w12, #R_AARCH64_RELATIVE
+       b.ne    1f
+       add     x13, x13, x23                   // relocate
+       str     x13, [x11, x23]
+       b       0b
+
+1:     cmp     w12, #R_AARCH64_ABS64
+       b.ne    0b
+       add     x12, x12, x12, lsl #1           // symtab offset: 24x top word
+       add     x12, x8, x12, lsr #(32 - 3)     // ... shifted into bottom word
+       ldrsh   w14, [x12, #6]                  // Elf64_Sym::st_shndx
+       ldr     x15, [x12, #8]                  // Elf64_Sym::st_value
+       cmp     w14, #-0xf                      // SHN_ABS (0xfff1) ?
+       add     x14, x15, x23                   // relocate
+       csel    x15, x14, x15, ne
+       add     x15, x13, x15
+       str     x15, [x11, x23]
+       b       0b
+
+2:     adr_l   x8, kimage_vaddr                // make relocated kimage_vaddr
+       dc      cvac, x8                        // value visible to secondaries
+       dsb     sy                              // with MMU off
+#endif
+
        adr_l   sp, initial_sp, x4
+       mov     x4, sp
+       and     x4, x4, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x4                      // Save thread_info
        str_l   x21, __fdt_pointer, x5          // Save FDT pointer
-       str_l   x24, memstart_addr, x6          // Save PHYS_OFFSET
+
+       ldr_l   x4, kimage_vaddr                // Save the offset between
+       sub     x4, x4, x24                     // the kernel virtual and
+       str_l   x4, kimage_voffset, x5          // physical mappings
+
        mov     x29, #0
 #ifdef CONFIG_KASAN
        bl      kasan_early_init
+#endif
+#ifdef CONFIG_RANDOMIZE_BASE
+       cbnz    x23, 0f                         // already running randomized?
+       mov     x0, x21                         // pass FDT address in x0
+       bl      kaslr_early_init                // parse FDT for KASLR options
+       cbz     x0, 0f                          // KASLR disabled? just proceed
+       mov     x23, x0                         // record KASLR offset
+       ret     x28                             // we must enable KASLR, return
+                                               // to __enable_mmu()
+0:
 #endif
        b       start_kernel
 ENDPROC(__mmap_switched)
@@ -438,6 +505,10 @@ ENDPROC(__mmap_switched)
  * hotplug and needs to have the same protections as the text region
  */
        .section ".text","ax"
+
+ENTRY(kimage_vaddr)
+       .quad           _text - TEXT_OFFSET
+
 /*
  * If we're fortunate enough to boot at EL2, ensure that the world is
  * sane before dropping to EL1.
@@ -603,14 +674,22 @@ ENTRY(secondary_startup)
        adrp    x26, swapper_pg_dir
        bl      __cpu_setup                     // initialise processor
 
-       ldr     x21, =secondary_data
-       ldr     x27, =__secondary_switched      // address to jump to after enabling the MMU
+       ldr     x8, kimage_vaddr
+       ldr     w9, 0f
+       sub     x27, x8, w9, sxtw               // address to jump to after enabling the MMU
        b       __enable_mmu
 ENDPROC(secondary_startup)
+0:     .long   (_text - TEXT_OFFSET) - __secondary_switched
 
 ENTRY(__secondary_switched)
-       ldr     x0, [x21]                       // get secondary_data.stack
+       adr_l   x5, vectors
+       msr     vbar_el1, x5
+       isb
+
+       ldr_l   x0, secondary_data              // get secondary_data.stack
        mov     sp, x0
+       and     x0, x0, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x0                      // save thread_info
        mov     x29, #0
        b       secondary_start_kernel
 ENDPROC(__secondary_switched)
@@ -628,12 +707,11 @@ ENDPROC(__secondary_switched)
  */
        .section        ".idmap.text", "ax"
 __enable_mmu:
+       mrs     x18, sctlr_el1                  // preserve old SCTLR_EL1 value
        mrs     x1, ID_AA64MMFR0_EL1
        ubfx    x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
        cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
        b.ne    __no_granule_support
-       ldr     x5, =vectors
-       msr     vbar_el1, x5
        msr     ttbr0_el1, x25                  // load TTBR0
        msr     ttbr1_el1, x26                  // load TTBR1
        isb
@@ -647,6 +725,26 @@ __enable_mmu:
        ic      iallu
        dsb     nsh
        isb
+#ifdef CONFIG_RANDOMIZE_BASE
+       mov     x19, x0                         // preserve new SCTLR_EL1 value
+       blr     x27
+
+       /*
+        * If we return here, we have a KASLR displacement in x23 which we need
+        * to take into account by discarding the current kernel mapping and
+        * creating a new one.
+        */
+       msr     sctlr_el1, x18                  // disable the MMU
+       isb
+       bl      __create_page_tables            // recreate kernel mapping
+
+       msr     sctlr_el1, x19                  // re-enable the MMU
+       isb
+       ic      iallu                           // flush instructions fetched
+       dsb     nsh                             // via old mapping
+       isb
+       add     x27, x27, x23                   // relocated __mmap_switched
+#endif
        br      x27
 ENDPROC(__enable_mmu)
 
index bc2abb8b1599576ae2dec02bce0c46c48fc707dd..db1bf57948f175a0fd3a9847897889ed5169c1e0 100644 (file)
  * There aren't any ELF relocations we can use to endian-swap values known only
  * at link time (e.g. the subtraction of two symbol addresses), so we must get
  * the linker to endian-swap certain values before emitting them.
+ *
+ * Note that, in order for this to work when building the ELF64 PIE executable
+ * (for KASLR), these values should not be referenced via R_AARCH64_ABS64
+ * relocations, since these are fixed up at runtime rather than at build time
+ * when PIE is in effect. So we need to split them up in 32-bit high and low
+ * words.
  */
 #ifdef CONFIG_CPU_BIG_ENDIAN
-#define DATA_LE64(data)                                        \
-       ((((data) & 0x00000000000000ff) << 56) |        \
-        (((data) & 0x000000000000ff00) << 40) |        \
-        (((data) & 0x0000000000ff0000) << 24) |        \
-        (((data) & 0x00000000ff000000) << 8)  |        \
-        (((data) & 0x000000ff00000000) >> 8)  |        \
-        (((data) & 0x0000ff0000000000) >> 24) |        \
-        (((data) & 0x00ff000000000000) >> 40) |        \
-        (((data) & 0xff00000000000000) >> 56))
+#define DATA_LE32(data)                                \
+       ((((data) & 0x000000ff) << 24) |        \
+        (((data) & 0x0000ff00) << 8)  |        \
+        (((data) & 0x00ff0000) >> 8)  |        \
+        (((data) & 0xff000000) >> 24))
 #else
-#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
+#define DATA_LE32(data) ((data) & 0xffffffff)
 #endif
 
+#define DEFINE_IMAGE_LE64(sym, data)                           \
+       sym##_lo32 = DATA_LE32((data) & 0xffffffff);            \
+       sym##_hi32 = DATA_LE32((data) >> 32)
+
 #ifdef CONFIG_CPU_BIG_ENDIAN
-#define __HEAD_FLAG_BE 1
+#define __HEAD_FLAG_BE         1
 #else
-#define __HEAD_FLAG_BE 0
+#define __HEAD_FLAG_BE         0
 #endif
 
-#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+#define __HEAD_FLAG_PAGE_SIZE  ((PAGE_SHIFT - 10) / 2)
+
+#define __HEAD_FLAG_PHYS_BASE  1
 
-#define __HEAD_FLAGS   ((__HEAD_FLAG_BE << 0) |        \
-                        (__HEAD_FLAG_PAGE_SIZE << 1))
+#define __HEAD_FLAGS           ((__HEAD_FLAG_BE << 0) |        \
+                                (__HEAD_FLAG_PAGE_SIZE << 1) | \
+                                (__HEAD_FLAG_PHYS_BASE << 3))
 
 /*
  * These will output as part of the Image header, which should be little-endian
  * endian swapped in head.S, all are done here for consistency.
  */
 #define HEAD_SYMBOLS                                           \
-       _kernel_size_le         = DATA_LE64(_end - _text);      \
-       _kernel_offset_le       = DATA_LE64(TEXT_OFFSET);       \
-       _kernel_flags_le        = DATA_LE64(__HEAD_FLAGS);
+       DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text);       \
+       DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);      \
+       DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
 
 #ifdef CONFIG_EFI
 
+/*
+ * Prevent the symbol aliases below from being emitted into the kallsyms
+ * table, by forcing them to be absolute symbols (which are conveniently
+ * ignored by scripts/kallsyms) rather than section relative symbols.
+ * The distinction is only relevant for partial linking, and only for symbols
+ * that are defined within a section declaration (which is not the case for
+ * the definitions below) so the resulting values will be identical.
+ */
+#define KALLSYMS_HIDE(sym)     ABSOLUTE(sym)
+
 /*
  * The EFI stub has its own symbol namespace prefixed by __efistub_, to
  * isolate it from the kernel proper. The following symbols are legally
  * linked at. The routines below are all implemented in assembler in a
  * position independent manner
  */
-__efistub_memcmp               = __pi_memcmp;
-__efistub_memchr               = __pi_memchr;
-__efistub_memcpy               = __pi_memcpy;
-__efistub_memmove              = __pi_memmove;
-__efistub_memset               = __pi_memset;
-__efistub_strlen               = __pi_strlen;
-__efistub_strcmp               = __pi_strcmp;
-__efistub_strncmp              = __pi_strncmp;
-__efistub___flush_dcache_area  = __pi___flush_dcache_area;
+__efistub_memcmp               = KALLSYMS_HIDE(__pi_memcmp);
+__efistub_memchr               = KALLSYMS_HIDE(__pi_memchr);
+__efistub_memcpy               = KALLSYMS_HIDE(__pi_memcpy);
+__efistub_memmove              = KALLSYMS_HIDE(__pi_memmove);
+__efistub_memset               = KALLSYMS_HIDE(__pi_memset);
+__efistub_strlen               = KALLSYMS_HIDE(__pi_strlen);
+__efistub_strcmp               = KALLSYMS_HIDE(__pi_strcmp);
+__efistub_strncmp              = KALLSYMS_HIDE(__pi_strncmp);
+__efistub___flush_dcache_area  = KALLSYMS_HIDE(__pi___flush_dcache_area);
 
 #ifdef CONFIG_KASAN
-__efistub___memcpy             = __pi_memcpy;
-__efistub___memmove            = __pi_memmove;
-__efistub___memset             = __pi_memset;
+__efistub___memcpy             = KALLSYMS_HIDE(__pi_memcpy);
+__efistub___memmove            = KALLSYMS_HIDE(__pi_memmove);
+__efistub___memset             = KALLSYMS_HIDE(__pi_memset);
 #endif
 
-__efistub__text                        = _text;
-__efistub__end                 = _end;
-__efistub__edata               = _edata;
+__efistub__text                        = KALLSYMS_HIDE(_text);
+__efistub__end                 = KALLSYMS_HIDE(_end);
+__efistub__edata               = KALLSYMS_HIDE(_edata);
 
 #endif
 
index 9f17ec071ee0e8a8b1380133cf319a9ad1c80de5..2386b26c071274d4d563a4fdc5e864aedda37204 100644 (file)
@@ -30,6 +30,9 @@
 
 unsigned long irq_err_count;
 
+/* irq stack only needs to be 16 byte aligned - not IRQ_STACK_SIZE aligned. */
+DEFINE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack) __aligned(16);
+
 int arch_show_interrupts(struct seq_file *p, int prec)
 {
        show_ipi_list(p, prec);
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
new file mode 100644 (file)
index 0000000..5829839
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/crc32.h>
+#include <linux/init.h>
+#include <linux/libfdt.h>
+#include <linux/mm_types.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include <asm/fixmap.h>
+#include <asm/kernel-pgtable.h>
+#include <asm/memory.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+
+u64 __read_mostly module_alloc_base;
+u16 __initdata memstart_offset_seed;
+
+static __init u64 get_kaslr_seed(void *fdt)
+{
+       int node, len;
+       u64 *prop;
+       u64 ret;
+
+       node = fdt_path_offset(fdt, "/chosen");
+       if (node < 0)
+               return 0;
+
+       prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
+       if (!prop || len != sizeof(u64))
+               return 0;
+
+       ret = fdt64_to_cpu(*prop);
+       *prop = 0;
+       return ret;
+}
+
+static __init const u8 *get_cmdline(void *fdt)
+{
+       static __initconst const u8 default_cmdline[] = CONFIG_CMDLINE;
+
+       if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
+               int node;
+               const u8 *prop;
+
+               node = fdt_path_offset(fdt, "/chosen");
+               if (node < 0)
+                       goto out;
+
+               prop = fdt_getprop(fdt, node, "bootargs", NULL);
+               if (!prop)
+                       goto out;
+               return prop;
+       }
+out:
+       return default_cmdline;
+}
+
+extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size,
+                                      pgprot_t prot);
+
+/*
+ * This routine will be executed with the kernel mapped at its default virtual
+ * address, and if it returns successfully, the kernel will be remapped, and
+ * start_kernel() will be executed from a randomized virtual offset. The
+ * relocation will result in all absolute references (e.g., static variables
+ * containing function pointers) to be reinitialized, and zero-initialized
+ * .bss variables will be reset to 0.
+ */
+u64 __init kaslr_early_init(u64 dt_phys)
+{
+       void *fdt;
+       u64 seed, offset, mask, module_range;
+       const u8 *cmdline, *str;
+       int size;
+
+       /*
+        * Set a reasonable default for module_alloc_base in case
+        * we end up running with module randomization disabled.
+        */
+       module_alloc_base = (u64)_etext - MODULES_VSIZE;
+
+       /*
+        * Try to map the FDT early. If this fails, we simply bail,
+        * and proceed with KASLR disabled. We will make another
+        * attempt at mapping the FDT in setup_machine()
+        */
+       early_fixmap_init();
+       fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
+       if (!fdt)
+               return 0;
+
+       /*
+        * Retrieve (and wipe) the seed from the FDT
+        */
+       seed = get_kaslr_seed(fdt);
+       if (!seed)
+               return 0;
+
+       /*
+        * Check if 'nokaslr' appears on the command line, and
+        * return 0 if that is the case.
+        */
+       cmdline = get_cmdline(fdt);
+       str = strstr(cmdline, "nokaslr");
+       if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
+               return 0;
+
+       /*
+        * OK, so we are proceeding with KASLR enabled. Calculate a suitable
+        * kernel image offset from the seed. Let's place the kernel in the
+        * lower half of the VMALLOC area (VA_BITS - 2).
+        * Even if we could randomize at page granularity for 16k and 64k pages,
+        * let's always round to 2 MB so we don't interfere with the ability to
+        * map using contiguous PTEs
+        */
+       mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1);
+       offset = seed & mask;
+
+       /* use the top 16 bits to randomize the linear region */
+       memstart_offset_seed = seed >> 48;
+
+       /*
+        * The kernel Image should not extend across a 1GB/32MB/512MB alignment
+        * boundary (for 4KB/16KB/64KB granule kernels, respectively). If this
+        * happens, increase the KASLR offset by the size of the kernel image.
+        */
+       if ((((u64)_text + offset) >> SWAPPER_TABLE_SHIFT) !=
+           (((u64)_end + offset) >> SWAPPER_TABLE_SHIFT))
+               offset = (offset + (u64)(_end - _text)) & mask;
+
+       if (IS_ENABLED(CONFIG_KASAN))
+               /*
+                * KASAN does not expect the module region to intersect the
+                * vmalloc region, since shadow memory is allocated for each
+                * module at load time, whereas the vmalloc region is shadowed
+                * by KASAN zero pages. So keep modules out of the vmalloc
+                * region if KASAN is enabled.
+                */
+               return offset;
+
+       if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {
+               /*
+                * Randomize the module region independently from the core
+                * kernel. This prevents modules from leaking any information
+                * about the address of the kernel itself, but results in
+                * branches between modules and the core kernel that are
+                * resolved via PLTs. (Branches between modules will be
+                * resolved normally.)
+                */
+               module_range = VMALLOC_END - VMALLOC_START - MODULES_VSIZE;
+               module_alloc_base = VMALLOC_START;
+       } else {
+               /*
+                * Randomize the module region by setting module_alloc_base to
+                * a PAGE_SIZE multiple in the range [_etext - MODULES_VSIZE,
+                * _stext) . This guarantees that the resulting region still
+                * covers [_stext, _etext], and that all relative branches can
+                * be resolved without veneers.
+                */
+               module_range = MODULES_VSIZE - (u64)(_etext - _stext);
+               module_alloc_base = (u64)_etext + offset - MODULES_VSIZE;
+       }
+
+       /* use the lower 21 bits to randomize the base of the module region */
+       module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
+       module_alloc_base &= PAGE_MASK;
+
+       return offset;
+}
diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c
new file mode 100644 (file)
index 0000000..1ce90d8
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014-2016 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sort.h>
+
+struct plt_entry {
+       /*
+        * A program that conforms to the AArch64 Procedure Call Standard
+        * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or
+        * IP1 (x17) may be inserted at any branch instruction that is
+        * exposed to a relocation that supports long branches. Since that
+        * is exactly what we are dealing with here, we are free to use x16
+        * as a scratch register in the PLT veneers.
+        */
+       __le32  mov0;   /* movn x16, #0x....                    */
+       __le32  mov1;   /* movk x16, #0x...., lsl #16           */
+       __le32  mov2;   /* movk x16, #0x...., lsl #32           */
+       __le32  br;     /* br   x16                             */
+};
+
+u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
+                         Elf64_Sym *sym)
+{
+       struct plt_entry *plt = (struct plt_entry *)mod->arch.plt->sh_addr;
+       int i = mod->arch.plt_num_entries;
+       u64 val = sym->st_value + rela->r_addend;
+
+       /*
+        * We only emit PLT entries against undefined (SHN_UNDEF) symbols,
+        * which are listed in the ELF symtab section, but without a type
+        * or a size.
+        * So, similar to how the module loader uses the Elf64_Sym::st_value
+        * field to store the resolved addresses of undefined symbols, let's
+        * borrow the Elf64_Sym::st_size field (whose value is never used by
+        * the module loader, even for symbols that are defined) to record
+        * the address of a symbol's associated PLT entry as we emit it for a
+        * zero addend relocation (which is the only kind we have to deal with
+        * in practice). This allows us to find duplicates without having to
+        * go through the table every time.
+        */
+       if (rela->r_addend == 0 && sym->st_size != 0) {
+               BUG_ON(sym->st_size < (u64)plt || sym->st_size >= (u64)&plt[i]);
+               return sym->st_size;
+       }
+
+       mod->arch.plt_num_entries++;
+       BUG_ON(mod->arch.plt_num_entries > mod->arch.plt_max_entries);
+
+       /*
+        * MOVK/MOVN/MOVZ opcode:
+        * +--------+------------+--------+-----------+-------------+---------+
+        * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] |
+        * +--------+------------+--------+-----------+-------------+---------+
+        *
+        * Rd     := 0x10 (x16)
+        * hw     := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32)
+        * opc    := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ)
+        * sf     := 1 (64-bit variant)
+        */
+       plt[i] = (struct plt_entry){
+               cpu_to_le32(0x92800010 | (((~val      ) & 0xffff)) << 5),
+               cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5),
+               cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5),
+               cpu_to_le32(0xd61f0200)
+       };
+
+       if (rela->r_addend == 0)
+               sym->st_size = (u64)&plt[i];
+
+       return (u64)&plt[i];
+}
+
+#define cmp_3way(a,b)  ((a) < (b) ? -1 : (a) > (b))
+
+static int cmp_rela(const void *a, const void *b)
+{
+       const Elf64_Rela *x = a, *y = b;
+       int i;
+
+       /* sort by type, symbol index and addend */
+       i = cmp_3way(ELF64_R_TYPE(x->r_info), ELF64_R_TYPE(y->r_info));
+       if (i == 0)
+               i = cmp_3way(ELF64_R_SYM(x->r_info), ELF64_R_SYM(y->r_info));
+       if (i == 0)
+               i = cmp_3way(x->r_addend, y->r_addend);
+       return i;
+}
+
+static bool duplicate_rel(const Elf64_Rela *rela, int num)
+{
+       /*
+        * Entries are sorted by type, symbol index and addend. That means
+        * that, if a duplicate entry exists, it must be in the preceding
+        * slot.
+        */
+       return num > 0 && cmp_rela(rela + num, rela + num - 1) == 0;
+}
+
+static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num)
+{
+       unsigned int ret = 0;
+       Elf64_Sym *s;
+       int i;
+
+       for (i = 0; i < num; i++) {
+               switch (ELF64_R_TYPE(rela[i].r_info)) {
+               case R_AARCH64_JUMP26:
+               case R_AARCH64_CALL26:
+                       /*
+                        * We only have to consider branch targets that resolve
+                        * to undefined symbols. This is not simply a heuristic,
+                        * it is a fundamental limitation, since the PLT itself
+                        * is part of the module, and needs to be within 128 MB
+                        * as well, so modules can never grow beyond that limit.
+                        */
+                       s = syms + ELF64_R_SYM(rela[i].r_info);
+                       if (s->st_shndx != SHN_UNDEF)
+                               break;
+
+                       /*
+                        * Jump relocations with non-zero addends against
+                        * undefined symbols are supported by the ELF spec, but
+                        * do not occur in practice (e.g., 'jump n bytes past
+                        * the entry point of undefined function symbol f').
+                        * So we need to support them, but there is no need to
+                        * take them into consideration when trying to optimize
+                        * this code. So let's only check for duplicates when
+                        * the addend is zero: this allows us to record the PLT
+                        * entry address in the symbol table itself, rather than
+                        * having to search the list for duplicates each time we
+                        * emit one.
+                        */
+                       if (rela[i].r_addend != 0 || !duplicate_rel(rela, i))
+                               ret++;
+                       break;
+               }
+       }
+       return ret;
+}
+
+int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
+                             char *secstrings, struct module *mod)
+{
+       unsigned long plt_max_entries = 0;
+       Elf64_Sym *syms = NULL;
+       int i;
+
+       /*
+        * Find the empty .plt section so we can expand it to store the PLT
+        * entries. Record the symtab address as well.
+        */
+       for (i = 0; i < ehdr->e_shnum; i++) {
+               if (strcmp(".plt", secstrings + sechdrs[i].sh_name) == 0)
+                       mod->arch.plt = sechdrs + i;
+               else if (sechdrs[i].sh_type == SHT_SYMTAB)
+                       syms = (Elf64_Sym *)sechdrs[i].sh_addr;
+       }
+
+       if (!mod->arch.plt) {
+               pr_err("%s: module PLT section missing\n", mod->name);
+               return -ENOEXEC;
+       }
+       if (!syms) {
+               pr_err("%s: module symtab section missing\n", mod->name);
+               return -ENOEXEC;
+       }
+
+       for (i = 0; i < ehdr->e_shnum; i++) {
+               Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset;
+               int numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela);
+               Elf64_Shdr *dstsec = sechdrs + sechdrs[i].sh_info;
+
+               if (sechdrs[i].sh_type != SHT_RELA)
+                       continue;
+
+               /* ignore relocations that operate on non-exec sections */
+               if (!(dstsec->sh_flags & SHF_EXECINSTR))
+                       continue;
+
+               /* sort by type, symbol index and addend */
+               sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL);
+
+               plt_max_entries += count_plts(syms, rels, numrels);
+       }
+
+       mod->arch.plt->sh_type = SHT_NOBITS;
+       mod->arch.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+       mod->arch.plt->sh_addralign = L1_CACHE_BYTES;
+       mod->arch.plt->sh_size = plt_max_entries * sizeof(struct plt_entry);
+       mod->arch.plt_num_entries = 0;
+       mod->arch.plt_max_entries = plt_max_entries;
+       return 0;
+}
index f4bc779e62e887547b7a17b7672487f0851e1479..7f316982ce00186262728518f3a03f7871fb7dd7 100644 (file)
 #include <asm/insn.h>
 #include <asm/sections.h>
 
-#define        AARCH64_INSN_IMM_MOVNZ          AARCH64_INSN_IMM_MAX
-#define        AARCH64_INSN_IMM_MOVK           AARCH64_INSN_IMM_16
-
 void *module_alloc(unsigned long size)
 {
        void *p;
 
-       p = __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR, MODULES_END,
+       p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
+                               module_alloc_base + MODULES_VSIZE,
                                GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
                                NUMA_NO_NODE, __builtin_return_address(0));
 
+       if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
+           !IS_ENABLED(CONFIG_KASAN))
+               /*
+                * KASAN can only deal with module allocations being served
+                * from the reserved module region, since the remainder of
+                * the vmalloc region is already backed by zero shadow pages,
+                * and punching holes into it is non-trivial. Since the module
+                * region is not randomized when KASAN is enabled, it is even
+                * less likely that the module region gets exhausted, so we
+                * can simply omit this fallback in that case.
+                */
+               p = __vmalloc_node_range(size, MODULE_ALIGN, VMALLOC_START,
+                               VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
+                               NUMA_NO_NODE, __builtin_return_address(0));
+
        if (p && (kasan_module_alloc(p, size) < 0)) {
                vfree(p);
                return NULL;
@@ -75,15 +88,18 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val)
 
 static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
 {
-       u64 imm_mask = (1 << len) - 1;
        s64 sval = do_reloc(op, place, val);
 
        switch (len) {
        case 16:
                *(s16 *)place = sval;
+               if (sval < S16_MIN || sval > U16_MAX)
+                       return -ERANGE;
                break;
        case 32:
                *(s32 *)place = sval;
+               if (sval < S32_MIN || sval > U32_MAX)
+                       return -ERANGE;
                break;
        case 64:
                *(s64 *)place = sval;
@@ -92,34 +108,23 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
                pr_err("Invalid length (%d) for data relocation\n", len);
                return 0;
        }
-
-       /*
-        * Extract the upper value bits (including the sign bit) and
-        * shift them to bit 0.
-        */
-       sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
-
-       /*
-        * Overflow has occurred if the value is not representable in
-        * len bits (i.e the bottom len bits are not sign-extended and
-        * the top bits are not all zero).
-        */
-       if ((u64)(sval + 1) > 2)
-               return -ERANGE;
-
        return 0;
 }
 
+enum aarch64_insn_movw_imm_type {
+       AARCH64_INSN_IMM_MOVNZ,
+       AARCH64_INSN_IMM_MOVKZ,
+};
+
 static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
-                          int lsb, enum aarch64_insn_imm_type imm_type)
+                          int lsb, enum aarch64_insn_movw_imm_type imm_type)
 {
-       u64 imm, limit = 0;
+       u64 imm;
        s64 sval;
        u32 insn = le32_to_cpu(*(u32 *)place);
 
        sval = do_reloc(op, place, val);
-       sval >>= lsb;
-       imm = sval & 0xffff;
+       imm = sval >> lsb;
 
        if (imm_type == AARCH64_INSN_IMM_MOVNZ) {
                /*
@@ -128,7 +133,7 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
                 * immediate is less than zero.
                 */
                insn &= ~(3 << 29);
-               if ((s64)imm >= 0) {
+               if (sval >= 0) {
                        /* >=0: Set the instruction to MOVZ (opcode 10b). */
                        insn |= 2 << 29;
                } else {
@@ -140,29 +145,13 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
                         */
                        imm = ~imm;
                }
-               imm_type = AARCH64_INSN_IMM_MOVK;
        }
 
        /* Update the instruction with the new encoding. */
-       insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+       insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm);
        *(u32 *)place = cpu_to_le32(insn);
 
-       /* Shift out the immediate field. */
-       sval >>= 16;
-
-       /*
-        * For unsigned immediates, the overflow check is straightforward.
-        * For signed immediates, the sign bit is actually the bit past the
-        * most significant bit of the field.
-        * The AARCH64_INSN_IMM_16 immediate type is unsigned.
-        */
-       if (imm_type != AARCH64_INSN_IMM_16) {
-               sval++;
-               limit++;
-       }
-
-       /* Check the upper bits depending on the sign of the immediate. */
-       if ((u64)sval > limit)
+       if (imm > U16_MAX)
                return -ERANGE;
 
        return 0;
@@ -267,25 +256,25 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        overflow_check = false;
                case R_AARCH64_MOVW_UABS_G0:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G1_NC:
                        overflow_check = false;
                case R_AARCH64_MOVW_UABS_G1:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G2_NC:
                        overflow_check = false;
                case R_AARCH64_MOVW_UABS_G2:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_UABS_G3:
                        /* We're using the top bits so we can't overflow. */
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48,
-                                             AARCH64_INSN_IMM_16);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_SABS_G0:
                        ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
@@ -302,7 +291,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_MOVW_PREL_G0_NC:
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
-                                             AARCH64_INSN_IMM_MOVK);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_PREL_G0:
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
@@ -311,7 +300,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_MOVW_PREL_G1_NC:
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
-                                             AARCH64_INSN_IMM_MOVK);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_PREL_G1:
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
@@ -320,7 +309,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_MOVW_PREL_G2_NC:
                        overflow_check = false;
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
-                                             AARCH64_INSN_IMM_MOVK);
+                                             AARCH64_INSN_IMM_MOVKZ);
                        break;
                case R_AARCH64_MOVW_PREL_G2:
                        ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
@@ -388,6 +377,13 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_CALL26:
                        ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26,
                                             AARCH64_INSN_IMM_26);
+
+                       if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
+                           ovf == -ERANGE) {
+                               val = module_emit_plt_entry(me, &rel[i], sym);
+                               ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2,
+                                                    26, AARCH64_INSN_IMM_26);
+                       }
                        break;
 
                default:
diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds
new file mode 100644 (file)
index 0000000..8949f6c
--- /dev/null
@@ -0,0 +1,3 @@
+SECTIONS {
+       .plt (NOLOAD) : { BYTE(0) }
+}
index 3aa74830cc69af0053efb77c72e9c26ae3bd6c02..ff4665462a025d4ec2655ca30d49732a63194e53 100644 (file)
@@ -164,8 +164,11 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
        frame.fp = regs->regs[29];
        frame.sp = regs->sp;
        frame.pc = regs->pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = current->curr_ret_stack;
+#endif
 
-       walk_stackframe(&frame, callchain_trace, entry);
+       walk_stackframe(current, &frame, callchain_trace, entry);
 }
 
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
index 62068ded1e906fbadb505e29a61cc67b064148d9..6f3fb46170bfdc9a22230e60776a92b629b3a5f2 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/notifier.h>
 #include <trace/events/power.h>
 
+#include <asm/alternative.h>
 #include <asm/compat.h>
 #include <asm/cacheflush.h>
 #include <asm/fpsimd.h>
@@ -346,6 +347,9 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
        } else {
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->pstate = PSR_MODE_EL1h;
+               if (IS_ENABLED(CONFIG_ARM64_UAO) &&
+                   cpus_have_cap(ARM64_HAS_UAO))
+                       childregs->pstate |= PSR_UAO_BIT;
                p->thread.cpu_context.x19 = stack_start;
                p->thread.cpu_context.x20 = stk_sz;
        }
@@ -374,6 +378,17 @@ static void tls_thread_switch(struct task_struct *next)
        : : "r" (tpidr), "r" (tpidrro));
 }
 
+/* Restore the UAO state depending on next's addr_limit */
+static void uao_thread_switch(struct task_struct *next)
+{
+       if (IS_ENABLED(CONFIG_ARM64_UAO)) {
+               if (task_thread_info(next)->addr_limit == KERNEL_DS)
+                       asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
+               else
+                       asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO));
+       }
+}
+
 /*
  * Thread switching.
  */
@@ -386,6 +401,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
        tls_thread_switch(next);
        hw_breakpoint_thread_switch(next);
        contextidr_thread_switch(next);
+       uao_thread_switch(next);
 
        /*
         * Complete any pending TLB or cache maintenance on this CPU in case
@@ -410,11 +426,14 @@ unsigned long get_wchan(struct task_struct *p)
        frame.fp = thread_saved_fp(p);
        frame.sp = thread_saved_sp(p);
        frame.pc = thread_saved_pc(p);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = p->curr_ret_stack;
+#endif
        stack_page = (unsigned long)task_stack_page(p);
        do {
                if (frame.sp < stack_page ||
                    frame.sp >= stack_page + THREAD_SIZE ||
-                   unwind_frame(&frame))
+                   unwind_frame(p, &frame))
                        return 0;
                if (!in_sched_functions(frame.pc))
                        return frame.pc;
index 6c4fd2810ecb35b3e648db18923d21f19a50f422..1718706fde83604f78d81d850bf8827705338f1a 100644 (file)
@@ -43,8 +43,11 @@ void *return_address(unsigned int level)
        frame.fp = (unsigned long)__builtin_frame_address(0);
        frame.sp = current_stack_pointer;
        frame.pc = (unsigned long)return_address; /* dummy */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = current->curr_ret_stack;
+#endif
 
-       walk_stackframe(&frame, save_return_addr, &data);
+       walk_stackframe(current, &frame, save_return_addr, &data);
 
        if (!data.level)
                return data.addr;
index 8119479147db147c33800f76aa0d07c6072e8559..42371f69def3a3afc68a7f1a28d0e819e83c7837 100644 (file)
@@ -62,6 +62,7 @@
 #include <asm/memblock.h>
 #include <asm/efi.h>
 #include <asm/xen/hypervisor.h>
+#include <asm/mmu_context.h>
 
 phys_addr_t __fdt_pointer __initdata;
 
@@ -313,6 +314,12 @@ void __init setup_arch(char **cmdline_p)
         */
        local_async_enable();
 
+       /*
+        * TTBR0 is only used for the identity mapping at this stage. Make it
+        * point to zero page to avoid speculatively fetching new entries.
+        */
+       cpu_uninstall_idmap();
+
        efi_init();
        arm64_memblock_init();
 
@@ -381,3 +388,32 @@ static int __init topology_init(void)
        return 0;
 }
 subsys_initcall(topology_init);
+
+/*
+ * Dump out kernel offset information on panic.
+ */
+static int dump_kernel_offset(struct notifier_block *self, unsigned long v,
+                             void *p)
+{
+       u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR;
+
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) {
+               pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n",
+                        kaslr_offset, KIMAGE_VADDR);
+       } else {
+               pr_emerg("Kernel Offset: disabled\n");
+       }
+       return 0;
+}
+
+static struct notifier_block kernel_offset_notifier = {
+       .notifier_call = dump_kernel_offset
+};
+
+static int __init register_kernel_offset_dumper(void)
+{
+       atomic_notifier_chain_register(&panic_notifier_list,
+                                      &kernel_offset_notifier);
+       return 0;
+}
+__initcall(register_kernel_offset_dumper);
index f586f7c875e29295b6094efd4967e26cb6d01a99..e33fe33876ab3804f2c6dcd6c5458e576596ef24 100644 (file)
@@ -173,6 +173,9 @@ ENTRY(cpu_resume)
        /* load physical address of identity map page table in x1 */
        adrp    x1, idmap_pg_dir
        mov     sp, x2
+       /* save thread_info */
+       and     x2, x2, #~(THREAD_SIZE - 1)
+       msr     sp_el0, x2
        /*
         * cpu_do_resume expects x0 to contain context physical address
         * pointer and x1 to contain physical address of 1:1 page tables
index b1adc51b2c2e7682212554ba8276b5e7c25fbff5..24cb4f800033bc2b9d5ad49144f915ca4506e6dc 100644 (file)
@@ -70,6 +70,7 @@ enum ipi_msg_type {
        IPI_CPU_STOP,
        IPI_TIMER,
        IPI_IRQ_WORK,
+       IPI_WAKEUP
 };
 
 /*
@@ -149,9 +150,7 @@ asmlinkage void secondary_start_kernel(void)
         * TTBR0 is only used for the identity mapping at this stage. Make it
         * point to zero page to avoid speculatively fetching new entries.
         */
-       cpu_set_reserved_ttbr0();
-       local_flush_tlb_all();
-       cpu_set_default_tcr_t0sz();
+       cpu_uninstall_idmap();
 
        preempt_disable();
        trace_hardirqs_off();
@@ -445,6 +444,17 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
        /* map the logical cpu id to cpu MPIDR */
        cpu_logical_map(cpu_count) = hwid;
 
+       /*
+        * Set-up the ACPI parking protocol cpu entries
+        * while initializing the cpu_logical_map to
+        * avoid parsing MADT entries multiple times for
+        * nothing (ie a valid cpu_logical_map entry should
+        * contain a valid parking protocol data set to
+        * initialize the cpu if the parking protocol is
+        * the only available enable method).
+        */
+       acpi_set_mailbox_entry(cpu_count, processor);
+
        cpu_count++;
 }
 
@@ -627,6 +637,7 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
        S(IPI_CPU_STOP, "CPU stop interrupts"),
        S(IPI_TIMER, "Timer broadcast interrupts"),
        S(IPI_IRQ_WORK, "IRQ work interrupts"),
+       S(IPI_WAKEUP, "CPU wake-up interrupts"),
 };
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
@@ -670,6 +681,13 @@ void arch_send_call_function_single_ipi(int cpu)
        smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC);
 }
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+       smp_cross_call(mask, IPI_WAKEUP);
+}
+#endif
+
 #ifdef CONFIG_IRQ_WORK
 void arch_irq_work_raise(void)
 {
@@ -747,6 +765,14 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
                break;
 #endif
 
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+       case IPI_WAKEUP:
+               WARN_ONCE(!acpi_parking_protocol_valid(cpu),
+                         "CPU%u: Wake-up IPI outside the ACPI parking protocol\n",
+                         cpu);
+               break;
+#endif
+
        default:
                pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
                break;
index ccb6078ed9f20fb55132deb48504df3a3134a784..cfd46c227c8cbd7c57c9b88c1d6189404f0bdcfa 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/ftrace.h>
 #include <linux/sched.h>
 #include <linux/stacktrace.h>
 
+#include <asm/irq.h>
 #include <asm/stacktrace.h>
 
 /*
  *     ldp     x29, x30, [sp]
  *     add     sp, sp, #0x10
  */
-int notrace unwind_frame(struct stackframe *frame)
+int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 {
        unsigned long high, low;
        unsigned long fp = frame->fp;
+       unsigned long irq_stack_ptr;
+
+       /*
+        * Switching between stacks is valid when tracing current and in
+        * non-preemptible context.
+        */
+       if (tsk == current && !preemptible())
+               irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+       else
+               irq_stack_ptr = 0;
 
        low  = frame->sp;
-       high = ALIGN(low, THREAD_SIZE);
+       /* irq stacks are not THREAD_SIZE aligned */
+       if (on_irq_stack(frame->sp, raw_smp_processor_id()))
+               high = irq_stack_ptr;
+       else
+               high = ALIGN(low, THREAD_SIZE) - 0x20;
 
-       if (fp < low || fp > high - 0x18 || fp & 0xf)
+       if (fp < low || fp > high || fp & 0xf)
                return -EINVAL;
 
        frame->sp = fp + 0x10;
        frame->fp = *(unsigned long *)(fp);
        frame->pc = *(unsigned long *)(fp + 8);
 
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       if (tsk && tsk->ret_stack &&
+                       (frame->pc == (unsigned long)return_to_handler)) {
+               /*
+                * This is a case where function graph tracer has
+                * modified a return address (LR) in a stack frame
+                * to hook a function return.
+                * So replace it to an original value.
+                */
+               frame->pc = tsk->ret_stack[frame->graph--].ret;
+       }
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+       /*
+        * Check whether we are going to walk through from interrupt stack
+        * to task stack.
+        * If we reach the end of the stack - and its an interrupt stack,
+        * unpack the dummy frame to find the original elr.
+        *
+        * Check the frame->fp we read from the bottom of the irq_stack,
+        * and the original task stack pointer are both in current->stack.
+        */
+       if (frame->sp == irq_stack_ptr) {
+               struct pt_regs *irq_args;
+               unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
+
+               if (object_is_on_stack((void *)orig_sp) &&
+                  object_is_on_stack((void *)frame->fp)) {
+                       frame->sp = orig_sp;
+
+                       /* orig_sp is the saved pt_regs, find the elr */
+                       irq_args = (struct pt_regs *)orig_sp;
+                       frame->pc = irq_args->pc;
+               } else {
+                       /*
+                        * This frame has a non-standard format, and we
+                        * didn't fix it, because the data looked wrong.
+                        * Refuse to output this frame.
+                        */
+                       return -EINVAL;
+               }
+       }
+
        return 0;
 }
 
-void notrace walk_stackframe(struct stackframe *frame,
+void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
                     int (*fn)(struct stackframe *, void *), void *data)
 {
        while (1) {
@@ -61,7 +120,7 @@ void notrace walk_stackframe(struct stackframe *frame,
 
                if (fn(frame, data))
                        break;
-               ret = unwind_frame(frame);
+               ret = unwind_frame(tsk, frame);
                if (ret < 0)
                        break;
        }
@@ -112,8 +171,11 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
                frame.sp = current_stack_pointer;
                frame.pc = (unsigned long)save_stack_trace_tsk;
        }
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = tsk->curr_ret_stack;
+#endif
 
-       walk_stackframe(&frame, save_trace, &data);
+       walk_stackframe(tsk, &frame, save_trace, &data);
        if (trace->nr_entries < trace->max_entries)
                trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
index 1095aa483a1c28e5387b23895c14d7a1746268a3..66055392f445ef47a7fb3749ca6024df1ea185c9 100644 (file)
@@ -60,7 +60,6 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
  */
 int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
 {
-       struct mm_struct *mm = current->active_mm;
        int ret;
        unsigned long flags;
 
@@ -87,22 +86,11 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
        ret = __cpu_suspend_enter(arg, fn);
        if (ret == 0) {
                /*
-                * We are resuming from reset with TTBR0_EL1 set to the
-                * idmap to enable the MMU; set the TTBR0 to the reserved
-                * page tables to prevent speculative TLB allocations, flush
-                * the local tlb and set the default tcr_el1.t0sz so that
-                * the TTBR0 address space set-up is properly restored.
-                * If the current active_mm != &init_mm we entered cpu_suspend
-                * with mappings in TTBR0 that must be restored, so we switch
-                * them back to complete the address space configuration
-                * restoration before returning.
+                * We are resuming from reset with the idmap active in TTBR0_EL1.
+                * We must uninstall the idmap and restore the expected MMU
+                * state before we can possibly return to userspace.
                 */
-               cpu_set_reserved_ttbr0();
-               local_flush_tlb_all();
-               cpu_set_default_tcr_t0sz();
-
-               if (mm != &init_mm)
-                       cpu_switch_mm(mm->pgd, mm);
+               cpu_uninstall_idmap();
 
                /*
                 * Restore per-cpu offset before any kernel
index 13339b6ffc1a07839103fca328f1eccd6d185c12..59779699a1a40ef3a1940aa0d878c16164ea5398 100644 (file)
@@ -52,8 +52,11 @@ unsigned long profile_pc(struct pt_regs *regs)
        frame.fp = regs->regs[29];
        frame.sp = regs->sp;
        frame.pc = regs->pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = -1; /* no task info */
+#endif
        do {
-               int ret = unwind_frame(&frame);
+               int ret = unwind_frame(NULL, &frame);
                if (ret < 0)
                        return 0;
        } while (in_lock_functions(frame.pc));
index e9b9b53643936a121e8c73db99373d7e7cab9b48..c5392081b49ba4ac4f48d9a0782442ac888ed222 100644 (file)
@@ -146,17 +146,24 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 {
        struct stackframe frame;
+       unsigned long irq_stack_ptr;
+       int skip;
+
+       /*
+        * Switching between stacks is valid when tracing current and in
+        * non-preemptible context.
+        */
+       if (tsk == current && !preemptible())
+               irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+       else
+               irq_stack_ptr = 0;
 
        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
        if (!tsk)
                tsk = current;
 
-       if (regs) {
-               frame.fp = regs->regs[29];
-               frame.sp = regs->sp;
-               frame.pc = regs->pc;
-       } else if (tsk == current) {
+       if (tsk == current) {
                frame.fp = (unsigned long)__builtin_frame_address(0);
                frame.sp = current_stack_pointer;
                frame.pc = (unsigned long)dump_backtrace;
@@ -168,21 +175,49 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
                frame.sp = thread_saved_sp(tsk);
                frame.pc = thread_saved_pc(tsk);
        }
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       frame.graph = tsk->curr_ret_stack;
+#endif
 
-       pr_emerg("Call trace:\n");
+       skip = !!regs;
+       printk("Call trace:\n");
        while (1) {
                unsigned long where = frame.pc;
                unsigned long stack;
                int ret;
 
-               dump_backtrace_entry(where);
-               ret = unwind_frame(&frame);
+               /* skip until specified stack frame */
+               if (!skip) {
+                       dump_backtrace_entry(where);
+               } else if (frame.fp == regs->regs[29]) {
+                       skip = 0;
+                       /*
+                        * Mostly, this is the case where this function is
+                        * called in panic/abort. As exception handler's
+                        * stack frame does not contain the corresponding pc
+                        * at which an exception has taken place, use regs->pc
+                        * instead.
+                        */
+                       dump_backtrace_entry(regs->pc);
+               }
+               ret = unwind_frame(tsk, &frame);
                if (ret < 0)
                        break;
                stack = frame.sp;
-               if (in_exception_text(where))
+               if (in_exception_text(where)) {
+                       /*
+                        * If we switched to the irq_stack before calling this
+                        * exception handler, then the pt_regs will be on the
+                        * task stack. The easiest way to tell is if the large
+                        * pt_regs would overlap with the end of the irq_stack.
+                        */
+                       if (stack < irq_stack_ptr &&
+                           (stack + sizeof(struct pt_regs)) > irq_stack_ptr)
+                               stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
+
                        dump_mem("", "Exception stack", stack,
                                 stack + sizeof(struct pt_regs), false);
+               }
        }
 }
 
@@ -456,22 +491,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
 
 void __pte_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pte %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pte %016lx.\n", file, line, val);
 }
 
 void __pmd_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pmd %016lx.\n", file, line, val);
 }
 
 void __pud_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pud %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pud %016lx.\n", file, line, val);
 }
 
 void __pgd_error(const char *file, int line, unsigned long val)
 {
-       pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
+       pr_err("%s:%d: bad pgd %016lx.\n", file, line, val);
 }
 
 /* GENERIC_BUG traps */
index 71426a78db123d13e98acf8659d65155ff342a06..e3f6cd740ea346bd887f01e2b46a558d8075d966 100644 (file)
@@ -87,15 +87,16 @@ SECTIONS
                EXIT_CALL
                *(.discard)
                *(.discard.*)
+               *(.interp .dynamic)
        }
 
-       . = PAGE_OFFSET + TEXT_OFFSET;
+       . = KIMAGE_VADDR + TEXT_OFFSET;
 
        .head.text : {
                _text = .;
                HEAD_TEXT
        }
-       ALIGN_DEBUG_RO
+       ALIGN_DEBUG_RO_MIN(PAGE_SIZE)
        .text : {                       /* Real text segment            */
                _stext = .;             /* Text and read-only data      */
                        __exception_text_start = .;
@@ -113,14 +114,12 @@ SECTIONS
                *(.got)                 /* Global offset table          */
        }
 
-       ALIGN_DEBUG_RO
        RO_DATA(PAGE_SIZE)
        EXCEPTION_TABLE(8)
        NOTES
-       ALIGN_DEBUG_RO
-       _etext = .;                     /* End of text and rodata section */
 
        ALIGN_DEBUG_RO_MIN(PAGE_SIZE)
+       _etext = .;                     /* End of text and rodata section */
        __init_begin = .;
 
        INIT_TEXT_SECTION(8)
@@ -128,7 +127,6 @@ SECTIONS
                ARM_EXIT_KEEP(EXIT_TEXT)
        }
 
-       ALIGN_DEBUG_RO_MIN(16)
        .init.data : {
                INIT_DATA
                INIT_SETUP(16)
@@ -143,9 +141,6 @@ SECTIONS
 
        PERCPU_SECTION(L1_CACHE_BYTES)
 
-       . = ALIGN(PAGE_SIZE);
-       __init_end = .;
-
        . = ALIGN(4);
        .altinstructions : {
                __alt_instructions = .;
@@ -155,8 +150,25 @@ SECTIONS
        .altinstr_replacement : {
                *(.altinstr_replacement)
        }
+       .rela : ALIGN(8) {
+               __reloc_start = .;
+               *(.rela .rela*)
+               __reloc_end = .;
+       }
+       .dynsym : ALIGN(8) {
+               __dynsym_start = .;
+               *(.dynsym)
+       }
+       .dynstr : {
+               *(.dynstr)
+       }
+       .hash : {
+               *(.hash)
+       }
 
        . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+
        _data = .;
        _sdata = .;
        RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
@@ -190,4 +202,4 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
 /*
  * If padding is applied before .head.text, virt<->phys conversions will fail.
  */
-ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned")
+ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned")
index 86c289832272d71ba48786414bb6e4ecb9b9cb14..309e3479dc2c48fb47ca28a44b81e9d06b73e7bf 100644 (file)
@@ -923,7 +923,7 @@ __hyp_panic_str:
        .align  2
 
 /*
- * u64 kvm_call_hyp(void *hypfn, ...);
+ * u64 __kvm_call_hyp(void *hypfn, ...);
  *
  * This is not really a variadic function in the classic C-way and care must
  * be taken when calling this to ensure parameters are passed in registers
@@ -940,10 +940,10 @@ __hyp_panic_str:
  * used to implement __hyp_get_vectors in the same way as in
  * arch/arm64/kernel/hyp_stub.S.
  */
-ENTRY(kvm_call_hyp)
+ENTRY(__kvm_call_hyp)
        hvc     #0
        ret
-ENDPROC(kvm_call_hyp)
+ENDPROC(__kvm_call_hyp)
 
 .macro invalid_vector  label, target
        .align  2
index 1a811ecf71da8a8032a1e8cda8cf686f8fc71189..c86b7909ef312009028c46ba83b375b544d9ae84 100644 (file)
@@ -4,15 +4,16 @@ lib-y         := bitops.o clear_user.o delay.o copy_from_user.o       \
                   memcmp.o strcmp.o strncmp.o strlen.o strnlen.o       \
                   strchr.o strrchr.o
 
-# Tell the compiler to treat all general purpose registers as
-# callee-saved, which allows for efficient runtime patching of the bl
-# instruction in the caller with an atomic instruction when supported by
-# the CPU. Result and argument registers are handled correctly, based on
-# the function prototype.
+# Tell the compiler to treat all general purpose registers (with the
+# exception of the IP registers, which are already handled by the caller
+# in case of a PLT) as callee-saved, which allows for efficient runtime
+# patching of the bl instruction in the caller with an atomic instruction
+# when supported by the CPU. Result and argument registers are handled
+# correctly, based on the function prototype.
 lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o
 CFLAGS_atomic_ll_sc.o  := -fcall-used-x0 -ffixed-x1 -ffixed-x2         \
                   -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6          \
                   -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9           \
                   -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12   \
                   -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15   \
-                  -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18
+                  -fcall-saved-x18
index a9723c71c52b20adf4e2efe69b2e43163cb2c878..5d1cad3ce6d601aa474ae9c9b8ef4c76a785912e 100644 (file)
  * Alignment fixed up by hardware.
  */
 ENTRY(__clear_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        mov     x2, x1                  // save the size for fixup return
        subs    x1, x1, #8
        b.mi    2f
 1:
-USER(9f, str   xzr, [x0], #8   )
+uao_user_alternative 9f, str, sttr, xzr, x0, 8
        subs    x1, x1, #8
        b.pl    1b
 2:     adds    x1, x1, #4
        b.mi    3f
-USER(9f, str   wzr, [x0], #4   )
+uao_user_alternative 9f, str, sttr, wzr, x0, 4
        sub     x1, x1, #4
 3:     adds    x1, x1, #2
        b.mi    4f
-USER(9f, strh  wzr, [x0], #2   )
+uao_user_alternative 9f, strh, sttrh, wzr, x0, 2
        sub     x1, x1, #2
 4:     adds    x1, x1, #1
        b.mi    5f
-USER(9f, strb  wzr, [x0]       )
+uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
 5:     mov     x0, #0
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        ret
 ENDPROC(__clear_user)
index 4699cd74f87e4af7bf69da8ce48a88a7f4f69b74..17e8306dca294ecf37fc27355956eb6bcfc5d92e 100644 (file)
@@ -34,7 +34,7 @@
  */
 
        .macro ldrb1 ptr, regB, val
-       USER(9998f, ldrb  \ptr, [\regB], \val)
+       uao_user_alternative 9998f, ldrb, ldtrb, \ptr, \regB, \val
        .endm
 
        .macro strb1 ptr, regB, val
@@ -42,7 +42,7 @@
        .endm
 
        .macro ldrh1 ptr, regB, val
-       USER(9998f, ldrh  \ptr, [\regB], \val)
+       uao_user_alternative 9998f, ldrh, ldtrh, \ptr, \regB, \val
        .endm
 
        .macro strh1 ptr, regB, val
@@ -50,7 +50,7 @@
        .endm
 
        .macro ldr1 ptr, regB, val
-       USER(9998f, ldr \ptr, [\regB], \val)
+       uao_user_alternative 9998f, ldr, ldtr, \ptr, \regB, \val
        .endm
 
        .macro str1 ptr, regB, val
@@ -58,7 +58,7 @@
        .endm
 
        .macro ldp1 ptr, regB, regC, val
-       USER(9998f, ldp \ptr, \regB, [\regC], \val)
+       uao_ldp 9998f, \ptr, \regB, \regC, \val
        .endm
 
        .macro stp1 ptr, regB, regC, val
 
 end    .req    x5
 ENTRY(__copy_from_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        add     end, x0, x2
 #include "copy_template.S"
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        mov     x0, #0                          // Nothing to copy
        ret
index 81c8fc93c100b7be7da17ebf96b1edeeb806671f..f7292dd08c840f27d39874fe7cc08aa89bdfb66d 100644 (file)
  *     x0 - bytes not copied
  */
        .macro ldrb1 ptr, regB, val
-       USER(9998f, ldrb  \ptr, [\regB], \val)
+       uao_user_alternative 9998f, ldrb, ldtrb, \ptr, \regB, \val
        .endm
 
        .macro strb1 ptr, regB, val
-       USER(9998f, strb \ptr, [\regB], \val)
+       uao_user_alternative 9998f, strb, sttrb, \ptr, \regB, \val
        .endm
 
        .macro ldrh1 ptr, regB, val
-       USER(9998f, ldrh  \ptr, [\regB], \val)
+       uao_user_alternative 9998f, ldrh, ldtrh, \ptr, \regB, \val
        .endm
 
        .macro strh1 ptr, regB, val
-       USER(9998f, strh \ptr, [\regB], \val)
+       uao_user_alternative 9998f, strh, sttrh, \ptr, \regB, \val
        .endm
 
        .macro ldr1 ptr, regB, val
-       USER(9998f, ldr \ptr, [\regB], \val)
+       uao_user_alternative 9998f, ldr, ldtr, \ptr, \regB, \val
        .endm
 
        .macro str1 ptr, regB, val
-       USER(9998f, str \ptr, [\regB], \val)
+       uao_user_alternative 9998f, str, sttr, \ptr, \regB, \val
        .endm
 
        .macro ldp1 ptr, regB, regC, val
-       USER(9998f, ldp \ptr, \regB, [\regC], \val)
+       uao_ldp 9998f, \ptr, \regB, \regC, \val
        .endm
 
        .macro stp1 ptr, regB, regC, val
-       USER(9998f, stp \ptr, \regB, [\regC], \val)
+       uao_stp 9998f, \ptr, \regB, \regC, \val
        .endm
 
 end    .req    x5
 ENTRY(__copy_in_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        add     end, x0, x2
 #include "copy_template.S"
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        mov     x0, #0
        ret
index 512b9a7b980e98bbed9a699107e936e4b1913dca..4c1e700840b6ced5a0b2f868bfb4f37dddc8abc0 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/const.h>
 #include <asm/assembler.h>
 #include <asm/page.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative.h>
 
 /*
  * Copy a page from src to dest (both are page aligned)
  *     x1 - src
  */
 ENTRY(copy_page)
-       /* Assume cache line size is 64 bytes. */
-       prfm    pldl1strm, [x1, #64]
-1:     ldp     x2, x3, [x1]
+alternative_if_not ARM64_HAS_NO_HW_PREFETCH
+       nop
+       nop
+alternative_else
+       # Prefetch two cache lines ahead.
+       prfm    pldl1strm, [x1, #128]
+       prfm    pldl1strm, [x1, #256]
+alternative_endif
+
+       ldp     x2, x3, [x1]
        ldp     x4, x5, [x1, #16]
        ldp     x6, x7, [x1, #32]
        ldp     x8, x9, [x1, #48]
-       add     x1, x1, #64
-       prfm    pldl1strm, [x1, #64]
+       ldp     x10, x11, [x1, #64]
+       ldp     x12, x13, [x1, #80]
+       ldp     x14, x15, [x1, #96]
+       ldp     x16, x17, [x1, #112]
+
+       mov     x18, #(PAGE_SIZE - 128)
+       add     x1, x1, #128
+1:
+       subs    x18, x18, #128
+
+alternative_if_not ARM64_HAS_NO_HW_PREFETCH
+       nop
+alternative_else
+       prfm    pldl1strm, [x1, #384]
+alternative_endif
+
        stnp    x2, x3, [x0]
+       ldp     x2, x3, [x1]
        stnp    x4, x5, [x0, #16]
+       ldp     x4, x5, [x1, #16]
        stnp    x6, x7, [x0, #32]
+       ldp     x6, x7, [x1, #32]
        stnp    x8, x9, [x0, #48]
-       add     x0, x0, #64
-       tst     x1, #(PAGE_SIZE - 1)
-       b.ne    1b
+       ldp     x8, x9, [x1, #48]
+       stnp    x10, x11, [x0, #64]
+       ldp     x10, x11, [x1, #64]
+       stnp    x12, x13, [x0, #80]
+       ldp     x12, x13, [x1, #80]
+       stnp    x14, x15, [x0, #96]
+       ldp     x14, x15, [x1, #96]
+       stnp    x16, x17, [x0, #112]
+       ldp     x16, x17, [x1, #112]
+
+       add     x0, x0, #128
+       add     x1, x1, #128
+
+       b.gt    1b
+
+       stnp    x2, x3, [x0]
+       stnp    x4, x5, [x0, #16]
+       stnp    x6, x7, [x0, #32]
+       stnp    x8, x9, [x0, #48]
+       stnp    x10, x11, [x0, #64]
+       stnp    x12, x13, [x0, #80]
+       stnp    x14, x15, [x0, #96]
+       stnp    x16, x17, [x0, #112]
+
        ret
 ENDPROC(copy_page)
index 7512bbbc07ac39dbe8c963745281f25c2d60efa4..21faae60f9887ecbbfccb7ba1fb918839d47a291 100644 (file)
@@ -37,7 +37,7 @@
        .endm
 
        .macro strb1 ptr, regB, val
-       USER(9998f, strb \ptr, [\regB], \val)
+       uao_user_alternative 9998f, strb, sttrb, \ptr, \regB, \val
        .endm
 
        .macro ldrh1 ptr, regB, val
@@ -45,7 +45,7 @@
        .endm
 
        .macro strh1 ptr, regB, val
-       USER(9998f, strh \ptr, [\regB], \val)
+       uao_user_alternative 9998f, strh, sttrh, \ptr, \regB, \val
        .endm
 
        .macro ldr1 ptr, regB, val
@@ -53,7 +53,7 @@
        .endm
 
        .macro str1 ptr, regB, val
-       USER(9998f, str \ptr, [\regB], \val)
+       uao_user_alternative 9998f, str, sttr, \ptr, \regB, \val
        .endm
 
        .macro ldp1 ptr, regB, regC, val
        .endm
 
        .macro stp1 ptr, regB, regC, val
-       USER(9998f, stp \ptr, \regB, [\regC], \val)
+       uao_stp 9998f, \ptr, \regB, \regC, \val
        .endm
 
 end    .req    x5
 ENTRY(__copy_to_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        add     end, x0, x2
 #include "copy_template.S"
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \
+ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
            CONFIG_ARM64_PAN)
        mov     x0, #0
        ret
index cfa44a6adc0ad5ec29f78228196b7e834b65df40..6df07069a0253013e254dbb1206debaa939a3526 100644 (file)
@@ -81,25 +81,31 @@ ENDPROC(__flush_cache_user_range)
 /*
  *     __flush_dcache_area(kaddr, size)
  *
- *     Ensure that the data held in the page kaddr is written back to the
- *     page in question.
+ *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     are cleaned and invalidated to the PoC.
  *
  *     - kaddr   - kernel address
  *     - size    - size in question
  */
 ENTRY(__flush_dcache_area)
-       dcache_line_size x2, x3
-       add     x1, x0, x1
-       sub     x3, x2, #1
-       bic     x0, x0, x3
-1:     dc      civac, x0                       // clean & invalidate D line / unified line
-       add     x0, x0, x2
-       cmp     x0, x1
-       b.lo    1b
-       dsb     sy
+       dcache_by_line_op civac, sy, x0, x1, x2, x3
        ret
 ENDPIPROC(__flush_dcache_area)
 
+/*
+ *     __clean_dcache_area_pou(kaddr, size)
+ *
+ *     Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ *     are cleaned to the PoU.
+ *
+ *     - kaddr   - kernel address
+ *     - size    - size in question
+ */
+ENTRY(__clean_dcache_area_pou)
+       dcache_by_line_op cvau, ish, x0, x1, x2, x3
+       ret
+ENDPROC(__clean_dcache_area_pou)
+
 /*
  *     __inval_cache_range(start, end)
  *     - start   - start address of region
index e87f53ff5f583aeb47b3ec3187d229df380b2c50..7275628ba59f663489f6f9403d46ca8a5050c6f7 100644 (file)
@@ -187,7 +187,7 @@ switch_mm_fastpath:
 
 static int asids_init(void)
 {
-       int fld = cpuid_feature_extract_field(read_cpuid(ID_AA64MMFR0_EL1), 4);
+       int fld = cpuid_feature_extract_field(read_cpuid(SYS_ID_AA64MMFR0_EL1), 4);
 
        switch (fld) {
        default:
index 13bbc3be6f5ab31a24d6d0a03b8f368ea6923ed8..22e4cb4d6f538baa43f7071ad1729dec01216d23 100644 (file)
@@ -24,8 +24,9 @@
 
 void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
 {
+       struct page *page = virt_to_page(kto);
        copy_page(kto, kfrom);
-       __flush_dcache_area(kto, PAGE_SIZE);
+       flush_dcache_page(page);
 }
 EXPORT_SYMBOL_GPL(__cpu_copy_user_page);
 
index b51a5e0d935f0ab885906a188c277196bd968f61..2b05653e81567b4fcbe541aa30d38f2d5e19238d 100644 (file)
@@ -33,7 +33,7 @@
 static struct gen_pool *atomic_pool;
 
 #define DEFAULT_DMA_COHERENT_POOL_SIZE  SZ_256K
-static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
+static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
 
 static int __init early_coherent_pool(char *p)
 {
index 5a22a119a74c87b4b5b54e114701b3c6eed233e6..6be918478f855021fee88a50fefe1b6642252c81 100644 (file)
@@ -35,7 +35,9 @@ struct addr_marker {
 };
 
 enum address_markers_idx {
-       VMALLOC_START_NR = 0,
+       MODULES_START_NR = 0,
+       MODULES_END_NR,
+       VMALLOC_START_NR,
        VMALLOC_END_NR,
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
        VMEMMAP_START_NR,
@@ -45,12 +47,12 @@ enum address_markers_idx {
        FIXADDR_END_NR,
        PCI_START_NR,
        PCI_END_NR,
-       MODULES_START_NR,
-       MODUELS_END_NR,
        KERNEL_SPACE_NR,
 };
 
 static struct addr_marker address_markers[] = {
+       { MODULES_VADDR,        "Modules start" },
+       { MODULES_END,          "Modules end" },
        { VMALLOC_START,        "vmalloc() Area" },
        { VMALLOC_END,          "vmalloc() End" },
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
@@ -61,9 +63,7 @@ static struct addr_marker address_markers[] = {
        { FIXADDR_TOP,          "Fixmap end" },
        { PCI_IO_START,         "PCI I/O start" },
        { PCI_IO_END,           "PCI I/O end" },
-       { MODULES_VADDR,        "Modules start" },
-       { MODULES_END,          "Modules end" },
-       { PAGE_OFFSET,          "Kernel Mapping" },
+       { PAGE_OFFSET,          "Linear Mapping" },
        { -1,                   NULL },
 };
 
@@ -90,6 +90,11 @@ struct prot_bits {
 
 static const struct prot_bits pte_bits[] = {
        {
+               .mask   = PTE_VALID,
+               .val    = PTE_VALID,
+               .set    = " ",
+               .clear  = "F",
+       }, {
                .mask   = PTE_USER,
                .val    = PTE_USER,
                .set    = "USR",
index 79444279ba8c674316e34cfe0861c42021fa92f3..81acd4706878f85d8821f0ff924bff05adc31c97 100644 (file)
@@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs)
 
        fixup = search_exception_tables(instruction_pointer(regs));
        if (fixup)
-               regs->pc = fixup->fixup;
+               regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;
 
        return fixup != NULL;
 }
index 92ddac1e8ca2f35b8f24028514bb761aed3591a4..44e56de23f792d1fed3b127791b83415df118085 100644 (file)
@@ -192,6 +192,14 @@ out:
        return fault;
 }
 
+static inline int permission_fault(unsigned int esr)
+{
+       unsigned int ec       = (esr & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT;
+       unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
+
+       return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM);
+}
+
 static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
                                   struct pt_regs *regs)
 {
@@ -225,12 +233,13 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
                mm_flags |= FAULT_FLAG_WRITE;
        }
 
-       /*
-        * PAN bit set implies the fault happened in kernel space, but not
-        * in the arch's user access functions.
-        */
-       if (IS_ENABLED(CONFIG_ARM64_PAN) && (regs->pstate & PSR_PAN_BIT))
-               goto no_context;
+       if (permission_fault(esr) && (addr < USER_DS)) {
+               if (get_fs() == KERNEL_DS)
+                       die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
+
+               if (!search_exception_tables(regs->pc))
+                       die("Accessing user space memory outside uaccess.h routines", regs, esr);
+       }
 
        /*
         * As per x86, we may deadlock here. However, since the kernel only
@@ -561,3 +570,16 @@ void cpu_enable_pan(void *__unused)
        config_sctlr_el1(SCTLR_EL1_SPAN, 0);
 }
 #endif /* CONFIG_ARM64_PAN */
+
+#ifdef CONFIG_ARM64_UAO
+/*
+ * Kernel threads have fs=KERNEL_DS by default, and don't need to call
+ * set_fs(), devtmpfs in particular relies on this behaviour.
+ * We need to enable the feature at runtime (instead of adding it to
+ * PSR_MODE_EL1h) as the feature may not be implemented by the cpu.
+ */
+void cpu_enable_uao(void *__unused)
+{
+       asm(SET_PSTATE_UAO(1));
+}
+#endif /* CONFIG_ARM64_UAO */
index c26b804015e80c46e1380d0a1af7f8f439c55405..46649d6e6c5a5608caa84015d3ce4f09d3d47eee 100644 (file)
@@ -34,19 +34,24 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
                __flush_icache_all();
 }
 
+static void sync_icache_aliases(void *kaddr, unsigned long len)
+{
+       unsigned long addr = (unsigned long)kaddr;
+
+       if (icache_is_aliasing()) {
+               __clean_dcache_area_pou(kaddr, len);
+               __flush_icache_all();
+       } else {
+               flush_icache_range(addr, addr + len);
+       }
+}
+
 static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                                unsigned long uaddr, void *kaddr,
                                unsigned long len)
 {
-       if (vma->vm_flags & VM_EXEC) {
-               unsigned long addr = (unsigned long)kaddr;
-               if (icache_is_aliasing()) {
-                       __flush_dcache_area(kaddr, len);
-                       __flush_icache_all();
-               } else {
-                       flush_icache_range(addr, addr + len);
-               }
-       }
+       if (vma->vm_flags & VM_EXEC)
+               sync_icache_aliases(kaddr, len);
 }
 
 /*
@@ -74,13 +79,11 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
        if (!page_mapping(page))
                return;
 
-       if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
-               __flush_dcache_area(page_address(page),
-                               PAGE_SIZE << compound_order(page));
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+               sync_icache_aliases(page_address(page),
+                                   PAGE_SIZE << compound_order(page));
+       else if (icache_is_aivivt())
                __flush_icache_all();
-       } else if (icache_is_aivivt()) {
-               __flush_icache_all();
-       }
 }
 
 /*
index 383b03ff38f850a0b0a000ee4e6450fd6649c7db..da30529bb1f65c9e3d5408b2e28ab31bc2283211 100644 (file)
@@ -41,15 +41,273 @@ int pud_huge(pud_t pud)
 #endif
 }
 
+static int find_num_contig(struct mm_struct *mm, unsigned long addr,
+                          pte_t *ptep, pte_t pte, size_t *pgsize)
+{
+       pgd_t *pgd = pgd_offset(mm, addr);
+       pud_t *pud;
+       pmd_t *pmd;
+
+       *pgsize = PAGE_SIZE;
+       if (!pte_cont(pte))
+               return 1;
+       if (!pgd_present(*pgd)) {
+               VM_BUG_ON(!pgd_present(*pgd));
+               return 1;
+       }
+       pud = pud_offset(pgd, addr);
+       if (!pud_present(*pud)) {
+               VM_BUG_ON(!pud_present(*pud));
+               return 1;
+       }
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd)) {
+               VM_BUG_ON(!pmd_present(*pmd));
+               return 1;
+       }
+       if ((pte_t *)pmd == ptep) {
+               *pgsize = PMD_SIZE;
+               return CONT_PMDS;
+       }
+       return CONT_PTES;
+}
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+                           pte_t *ptep, pte_t pte)
+{
+       size_t pgsize;
+       int i;
+       int ncontig = find_num_contig(mm, addr, ptep, pte, &pgsize);
+       unsigned long pfn;
+       pgprot_t hugeprot;
+
+       if (ncontig == 1) {
+               set_pte_at(mm, addr, ptep, pte);
+               return;
+       }
+
+       pfn = pte_pfn(pte);
+       hugeprot = __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte));
+       for (i = 0; i < ncontig; i++) {
+               pr_debug("%s: set pte %p to 0x%llx\n", __func__, ptep,
+                        pte_val(pfn_pte(pfn, hugeprot)));
+               set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot));
+               ptep++;
+               pfn += pgsize >> PAGE_SHIFT;
+               addr += pgsize;
+       }
+}
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+                     unsigned long addr, unsigned long sz)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pte_t *pte = NULL;
+
+       pr_debug("%s: addr:0x%lx sz:0x%lx\n", __func__, addr, sz);
+       pgd = pgd_offset(mm, addr);
+       pud = pud_alloc(mm, pgd, addr);
+       if (!pud)
+               return NULL;
+
+       if (sz == PUD_SIZE) {
+               pte = (pte_t *)pud;
+       } else if (sz == (PAGE_SIZE * CONT_PTES)) {
+               pmd_t *pmd = pmd_alloc(mm, pud, addr);
+
+               WARN_ON(addr & (sz - 1));
+               /*
+                * Note that if this code were ever ported to the
+                * 32-bit arm platform then it will cause trouble in
+                * the case where CONFIG_HIGHPTE is set, since there
+                * will be no pte_unmap() to correspond with this
+                * pte_alloc_map().
+                */
+               pte = pte_alloc_map(mm, NULL, pmd, addr);
+       } else if (sz == PMD_SIZE) {
+               if (IS_ENABLED(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) &&
+                   pud_none(*pud))
+                       pte = huge_pmd_share(mm, addr, pud);
+               else
+                       pte = (pte_t *)pmd_alloc(mm, pud, addr);
+       } else if (sz == (PMD_SIZE * CONT_PMDS)) {
+               pmd_t *pmd;
+
+               pmd = pmd_alloc(mm, pud, addr);
+               WARN_ON(addr & (sz - 1));
+               return (pte_t *)pmd;
+       }
+
+       pr_debug("%s: addr:0x%lx sz:0x%lx ret pte=%p/0x%llx\n", __func__, addr,
+              sz, pte, pte_val(*pte));
+       return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd = NULL;
+       pte_t *pte = NULL;
+
+       pgd = pgd_offset(mm, addr);
+       pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd);
+       if (!pgd_present(*pgd))
+               return NULL;
+       pud = pud_offset(pgd, addr);
+       if (!pud_present(*pud))
+               return NULL;
+
+       if (pud_huge(*pud))
+               return (pte_t *)pud;
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd))
+               return NULL;
+
+       if (pte_cont(pmd_pte(*pmd))) {
+               pmd = pmd_offset(
+                       pud, (addr & CONT_PMD_MASK));
+               return (pte_t *)pmd;
+       }
+       if (pmd_huge(*pmd))
+               return (pte_t *)pmd;
+       pte = pte_offset_kernel(pmd, addr);
+       if (pte_present(*pte) && pte_cont(*pte)) {
+               pte = pte_offset_kernel(
+                       pmd, (addr & CONT_PTE_MASK));
+               return pte;
+       }
+       return NULL;
+}
+
+pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+                        struct page *page, int writable)
+{
+       size_t pagesize = huge_page_size(hstate_vma(vma));
+
+       if (pagesize == CONT_PTE_SIZE) {
+               entry = pte_mkcont(entry);
+       } else if (pagesize == CONT_PMD_SIZE) {
+               entry = pmd_pte(pmd_mkcont(pte_pmd(entry)));
+       } else if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) {
+               pr_warn("%s: unrecognized huge page size 0x%lx\n",
+                       __func__, pagesize);
+       }
+       return entry;
+}
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+                             unsigned long addr, pte_t *ptep)
+{
+       pte_t pte;
+
+       if (pte_cont(*ptep)) {
+               int ncontig, i;
+               size_t pgsize;
+               pte_t *cpte;
+               bool is_dirty = false;
+
+               cpte = huge_pte_offset(mm, addr);
+               ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize);
+               /* save the 1st pte to return */
+               pte = ptep_get_and_clear(mm, addr, cpte);
+               for (i = 1; i < ncontig; ++i) {
+                       /*
+                        * If HW_AFDBM is enabled, then the HW could
+                        * turn on the dirty bit for any of the page
+                        * in the set, so check them all.
+                        */
+                       ++cpte;
+                       if (pte_dirty(ptep_get_and_clear(mm, addr, cpte)))
+                               is_dirty = true;
+               }
+               if (is_dirty)
+                       return pte_mkdirty(pte);
+               else
+                       return pte;
+       } else {
+               return ptep_get_and_clear(mm, addr, ptep);
+       }
+}
+
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+                              unsigned long addr, pte_t *ptep,
+                              pte_t pte, int dirty)
+{
+       pte_t *cpte;
+
+       if (pte_cont(pte)) {
+               int ncontig, i, changed = 0;
+               size_t pgsize = 0;
+               unsigned long pfn = pte_pfn(pte);
+               /* Select all bits except the pfn */
+               pgprot_t hugeprot =
+                       __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^
+                                pte_val(pte));
+
+               cpte = huge_pte_offset(vma->vm_mm, addr);
+               pfn = pte_pfn(*cpte);
+               ncontig = find_num_contig(vma->vm_mm, addr, cpte,
+                                         *cpte, &pgsize);
+               for (i = 0; i < ncontig; ++i, ++cpte) {
+                       changed = ptep_set_access_flags(vma, addr, cpte,
+                                                       pfn_pte(pfn,
+                                                               hugeprot),
+                                                       dirty);
+                       pfn += pgsize >> PAGE_SHIFT;
+               }
+               return changed;
+       } else {
+               return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+       }
+}
+
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+                            unsigned long addr, pte_t *ptep)
+{
+       if (pte_cont(*ptep)) {
+               int ncontig, i;
+               pte_t *cpte;
+               size_t pgsize = 0;
+
+               cpte = huge_pte_offset(mm, addr);
+               ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize);
+               for (i = 0; i < ncontig; ++i, ++cpte)
+                       ptep_set_wrprotect(mm, addr, cpte);
+       } else {
+               ptep_set_wrprotect(mm, addr, ptep);
+       }
+}
+
+void huge_ptep_clear_flush(struct vm_area_struct *vma,
+                          unsigned long addr, pte_t *ptep)
+{
+       if (pte_cont(*ptep)) {
+               int ncontig, i;
+               pte_t *cpte;
+               size_t pgsize = 0;
+
+               cpte = huge_pte_offset(vma->vm_mm, addr);
+               ncontig = find_num_contig(vma->vm_mm, addr, cpte,
+                                         *cpte, &pgsize);
+               for (i = 0; i < ncontig; ++i, ++cpte)
+                       ptep_clear_flush(vma, addr, cpte);
+       } else {
+               ptep_clear_flush(vma, addr, ptep);
+       }
+}
+
 static __init int setup_hugepagesz(char *opt)
 {
        unsigned long ps = memparse(opt, &opt);
+
        if (ps == PMD_SIZE) {
                hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
        } else if (ps == PUD_SIZE) {
                hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
        } else {
-               pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
+               pr_err("hugepagesz: Unsupported page size %lu K\n", ps >> 10);
                return 0;
        }
        return 1;
index 224238943aff384a4b91fc3fadf1d1ea9b1d748f..2c38be3df4c8940c5872b50ba63c0d0aaf073a69 100644 (file)
 #include <linux/efi.h>
 #include <linux/swiotlb.h>
 
+#include <asm/boot.h>
 #include <asm/fixmap.h>
+#include <asm/kasan.h>
+#include <asm/kernel-pgtable.h>
 #include <asm/memory.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 
 #include "mm.h"
 
-phys_addr_t memstart_addr __read_mostly = 0;
+/*
+ * We need to be able to catch inadvertent references to memstart_addr
+ * that occur (potentially in generic code) before arm64_memblock_init()
+ * executes, which assigns it its actual value. So use a default value
+ * that cannot be mistaken for a real physical address.
+ */
+s64 memstart_addr __read_mostly = -1;
 phys_addr_t arm64_dma_phys_limit __read_mostly;
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -58,8 +67,8 @@ static int __init early_initrd(char *p)
        if (*endp == ',') {
                size = memparse(endp + 1, NULL);
 
-               initrd_start = (unsigned long)__va(start);
-               initrd_end = (unsigned long)__va(start + size);
+               initrd_start = start;
+               initrd_end = start + size;
        }
        return 0;
 }
@@ -71,7 +80,7 @@ early_param("initrd", early_initrd);
  * currently assumes that for memory starting above 4G, 32-bit devices will
  * use a DMA offset.
  */
-static phys_addr_t max_zone_dma_phys(void)
+static phys_addr_t __init max_zone_dma_phys(void)
 {
        phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
        return min(offset + (1ULL << 32), memblock_end_of_DRAM());
@@ -128,11 +137,11 @@ EXPORT_SYMBOL(pfn_valid);
 #endif
 
 #ifndef CONFIG_SPARSEMEM
-static void arm64_memory_present(void)
+static void __init arm64_memory_present(void)
 {
 }
 #else
-static void arm64_memory_present(void)
+static void __init arm64_memory_present(void)
 {
        struct memblock_region *reg;
 
@@ -161,7 +170,57 @@ early_param("mem", early_mem);
 
 void __init arm64_memblock_init(void)
 {
-       memblock_enforce_memory_limit(memory_limit);
+       const s64 linear_region_size = -(s64)PAGE_OFFSET;
+
+       /*
+        * Ensure that the linear region takes up exactly half of the kernel
+        * virtual address space. This way, we can distinguish a linear address
+        * from a kernel/module/vmalloc address by testing a single bit.
+        */
+       BUILD_BUG_ON(linear_region_size != BIT(VA_BITS - 1));
+
+       /*
+        * Select a suitable value for the base of physical memory.
+        */
+       memstart_addr = round_down(memblock_start_of_DRAM(),
+                                  ARM64_MEMSTART_ALIGN);
+
+       /*
+        * Remove the memory that we will not be able to cover with the
+        * linear mapping. Take care not to clip the kernel which may be
+        * high in memory.
+        */
+       memblock_remove(max_t(u64, memstart_addr + linear_region_size, __pa(_end)),
+                       ULLONG_MAX);
+       if (memblock_end_of_DRAM() > linear_region_size)
+               memblock_remove(0, memblock_end_of_DRAM() - linear_region_size);
+
+       /*
+        * Apply the memory limit if it was set. Since the kernel may be loaded
+        * high up in memory, add back the kernel region that must be accessible
+        * via the linear mapping.
+        */
+       if (memory_limit != (phys_addr_t)ULLONG_MAX) {
+               memblock_enforce_memory_limit(memory_limit);
+               memblock_add(__pa(_text), (u64)(_end - _text));
+       }
+
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+               extern u16 memstart_offset_seed;
+               u64 range = linear_region_size -
+                           (memblock_end_of_DRAM() - memblock_start_of_DRAM());
+
+               /*
+                * If the size of the linear region exceeds, by a sufficient
+                * margin, the size of the region that the available physical
+                * memory spans, randomize the linear region as well.
+                */
+               if (memstart_offset_seed > 0 && range >= ARM64_MEMSTART_ALIGN) {
+                       range = range / ARM64_MEMSTART_ALIGN + 1;
+                       memstart_addr -= ARM64_MEMSTART_ALIGN *
+                                        ((range * memstart_offset_seed) >> 16);
+               }
+       }
 
        /*
         * Register the kernel text, kernel data, initrd, and initial
@@ -169,8 +228,13 @@ void __init arm64_memblock_init(void)
         */
        memblock_reserve(__pa(_text), _end - _text);
 #ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
+       if (initrd_start) {
+               memblock_reserve(initrd_start, initrd_end - initrd_start);
+
+               /* the generic initrd code expects virtual addresses */
+               initrd_start = __phys_to_virt(initrd_start);
+               initrd_end = __phys_to_virt(initrd_end);
+       }
 #endif
 
        early_init_fdt_scan_reserved_mem();
@@ -304,35 +368,36 @@ void __init mem_init(void)
 #ifdef CONFIG_KASAN
                  "    kasan   : 0x%16lx - 0x%16lx   (%6ld GB)\n"
 #endif
+                 "    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n"
                  "    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n"
+                 "      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+                 "      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n"
+                 "      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n"
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
                  "    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n"
                  "              0x%16lx - 0x%16lx   (%6ld MB actual)\n"
 #endif
                  "    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n"
                  "    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n"
-                 "    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n"
-                 "    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n"
-                 "      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n"
-                 "      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n"
-                 "      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n",
+                 "    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n",
 #ifdef CONFIG_KASAN
                  MLG(KASAN_SHADOW_START, KASAN_SHADOW_END),
 #endif
+                 MLM(MODULES_VADDR, MODULES_END),
                  MLG(VMALLOC_START, VMALLOC_END),
+                 MLK_ROUNDUP(__init_begin, __init_end),
+                 MLK_ROUNDUP(_text, _etext),
+                 MLK_ROUNDUP(_sdata, _edata),
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
                  MLG(VMEMMAP_START,
                      VMEMMAP_START + VMEMMAP_SIZE),
-                 MLM((unsigned long)virt_to_page(PAGE_OFFSET),
+                 MLM((unsigned long)phys_to_page(memblock_start_of_DRAM()),
                      (unsigned long)virt_to_page(high_memory)),
 #endif
                  MLK(FIXADDR_START, FIXADDR_TOP),
                  MLM(PCI_IO_START, PCI_IO_END),
-                 MLM(MODULES_VADDR, MODULES_END),
-                 MLM(PAGE_OFFSET, (unsigned long)high_memory),
-                 MLK_ROUNDUP(__init_begin, __init_end),
-                 MLK_ROUNDUP(_text, _etext),
-                 MLK_ROUNDUP(_sdata, _edata));
+                 MLM(__phys_to_virt(memblock_start_of_DRAM()),
+                     (unsigned long)high_memory));
 
 #undef MLK
 #undef MLM
@@ -360,9 +425,8 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       fixup_init();
        free_initmem_default(0);
-       free_alternatives_memory();
+       fixup_init();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -383,3 +447,28 @@ static int __init keepinitrd_setup(char *__unused)
 
 __setup("keepinitrd", keepinitrd_setup);
 #endif
+
+/*
+ * Dump out memory limit information on panic.
+ */
+static int dump_mem_limit(struct notifier_block *self, unsigned long v, void *p)
+{
+       if (memory_limit != (phys_addr_t)ULLONG_MAX) {
+               pr_emerg("Memory Limit: %llu MB\n", memory_limit >> 20);
+       } else {
+               pr_emerg("Memory Limit: none\n");
+       }
+       return 0;
+}
+
+static struct notifier_block mem_limit_notifier = {
+       .notifier_call = dump_mem_limit,
+};
+
+static int __init register_mem_limit_dumper(void)
+{
+       atomic_notifier_chain_register(&panic_notifier_list,
+                                      &mem_limit_notifier);
+       return 0;
+}
+__initcall(register_mem_limit_dumper);
index cf038c7d9fa994c7d86e05920ffa8961aecc4ad8..757009daa9ede454abccbcab6b3a0421a355b49c 100644 (file)
 #include <linux/memblock.h>
 #include <linux/start_kernel.h>
 
+#include <asm/mmu_context.h>
+#include <asm/kernel-pgtable.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm/sections.h>
 #include <asm/tlbflush.h>
 
 static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
@@ -32,7 +35,7 @@ static void __init kasan_early_pte_populate(pmd_t *pmd, unsigned long addr,
        if (pmd_none(*pmd))
                pmd_populate_kernel(&init_mm, pmd, kasan_zero_pte);
 
-       pte = pte_offset_kernel(pmd, addr);
+       pte = pte_offset_kimg(pmd, addr);
        do {
                next = addr + PAGE_SIZE;
                set_pte(pte, pfn_pte(virt_to_pfn(kasan_zero_page),
@@ -50,7 +53,7 @@ static void __init kasan_early_pmd_populate(pud_t *pud,
        if (pud_none(*pud))
                pud_populate(&init_mm, pud, kasan_zero_pmd);
 
-       pmd = pmd_offset(pud, addr);
+       pmd = pmd_offset_kimg(pud, addr);
        do {
                next = pmd_addr_end(addr, end);
                kasan_early_pte_populate(pmd, addr, next);
@@ -67,7 +70,7 @@ static void __init kasan_early_pud_populate(pgd_t *pgd,
        if (pgd_none(*pgd))
                pgd_populate(&init_mm, pgd, kasan_zero_pud);
 
-       pud = pud_offset(pgd, addr);
+       pud = pud_offset_kimg(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
                kasan_early_pmd_populate(pud, addr, next);
@@ -96,6 +99,21 @@ asmlinkage void __init kasan_early_init(void)
        kasan_map_early_shadow();
 }
 
+/*
+ * Copy the current shadow region into a new pgdir.
+ */
+void __init kasan_copy_shadow(pgd_t *pgdir)
+{
+       pgd_t *pgd, *pgd_new, *pgd_end;
+
+       pgd = pgd_offset_k(KASAN_SHADOW_START);
+       pgd_end = pgd_offset_k(KASAN_SHADOW_END);
+       pgd_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START);
+       do {
+               set_pgd(pgd_new, *pgd);
+       } while (pgd++, pgd_new++, pgd != pgd_end);
+}
+
 static void __init clear_pgds(unsigned long start,
                        unsigned long end)
 {
@@ -108,18 +126,18 @@ static void __init clear_pgds(unsigned long start,
                set_pgd(pgd_offset_k(start), __pgd(0));
 }
 
-static void __init cpu_set_ttbr1(unsigned long ttbr1)
-{
-       asm(
-       "       msr     ttbr1_el1, %0\n"
-       "       isb"
-       :
-       : "r" (ttbr1));
-}
-
 void __init kasan_init(void)
 {
+       u64 kimg_shadow_start, kimg_shadow_end;
+       u64 mod_shadow_start, mod_shadow_end;
        struct memblock_region *reg;
+       int i;
+
+       kimg_shadow_start = (u64)kasan_mem_to_shadow(_text);
+       kimg_shadow_end = (u64)kasan_mem_to_shadow(_end);
+
+       mod_shadow_start = (u64)kasan_mem_to_shadow((void *)MODULES_VADDR);
+       mod_shadow_end = (u64)kasan_mem_to_shadow((void *)MODULES_END);
 
        /*
         * We are going to perform proper setup of shadow memory.
@@ -129,13 +147,33 @@ void __init kasan_init(void)
         * setup will be finished.
         */
        memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
-       cpu_set_ttbr1(__pa(tmp_pg_dir));
-       flush_tlb_all();
+       dsb(ishst);
+       cpu_replace_ttbr1(tmp_pg_dir);
 
        clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
+       vmemmap_populate(kimg_shadow_start, kimg_shadow_end,
+                        pfn_to_nid(virt_to_pfn(_text)));
+
+       /*
+        * vmemmap_populate() has populated the shadow region that covers the
+        * kernel image with SWAPPER_BLOCK_SIZE mappings, so we have to round
+        * the start and end addresses to SWAPPER_BLOCK_SIZE as well, to prevent
+        * kasan_populate_zero_shadow() from replacing the page table entries
+        * (PMD or PTE) at the edges of the shadow region for the kernel
+        * image.
+        */
+       kimg_shadow_start = round_down(kimg_shadow_start, SWAPPER_BLOCK_SIZE);
+       kimg_shadow_end = round_up(kimg_shadow_end, SWAPPER_BLOCK_SIZE);
+
        kasan_populate_zero_shadow((void *)KASAN_SHADOW_START,
-                       kasan_mem_to_shadow((void *)MODULES_VADDR));
+                                  (void *)mod_shadow_start);
+       kasan_populate_zero_shadow((void *)kimg_shadow_end,
+                                  kasan_mem_to_shadow((void *)PAGE_OFFSET));
+
+       if (kimg_shadow_start > mod_shadow_end)
+               kasan_populate_zero_shadow((void *)mod_shadow_end,
+                                          (void *)kimg_shadow_start);
 
        for_each_memblock(memory, reg) {
                void *start = (void *)__phys_to_virt(reg->base);
@@ -155,9 +193,16 @@ void __init kasan_init(void)
                                pfn_to_nid(virt_to_pfn(start)));
        }
 
+       /*
+        * KAsan may reuse the contents of kasan_zero_pte directly, so we
+        * should make sure that it maps the zero page read-only.
+        */
+       for (i = 0; i < PTRS_PER_PTE; i++)
+               set_pte(&kasan_zero_pte[i],
+                       pfn_pte(virt_to_pfn(kasan_zero_page), PAGE_KERNEL_RO));
+
        memset(kasan_zero_page, 0, PAGE_SIZE);
-       cpu_set_ttbr1(__pa(swapper_pg_dir));
-       flush_tlb_all();
+       cpu_replace_ttbr1(swapper_pg_dir);
 
        /* At this point kasan is fully initialized. Enable error messages */
        init_task.kasan_depth = 0;
index 116ad654dd593d18a07d68fd61875dd2de614222..41421c724fb9eb27a28ede211b0775af97b1fc32 100644 (file)
 #include <linux/slab.h>
 #include <linux/stop_machine.h>
 
+#include <asm/barrier.h>
 #include <asm/cputype.h>
 #include <asm/fixmap.h>
+#include <asm/kasan.h>
 #include <asm/kernel-pgtable.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 
 u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
 
+u64 kimage_voffset __read_mostly;
+EXPORT_SYMBOL(kimage_voffset);
+
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
  * and COW.
  */
-struct page *empty_zero_page;
+unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
 EXPORT_SYMBOL(empty_zero_page);
 
+static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
+static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
+static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
+
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
                              unsigned long size, pgprot_t vma_prot)
 {
@@ -62,16 +71,30 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 }
 EXPORT_SYMBOL(phys_mem_access_prot);
 
-static void __init *early_alloc(unsigned long sz)
+static phys_addr_t __init early_pgtable_alloc(void)
 {
        phys_addr_t phys;
        void *ptr;
 
-       phys = memblock_alloc(sz, sz);
+       phys = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
        BUG_ON(!phys);
-       ptr = __va(phys);
-       memset(ptr, 0, sz);
-       return ptr;
+
+       /*
+        * The FIX_{PGD,PUD,PMD} slots may be in active use, but the FIX_PTE
+        * slot will be free, so we can (ab)use the FIX_PTE slot to initialise
+        * any level of table.
+        */
+       ptr = pte_set_fixmap(phys);
+
+       memset(ptr, 0, PAGE_SIZE);
+
+       /*
+        * Implicit barriers also ensure the zeroed page is visible to the page
+        * table walker
+        */
+       pte_clear_fixmap();
+
+       return phys;
 }
 
 /*
@@ -95,24 +118,30 @@ static void split_pmd(pmd_t *pmd, pte_t *pte)
 static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
                                  unsigned long end, unsigned long pfn,
                                  pgprot_t prot,
-                                 void *(*alloc)(unsigned long size))
+                                 phys_addr_t (*pgtable_alloc)(void))
 {
        pte_t *pte;
 
        if (pmd_none(*pmd) || pmd_sect(*pmd)) {
-               pte = alloc(PTRS_PER_PTE * sizeof(pte_t));
+               phys_addr_t pte_phys;
+               BUG_ON(!pgtable_alloc);
+               pte_phys = pgtable_alloc();
+               pte = pte_set_fixmap(pte_phys);
                if (pmd_sect(*pmd))
                        split_pmd(pmd, pte);
-               __pmd_populate(pmd, __pa(pte), PMD_TYPE_TABLE);
+               __pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE);
                flush_tlb_all();
+               pte_clear_fixmap();
        }
        BUG_ON(pmd_bad(*pmd));
 
-       pte = pte_offset_kernel(pmd, addr);
+       pte = pte_set_fixmap_offset(pmd, addr);
        do {
                set_pte(pte, pfn_pte(pfn, prot));
                pfn++;
        } while (pte++, addr += PAGE_SIZE, addr != end);
+
+       pte_clear_fixmap();
 }
 
 static void split_pud(pud_t *old_pud, pmd_t *pmd)
@@ -127,10 +156,29 @@ static void split_pud(pud_t *old_pud, pmd_t *pmd)
        } while (pmd++, i++, i < PTRS_PER_PMD);
 }
 
-static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
-                                 unsigned long addr, unsigned long end,
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
+{
+
+       /*
+        * If debug_page_alloc is enabled we must map the linear map
+        * using pages. However, other mappings created by
+        * create_mapping_noalloc must use sections in some cases. Allow
+        * sections to be used in those cases, where no pgtable_alloc
+        * function is provided.
+        */
+       return !pgtable_alloc || !debug_pagealloc_enabled();
+}
+#else
+static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
+{
+       return true;
+}
+#endif
+
+static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
                                  phys_addr_t phys, pgprot_t prot,
-                                 void *(*alloc)(unsigned long size))
+                                 phys_addr_t (*pgtable_alloc)(void))
 {
        pmd_t *pmd;
        unsigned long next;
@@ -139,7 +187,10 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
         * Check for initial section mappings in the pgd/pud and remove them.
         */
        if (pud_none(*pud) || pud_sect(*pud)) {
-               pmd = alloc(PTRS_PER_PMD * sizeof(pmd_t));
+               phys_addr_t pmd_phys;
+               BUG_ON(!pgtable_alloc);
+               pmd_phys = pgtable_alloc();
+               pmd = pmd_set_fixmap(pmd_phys);
                if (pud_sect(*pud)) {
                        /*
                         * need to have the 1G of mappings continue to be
@@ -147,19 +198,20 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
                         */
                        split_pud(pud, pmd);
                }
-               pud_populate(mm, pud, pmd);
+               __pud_populate(pud, pmd_phys, PUD_TYPE_TABLE);
                flush_tlb_all();
+               pmd_clear_fixmap();
        }
        BUG_ON(pud_bad(*pud));
 
-       pmd = pmd_offset(pud, addr);
+       pmd = pmd_set_fixmap_offset(pud, addr);
        do {
                next = pmd_addr_end(addr, end);
                /* try section mapping first */
-               if (((addr | next | phys) & ~SECTION_MASK) == 0) {
+               if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
+                     block_mappings_allowed(pgtable_alloc)) {
                        pmd_t old_pmd =*pmd;
-                       set_pmd(pmd, __pmd(phys |
-                                          pgprot_val(mk_sect_prot(prot))));
+                       pmd_set_huge(pmd, phys, prot);
                        /*
                         * Check for previous table entries created during
                         * boot (__create_page_tables) and flush them.
@@ -167,17 +219,19 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
                        if (!pmd_none(old_pmd)) {
                                flush_tlb_all();
                                if (pmd_table(old_pmd)) {
-                                       phys_addr_t table = __pa(pte_offset_map(&old_pmd, 0));
+                                       phys_addr_t table = pmd_page_paddr(old_pmd);
                                        if (!WARN_ON_ONCE(slab_is_available()))
                                                memblock_free(table, PAGE_SIZE);
                                }
                        }
                } else {
                        alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
-                                      prot, alloc);
+                                      prot, pgtable_alloc);
                }
                phys += next - addr;
        } while (pmd++, addr = next, addr != end);
+
+       pmd_clear_fixmap();
 }
 
 static inline bool use_1G_block(unsigned long addr, unsigned long next,
@@ -192,31 +246,32 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next,
        return true;
 }
 
-static void alloc_init_pud(struct mm_struct *mm, pgd_t *pgd,
-                                 unsigned long addr, unsigned long end,
+static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                                  phys_addr_t phys, pgprot_t prot,
-                                 void *(*alloc)(unsigned long size))
+                                 phys_addr_t (*pgtable_alloc)(void))
 {
        pud_t *pud;
        unsigned long next;
 
        if (pgd_none(*pgd)) {
-               pud = alloc(PTRS_PER_PUD * sizeof(pud_t));
-               pgd_populate(mm, pgd, pud);
+               phys_addr_t pud_phys;
+               BUG_ON(!pgtable_alloc);
+               pud_phys = pgtable_alloc();
+               __pgd_populate(pgd, pud_phys, PUD_TYPE_TABLE);
        }
        BUG_ON(pgd_bad(*pgd));
 
-       pud = pud_offset(pgd, addr);
+       pud = pud_set_fixmap_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
 
                /*
                 * For 4K granule only, attempt to put down a 1GB block
                 */
-               if (use_1G_block(addr, next, phys)) {
+               if (use_1G_block(addr, next, phys) &&
+                   block_mappings_allowed(pgtable_alloc)) {
                        pud_t old_pud = *pud;
-                       set_pud(pud, __pud(phys |
-                                          pgprot_val(mk_sect_prot(prot))));
+                       pud_set_huge(pud, phys, prot);
 
                        /*
                         * If we have an old value for a pud, it will
@@ -228,51 +283,74 @@ static void alloc_init_pud(struct mm_struct *mm, pgd_t *pgd,
                        if (!pud_none(old_pud)) {
                                flush_tlb_all();
                                if (pud_table(old_pud)) {
-                                       phys_addr_t table = __pa(pmd_offset(&old_pud, 0));
+                                       phys_addr_t table = pud_page_paddr(old_pud);
                                        if (!WARN_ON_ONCE(slab_is_available()))
                                                memblock_free(table, PAGE_SIZE);
                                }
                        }
                } else {
-                       alloc_init_pmd(mm, pud, addr, next, phys, prot, alloc);
+                       alloc_init_pmd(pud, addr, next, phys, prot,
+                                      pgtable_alloc);
                }
                phys += next - addr;
        } while (pud++, addr = next, addr != end);
+
+       pud_clear_fixmap();
 }
 
 /*
  * Create the page directory entries and any necessary page tables for the
  * mapping specified by 'md'.
  */
-static void  __create_mapping(struct mm_struct *mm, pgd_t *pgd,
-                                   phys_addr_t phys, unsigned long virt,
+static void init_pgd(pgd_t *pgd, phys_addr_t phys, unsigned long virt,
                                    phys_addr_t size, pgprot_t prot,
-                                   void *(*alloc)(unsigned long size))
+                                   phys_addr_t (*pgtable_alloc)(void))
 {
        unsigned long addr, length, end, next;
 
+       /*
+        * If the virtual and physical address don't have the same offset
+        * within a page, we cannot map the region as the caller expects.
+        */
+       if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
+               return;
+
+       phys &= PAGE_MASK;
        addr = virt & PAGE_MASK;
        length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
 
        end = addr + length;
        do {
                next = pgd_addr_end(addr, end);
-               alloc_init_pud(mm, pgd, addr, next, phys, prot, alloc);
+               alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc);
                phys += next - addr;
        } while (pgd++, addr = next, addr != end);
 }
 
-static void *late_alloc(unsigned long size)
+static phys_addr_t late_pgtable_alloc(void)
 {
-       void *ptr;
-
-       BUG_ON(size > PAGE_SIZE);
-       ptr = (void *)__get_free_page(PGALLOC_GFP);
+       void *ptr = (void *)__get_free_page(PGALLOC_GFP);
        BUG_ON(!ptr);
-       return ptr;
+
+       /* Ensure the zeroed page is visible to the page table walker */
+       dsb(ishst);
+       return __pa(ptr);
+}
+
+static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
+                                unsigned long virt, phys_addr_t size,
+                                pgprot_t prot,
+                                phys_addr_t (*alloc)(void))
+{
+       init_pgd(pgd_offset_raw(pgdir, virt), phys, virt, size, prot, alloc);
 }
 
-static void __init create_mapping(phys_addr_t phys, unsigned long virt,
+/*
+ * This function can only be used to modify existing table entries,
+ * without allocating new levels of table. Note that this permits the
+ * creation of new section or page entries.
+ */
+static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
                                  phys_addr_t size, pgprot_t prot)
 {
        if (virt < VMALLOC_START) {
@@ -280,16 +358,16 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
                        &phys, virt);
                return;
        }
-       __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt,
-                        size, prot, early_alloc);
+       __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
+                            NULL);
 }
 
 void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
                               unsigned long virt, phys_addr_t size,
                               pgprot_t prot)
 {
-       __create_mapping(mm, pgd_offset(mm, virt), phys, virt, size, prot,
-                               late_alloc);
+       __create_pgd_mapping(mm->pgd, phys, virt, size, prot,
+                            late_pgtable_alloc);
 }
 
 static void create_mapping_late(phys_addr_t phys, unsigned long virt,
@@ -301,69 +379,57 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
                return;
        }
 
-       return __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK),
-                               phys, virt, size, prot, late_alloc);
+       __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
+                            late_pgtable_alloc);
 }
 
-#ifdef CONFIG_DEBUG_RODATA
-static void __init __map_memblock(phys_addr_t start, phys_addr_t end)
+static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
 {
+       unsigned long kernel_start = __pa(_stext);
+       unsigned long kernel_end = __pa(_etext);
+
        /*
-        * Set up the executable regions using the existing section mappings
-        * for now. This will get more fine grained later once all memory
-        * is mapped
+        * Take care not to create a writable alias for the
+        * read-only text and rodata sections of the kernel image.
         */
-       unsigned long kernel_x_start = round_down(__pa(_stext), SWAPPER_BLOCK_SIZE);
-       unsigned long kernel_x_end = round_up(__pa(__init_end), SWAPPER_BLOCK_SIZE);
-
-       if (end < kernel_x_start) {
-               create_mapping(start, __phys_to_virt(start),
-                       end - start, PAGE_KERNEL);
-       } else if (start >= kernel_x_end) {
-               create_mapping(start, __phys_to_virt(start),
-                       end - start, PAGE_KERNEL);
-       } else {
-               if (start < kernel_x_start)
-                       create_mapping(start, __phys_to_virt(start),
-                               kernel_x_start - start,
-                               PAGE_KERNEL);
-               create_mapping(kernel_x_start,
-                               __phys_to_virt(kernel_x_start),
-                               kernel_x_end - kernel_x_start,
-                               PAGE_KERNEL_EXEC);
-               if (kernel_x_end < end)
-                       create_mapping(kernel_x_end,
-                               __phys_to_virt(kernel_x_end),
-                               end - kernel_x_end,
-                               PAGE_KERNEL);
+
+       /* No overlap with the kernel text */
+       if (end < kernel_start || start >= kernel_end) {
+               __create_pgd_mapping(pgd, start, __phys_to_virt(start),
+                                    end - start, PAGE_KERNEL,
+                                    early_pgtable_alloc);
+               return;
        }
 
+       /*
+        * This block overlaps the kernel text mapping.
+        * Map the portion(s) which don't overlap.
+        */
+       if (start < kernel_start)
+               __create_pgd_mapping(pgd, start,
+                                    __phys_to_virt(start),
+                                    kernel_start - start, PAGE_KERNEL,
+                                    early_pgtable_alloc);
+       if (kernel_end < end)
+               __create_pgd_mapping(pgd, kernel_end,
+                                    __phys_to_virt(kernel_end),
+                                    end - kernel_end, PAGE_KERNEL,
+                                    early_pgtable_alloc);
+
+       /*
+        * Map the linear alias of the [_stext, _etext) interval as
+        * read-only/non-executable. This makes the contents of the
+        * region accessible to subsystems such as hibernate, but
+        * protects it from inadvertent modification or execution.
+        */
+       __create_pgd_mapping(pgd, kernel_start, __phys_to_virt(kernel_start),
+                            kernel_end - kernel_start, PAGE_KERNEL_RO,
+                            early_pgtable_alloc);
 }
-#else
-static void __init __map_memblock(phys_addr_t start, phys_addr_t end)
-{
-       create_mapping(start, __phys_to_virt(start), end - start,
-                       PAGE_KERNEL_EXEC);
-}
-#endif
 
-static void __init map_mem(void)
+static void __init map_mem(pgd_t *pgd)
 {
        struct memblock_region *reg;
-       phys_addr_t limit;
-
-       /*
-        * Temporarily limit the memblock range. We need to do this as
-        * create_mapping requires puds, pmds and ptes to be allocated from
-        * memory addressable from the initial direct kernel mapping.
-        *
-        * The initial direct kernel mapping, located at swapper_pg_dir, gives
-        * us PUD_SIZE (with SECTION maps) or PMD_SIZE (without SECTION maps,
-        * memory starting from PHYS_OFFSET (which must be aligned to 2MB as
-        * per Documentation/arm64/booting.txt).
-        */
-       limit = PHYS_OFFSET + SWAPPER_INIT_MAP_SIZE;
-       memblock_set_current_limit(limit);
 
        /* map all the memory banks */
        for_each_memblock(memory, reg) {
@@ -373,69 +439,87 @@ static void __init map_mem(void)
                if (start >= end)
                        break;
 
-               if (ARM64_SWAPPER_USES_SECTION_MAPS) {
-                       /*
-                        * For the first memory bank align the start address and
-                        * current memblock limit to prevent create_mapping() from
-                        * allocating pte page tables from unmapped memory. With
-                        * the section maps, if the first block doesn't end on section
-                        * size boundary, create_mapping() will try to allocate a pte
-                        * page, which may be returned from an unmapped area.
-                        * When section maps are not used, the pte page table for the
-                        * current limit is already present in swapper_pg_dir.
-                        */
-                       if (start < limit)
-                               start = ALIGN(start, SECTION_SIZE);
-                       if (end < limit) {
-                               limit = end & SECTION_MASK;
-                               memblock_set_current_limit(limit);
-                       }
-               }
-               __map_memblock(start, end);
+               __map_memblock(pgd, start, end);
        }
-
-       /* Limit no longer required. */
-       memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
 }
 
-static void __init fixup_executable(void)
+void mark_rodata_ro(void)
 {
-#ifdef CONFIG_DEBUG_RODATA
-       /* now that we are actually fully mapped, make the start/end more fine grained */
-       if (!IS_ALIGNED((unsigned long)_stext, SWAPPER_BLOCK_SIZE)) {
-               unsigned long aligned_start = round_down(__pa(_stext),
-                                                        SWAPPER_BLOCK_SIZE);
+       if (!IS_ENABLED(CONFIG_DEBUG_RODATA))
+               return;
 
-               create_mapping(aligned_start, __phys_to_virt(aligned_start),
-                               __pa(_stext) - aligned_start,
-                               PAGE_KERNEL);
-       }
+       create_mapping_late(__pa(_stext), (unsigned long)_stext,
+                               (unsigned long)_etext - (unsigned long)_stext,
+                               PAGE_KERNEL_ROX);
+}
 
-       if (!IS_ALIGNED((unsigned long)__init_end, SWAPPER_BLOCK_SIZE)) {
-               unsigned long aligned_end = round_up(__pa(__init_end),
-                                                         SWAPPER_BLOCK_SIZE);
-               create_mapping(__pa(__init_end), (unsigned long)__init_end,
-                               aligned_end - __pa(__init_end),
-                               PAGE_KERNEL);
-       }
-#endif
+void fixup_init(void)
+{
+       /*
+        * Unmap the __init region but leave the VM area in place. This
+        * prevents the region from being reused for kernel modules, which
+        * is not supported by kallsyms.
+        */
+       unmap_kernel_range((u64)__init_begin, (u64)(__init_end - __init_begin));
 }
 
-#ifdef CONFIG_DEBUG_RODATA
-void mark_rodata_ro(void)
+static void __init map_kernel_chunk(pgd_t *pgd, void *va_start, void *va_end,
+                                   pgprot_t prot, struct vm_struct *vma)
 {
-       create_mapping_late(__pa(_stext), (unsigned long)_stext,
-                               (unsigned long)_etext - (unsigned long)_stext,
-                               PAGE_KERNEL_ROX);
+       phys_addr_t pa_start = __pa(va_start);
+       unsigned long size = va_end - va_start;
+
+       BUG_ON(!PAGE_ALIGNED(pa_start));
+       BUG_ON(!PAGE_ALIGNED(size));
+
+       __create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot,
+                            early_pgtable_alloc);
 
+       vma->addr       = va_start;
+       vma->phys_addr  = pa_start;
+       vma->size       = size;
+       vma->flags      = VM_MAP;
+       vma->caller     = __builtin_return_address(0);
+
+       vm_area_add_early(vma);
 }
-#endif
 
-void fixup_init(void)
+/*
+ * Create fine-grained mappings for the kernel.
+ */
+static void __init map_kernel(pgd_t *pgd)
 {
-       create_mapping_late(__pa(__init_begin), (unsigned long)__init_begin,
-                       (unsigned long)__init_end - (unsigned long)__init_begin,
-                       PAGE_KERNEL);
+       static struct vm_struct vmlinux_text, vmlinux_init, vmlinux_data;
+
+       map_kernel_chunk(pgd, _stext, _etext, PAGE_KERNEL_EXEC, &vmlinux_text);
+       map_kernel_chunk(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC,
+                        &vmlinux_init);
+       map_kernel_chunk(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data);
+
+       if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) {
+               /*
+                * The fixmap falls in a separate pgd to the kernel, and doesn't
+                * live in the carveout for the swapper_pg_dir. We can simply
+                * re-use the existing dir for the fixmap.
+                */
+               set_pgd(pgd_offset_raw(pgd, FIXADDR_START),
+                       *pgd_offset_k(FIXADDR_START));
+       } else if (CONFIG_PGTABLE_LEVELS > 3) {
+               /*
+                * The fixmap shares its top level pgd entry with the kernel
+                * mapping. This can really only occur when we are running
+                * with 16k/4 levels, so we can simply reuse the pud level
+                * entry instead.
+                */
+               BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
+               set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START),
+                       __pud(__pa(bm_pmd) | PUD_TYPE_TABLE));
+               pud_clear_fixmap();
+       } else {
+               BUG();
+       }
+
+       kasan_copy_shadow(pgd);
 }
 
 /*
@@ -444,28 +528,35 @@ void fixup_init(void)
  */
 void __init paging_init(void)
 {
-       void *zero_page;
+       phys_addr_t pgd_phys = early_pgtable_alloc();
+       pgd_t *pgd = pgd_set_fixmap(pgd_phys);
 
-       map_mem();
-       fixup_executable();
+       map_kernel(pgd);
+       map_mem(pgd);
 
-       /* allocate the zero page. */
-       zero_page = early_alloc(PAGE_SIZE);
-
-       bootmem_init();
-
-       empty_zero_page = virt_to_page(zero_page);
+       /*
+        * We want to reuse the original swapper_pg_dir so we don't have to
+        * communicate the new address to non-coherent secondaries in
+        * secondary_entry, and so cpu_switch_mm can generate the address with
+        * adrp+add rather than a load from some global variable.
+        *
+        * To do this we need to go via a temporary pgd.
+        */
+       cpu_replace_ttbr1(__va(pgd_phys));
+       memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
+       cpu_replace_ttbr1(swapper_pg_dir);
 
-       /* Ensure the zero page is visible to the page table walker */
-       dsb(ishst);
+       pgd_clear_fixmap();
+       memblock_free(pgd_phys, PAGE_SIZE);
 
        /*
-        * TTBR0 is only used for the identity mapping at this stage. Make it
-        * point to zero page to avoid speculatively fetching new entries.
+        * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
+        * allocated with it.
         */
-       cpu_set_reserved_ttbr0();
-       local_flush_tlb_all();
-       cpu_set_default_tcr_t0sz();
+       memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE,
+                     SWAPPER_DIR_SIZE - PAGE_SIZE);
+
+       bootmem_init();
 }
 
 /*
@@ -552,21 +643,13 @@ void vmemmap_free(unsigned long start, unsigned long end)
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
-static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
-#if CONFIG_PGTABLE_LEVELS > 2
-static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
-#endif
-#if CONFIG_PGTABLE_LEVELS > 3
-static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
-#endif
-
 static inline pud_t * fixmap_pud(unsigned long addr)
 {
        pgd_t *pgd = pgd_offset_k(addr);
 
        BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
 
-       return pud_offset(pgd, addr);
+       return pud_offset_kimg(pgd, addr);
 }
 
 static inline pmd_t * fixmap_pmd(unsigned long addr)
@@ -575,16 +658,12 @@ static inline pmd_t * fixmap_pmd(unsigned long addr)
 
        BUG_ON(pud_none(*pud) || pud_bad(*pud));
 
-       return pmd_offset(pud, addr);
+       return pmd_offset_kimg(pud, addr);
 }
 
 static inline pte_t * fixmap_pte(unsigned long addr)
 {
-       pmd_t *pmd = fixmap_pmd(addr);
-
-       BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
-
-       return pte_offset_kernel(pmd, addr);
+       return &bm_pte[pte_index(addr)];
 }
 
 void __init early_fixmap_init(void)
@@ -595,15 +674,26 @@ void __init early_fixmap_init(void)
        unsigned long addr = FIXADDR_START;
 
        pgd = pgd_offset_k(addr);
-       pgd_populate(&init_mm, pgd, bm_pud);
-       pud = pud_offset(pgd, addr);
+       if (CONFIG_PGTABLE_LEVELS > 3 &&
+           !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa(bm_pud))) {
+               /*
+                * We only end up here if the kernel mapping and the fixmap
+                * share the top level pgd entry, which should only happen on
+                * 16k/4 levels configurations.
+                */
+               BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
+               pud = pud_offset_kimg(pgd, addr);
+       } else {
+               pgd_populate(&init_mm, pgd, bm_pud);
+               pud = fixmap_pud(addr);
+       }
        pud_populate(&init_mm, pud, bm_pmd);
-       pmd = pmd_offset(pud, addr);
+       pmd = fixmap_pmd(addr);
        pmd_populate_kernel(&init_mm, pmd, bm_pte);
 
        /*
         * The boot-ioremap range spans multiple pmds, for which
-        * we are not preparted:
+        * we are not prepared:
         */
        BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
                     != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
@@ -642,11 +732,10 @@ void __set_fixmap(enum fixed_addresses idx,
        }
 }
 
-void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
+void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
 {
        const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
-       pgprot_t prot = PAGE_KERNEL_RO;
-       int size, offset;
+       int offset;
        void *dt_virt;
 
        /*
@@ -663,7 +752,7 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
        /*
         * Make sure that the FDT region can be mapped without the need to
         * allocate additional translation table pages, so that it is safe
-        * to call create_mapping() this early.
+        * to call create_mapping_noalloc() this early.
         *
         * On 64k pages, the FDT will be mapped using PTEs, so we need to
         * be in the same PMD as the rest of the fixmap.
@@ -679,21 +768,73 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
        dt_virt = (void *)dt_virt_base + offset;
 
        /* map the first chunk so we can read the size from the header */
-       create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
-                      SWAPPER_BLOCK_SIZE, prot);
+       create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
+                       dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
 
        if (fdt_check_header(dt_virt) != 0)
                return NULL;
 
-       size = fdt_totalsize(dt_virt);
-       if (size > MAX_FDT_SIZE)
+       *size = fdt_totalsize(dt_virt);
+       if (*size > MAX_FDT_SIZE)
                return NULL;
 
-       if (offset + size > SWAPPER_BLOCK_SIZE)
-               create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
-                              round_up(offset + size, SWAPPER_BLOCK_SIZE), prot);
+       if (offset + *size > SWAPPER_BLOCK_SIZE)
+               create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
+                              round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot);
 
-       memblock_reserve(dt_phys, size);
+       return dt_virt;
+}
 
+void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
+{
+       void *dt_virt;
+       int size;
+
+       dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
+       if (!dt_virt)
+               return NULL;
+
+       memblock_reserve(dt_phys, size);
        return dt_virt;
 }
+
+int __init arch_ioremap_pud_supported(void)
+{
+       /* only 4k granule supports level 1 block mappings */
+       return IS_ENABLED(CONFIG_ARM64_4K_PAGES);
+}
+
+int __init arch_ioremap_pmd_supported(void)
+{
+       return 1;
+}
+
+int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot)
+{
+       BUG_ON(phys & ~PUD_MASK);
+       set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
+       return 1;
+}
+
+int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot)
+{
+       BUG_ON(phys & ~PMD_MASK);
+       set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
+       return 1;
+}
+
+int pud_clear_huge(pud_t *pud)
+{
+       if (!pud_sect(*pud))
+               return 0;
+       pud_clear(pud);
+       return 1;
+}
+
+int pmd_clear_huge(pmd_t *pmd)
+{
+       if (!pmd_sect(*pmd))
+               return 0;
+       pmd_clear(pmd);
+       return 1;
+}
index cf6240741134ecbeece606dade39dc90478a08b6..ca6d268e3313229b0941ce7d33439c7a4c861120 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -36,14 +37,32 @@ static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
        return 0;
 }
 
+/*
+ * This function assumes that the range is mapped with PAGE_SIZE pages.
+ */
+static int __change_memory_common(unsigned long start, unsigned long size,
+                               pgprot_t set_mask, pgprot_t clear_mask)
+{
+       struct page_change_data data;
+       int ret;
+
+       data.set_mask = set_mask;
+       data.clear_mask = clear_mask;
+
+       ret = apply_to_page_range(&init_mm, start, size, change_page_range,
+                                       &data);
+
+       flush_tlb_kernel_range(start, start + size);
+       return ret;
+}
+
 static int change_memory_common(unsigned long addr, int numpages,
                                pgprot_t set_mask, pgprot_t clear_mask)
 {
        unsigned long start = addr;
        unsigned long size = PAGE_SIZE*numpages;
        unsigned long end = start + size;
-       int ret;
-       struct page_change_data data;
+       struct vm_struct *area;
 
        if (!PAGE_ALIGNED(addr)) {
                start &= PAGE_MASK;
@@ -51,23 +70,29 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (start < MODULES_VADDR || start >= MODULES_END)
-               return -EINVAL;
-
-       if (end < MODULES_VADDR || end >= MODULES_END)
+       /*
+        * Kernel VA mappings are always live, and splitting live section
+        * mappings into page mappings may cause TLB conflicts. This means
+        * we have to ensure that changing the permission bits of the range
+        * we are operating on does not result in such splitting.
+        *
+        * Let's restrict ourselves to mappings created by vmalloc (or vmap).
+        * Those are guaranteed to consist entirely of page mappings, and
+        * splitting is never needed.
+        *
+        * So check whether the [addr, addr + size) interval is entirely
+        * covered by precisely one VM area that has the VM_ALLOC flag set.
+        */
+       area = find_vm_area((void *)addr);
+       if (!area ||
+           end > (unsigned long)area->addr + area->size ||
+           !(area->flags & VM_ALLOC))
                return -EINVAL;
 
        if (!numpages)
                return 0;
 
-       data.set_mask = set_mask;
-       data.clear_mask = clear_mask;
-
-       ret = apply_to_page_range(&init_mm, start, size, change_page_range,
-                                       &data);
-
-       flush_tlb_kernel_range(start, end);
-       return ret;
+       return __change_memory_common(start, size, set_mask, clear_mask);
 }
 
 int set_memory_ro(unsigned long addr, int numpages)
@@ -99,3 +124,19 @@ int set_memory_x(unsigned long addr, int numpages)
                                        __pgprot(PTE_PXN));
 }
 EXPORT_SYMBOL_GPL(set_memory_x);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void __kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       unsigned long addr = (unsigned long) page_address(page);
+
+       if (enable)
+               __change_memory_common(addr, PAGE_SIZE * numpages,
+                                       __pgprot(PTE_VALID),
+                                       __pgprot(0));
+       else
+               __change_memory_common(addr, PAGE_SIZE * numpages,
+                                       __pgprot(0),
+                                       __pgprot(PTE_VALID));
+}
+#endif
index cb3ba1b812e74dcd1acbc167756d60da331d105f..ae11d4e03d0e68d7f0fe621f1c9d313fcab09127 100644 (file)
@@ -46,14 +46,14 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
                kmem_cache_free(pgd_cache, pgd);
 }
 
-static int __init pgd_cache_init(void)
+void __init pgd_cache_init(void)
 {
+       if (PGD_SIZE == PAGE_SIZE)
+               return;
+
        /*
         * Naturally aligned pgds required by the architecture.
         */
-       if (PGD_SIZE != PAGE_SIZE)
-               pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
-                                             SLAB_PANIC, NULL);
-       return 0;
+       pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
+                                     SLAB_PANIC, NULL);
 }
-core_initcall(pgd_cache_init);
index d69dffffaa8993bc7260c1df035b92c3b3867b48..984edcda1850f1be420f92be7666b36c687cc476 100644 (file)
        msr     pmuserenr_el0, xzr              // Disable PMU access from EL0
 9000:
        .endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [kaddr, kaddr + size)
+ *
+ *     op:             operation passed to dc instruction
+ *     domain:         domain used in dsb instruciton
+ *     kaddr:          starting virtual address of the region
+ *     size:           size of the region
+ *     Corrupts:       kaddr, size, tmp1, tmp2
+ */
+       .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
+       dcache_line_size \tmp1, \tmp2
+       add     \size, \kaddr, \size
+       sub     \tmp2, \tmp1, #1
+       bic     \kaddr, \kaddr, \tmp2
+9998:  dc      \op, \kaddr
+       add     \kaddr, \kaddr, \tmp1
+       cmp     \kaddr, \size
+       b.lo    9998b
+       dsb     \domain
+       .endm
index b8f04b3f2786cc7ef29c1e47bf3bfec0f4bfc840..0c19534a901e616ecc5fe508ce205dc0de8fe0f4 100644 (file)
@@ -140,7 +140,33 @@ ENTRY(cpu_do_switch_mm)
        ret
 ENDPROC(cpu_do_switch_mm)
 
-       .section ".text.init", #alloc, #execinstr
+       .pushsection ".idmap.text", "ax"
+/*
+ * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd)
+ *
+ * This is the low-level counterpart to cpu_replace_ttbr1, and should not be
+ * called by anything else. It can only be executed from a TTBR0 mapping.
+ */
+ENTRY(idmap_cpu_replace_ttbr1)
+       mrs     x2, daif
+       msr     daifset, #0xf
+
+       adrp    x1, empty_zero_page
+       msr     ttbr1_el1, x1
+       isb
+
+       tlbi    vmalle1
+       dsb     nsh
+       isb
+
+       msr     ttbr1_el1, x0
+       isb
+
+       msr     daif, x2
+
+       ret
+ENDPROC(idmap_cpu_replace_ttbr1)
+       .popsection
 
 /*
  *     __cpu_setup
index 9041bbe2b7b42dfe344a7bfe8759ba493955ed94..8fdb9c7eeb6641c7c538116f48bd69fec5ce2930 100644 (file)
@@ -436,6 +436,7 @@ static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned lo
        return ioremap(phys_addr, size);
 }
 #define ioremap_cache ioremap_cache
+#define ioremap_uc ioremap_nocache
 
 
 /*
index bdeed9d13c6fe01c0c804b695af44efd16817f46..433c4b9a9f0a92af20e31f1f16f9be5cde955b12 100644 (file)
@@ -503,15 +503,15 @@ int __init db1000_dev_setup(void)
        if (board == BCSR_WHOAMI_DB1500) {
                c0 = AU1500_GPIO2_INT;
                c1 = AU1500_GPIO5_INT;
-               d0 = AU1500_GPIO0_INT;
-               d1 = AU1500_GPIO3_INT;
+               d0 = 0; /* GPIO number, NOT irq! */
+               d1 = 3; /* GPIO number, NOT irq! */
                s0 = AU1500_GPIO1_INT;
                s1 = AU1500_GPIO4_INT;
        } else if (board == BCSR_WHOAMI_DB1100) {
                c0 = AU1100_GPIO2_INT;
                c1 = AU1100_GPIO5_INT;
-               d0 = AU1100_GPIO0_INT;
-               d1 = AU1100_GPIO3_INT;
+               d0 = 0; /* GPIO number, NOT irq! */
+               d1 = 3; /* GPIO number, NOT irq! */
                s0 = AU1100_GPIO1_INT;
                s1 = AU1100_GPIO4_INT;
 
@@ -545,15 +545,15 @@ int __init db1000_dev_setup(void)
        } else if (board == BCSR_WHOAMI_DB1000) {
                c0 = AU1000_GPIO2_INT;
                c1 = AU1000_GPIO5_INT;
-               d0 = AU1000_GPIO0_INT;
-               d1 = AU1000_GPIO3_INT;
+               d0 = 0; /* GPIO number, NOT irq! */
+               d1 = 3; /* GPIO number, NOT irq! */
                s0 = AU1000_GPIO1_INT;
                s1 = AU1000_GPIO4_INT;
                platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs));
        } else if ((board == BCSR_WHOAMI_PB1500) ||
                   (board == BCSR_WHOAMI_PB1500R2)) {
                c0 = AU1500_GPIO203_INT;
-               d0 = AU1500_GPIO201_INT;
+               d0 = 1; /* GPIO number, NOT irq! */
                s0 = AU1500_GPIO202_INT;
                twosocks = 0;
                flashsize = 64;
@@ -566,7 +566,7 @@ int __init db1000_dev_setup(void)
                 */
        } else if (board == BCSR_WHOAMI_PB1100) {
                c0 = AU1100_GPIO11_INT;
-               d0 = AU1100_GPIO9_INT;
+               d0 = 9; /* GPIO number, NOT irq! */
                s0 = AU1100_GPIO10_INT;
                twosocks = 0;
                flashsize = 64;
@@ -583,7 +583,6 @@ int __init db1000_dev_setup(void)
        } else
                return 0; /* unknown board, no further dev setup to do */
 
-       irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH);
        irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW);
        irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW);
 
@@ -597,7 +596,6 @@ int __init db1000_dev_setup(void)
                c0, d0, /*s0*/0, 0, 0);
 
        if (twosocks) {
-               irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH);
                irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW);
                irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW);
 
index 5740bcfdfc7f622b76402a3c0551e3c475ea7099..6c37b9326f414ddbab91d1c2412bf42e08fe1ca4 100644 (file)
@@ -514,7 +514,7 @@ static void __init db1550_devices(void)
                AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x000400000 - 1,
                AU1000_PCMCIA_IO_PHYS_ADDR,
                AU1000_PCMCIA_IO_PHYS_ADDR   + 0x000010000 - 1,
-               AU1550_GPIO3_INT, AU1550_GPIO0_INT,
+               AU1550_GPIO3_INT, 0,
                /*AU1550_GPIO21_INT*/0, 0, 0);
 
        db1x_register_pcmcia_socket(
@@ -524,7 +524,7 @@ static void __init db1550_devices(void)
                AU1000_PCMCIA_MEM_PHYS_ADDR  + 0x004400000 - 1,
                AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004000000,
                AU1000_PCMCIA_IO_PHYS_ADDR   + 0x004010000 - 1,
-               AU1550_GPIO5_INT, AU1550_GPIO1_INT,
+               AU1550_GPIO5_INT, 1,
                /*AU1550_GPIO22_INT*/0, 0, 1);
 
        platform_device_register(&db1550_nand_dev);
index 490cea569d57d0088e50e241f3465c91f07bbcc7..5c62065cbf22d610323331b8d3bd56e6e53fa793 100644 (file)
@@ -885,7 +885,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
 {
        union mips_instruction insn;
        unsigned long value;
-       unsigned int res;
+       unsigned int res, preempted;
        unsigned long origpc;
        unsigned long orig31;
        void __user *fault_addr = NULL;
@@ -1226,27 +1226,36 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                        if (!access_ok(VERIFY_READ, addr, sizeof(*fpr)))
                                goto sigbus;
 
-                       /*
-                        * Disable preemption to avoid a race between copying
-                        * state from userland, migrating to another CPU and
-                        * updating the hardware vector register below.
-                        */
-                       preempt_disable();
-
-                       res = __copy_from_user_inatomic(fpr, addr,
-                                                       sizeof(*fpr));
-                       if (res)
-                               goto fault;
-
-                       /*
-                        * Update the hardware register if it is in use by the
-                        * task in this quantum, in order to avoid having to
-                        * save & restore the whole vector context.
-                        */
-                       if (test_thread_flag(TIF_USEDMSA))
-                               write_msa_wr(wd, fpr, df);
+                       do {
+                               /*
+                                * If we have live MSA context keep track of
+                                * whether we get preempted in order to avoid
+                                * the register context we load being clobbered
+                                * by the live context as it's saved during
+                                * preemption. If we don't have live context
+                                * then it can't be saved to clobber the value
+                                * we load.
+                                */
+                               preempted = test_thread_flag(TIF_USEDMSA);
+
+                               res = __copy_from_user_inatomic(fpr, addr,
+                                                               sizeof(*fpr));
+                               if (res)
+                                       goto fault;
 
-                       preempt_enable();
+                               /*
+                                * Update the hardware register if it is in use
+                                * by the task in this quantum, in order to
+                                * avoid having to save & restore the whole
+                                * vector context.
+                                */
+                               preempt_disable();
+                               if (test_thread_flag(TIF_USEDMSA)) {
+                                       write_msa_wr(wd, fpr, df);
+                                       preempted = 0;
+                               }
+                               preempt_enable();
+                       } while (preempted);
                        break;
 
                case msa_st_op:
index 729f89163bc32113dba77e309c8ce767ed3d15e8..d2256fa97ea0c7875df5d21bcfff23bb6f25a0d9 100644 (file)
@@ -11,6 +11,7 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
+       select BUILDTIME_EXTABLE_SORT
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
index b3069fd83468c5972f98d19f8f17dfa9bfb5e0cf..60e6f07b7e326bc4eb306105dcae477d5aa01f0e 100644 (file)
         */
 #define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr)      \
        .section __ex_table,"aw"                        !       \
-       ASM_ULONG_INSN  fault_addr, except_addr         !       \
+       .word (fault_addr - .), (except_addr - .)       !       \
        .previous
 
 
index 0abdd4c607ed9dc22dce8610d8f8d1d016656553..6f893d29f1b21625aadc4464d06ffba30b7697f3 100644 (file)
@@ -60,14 +60,15 @@ static inline long access_ok(int type, const void __user * addr,
  * use a 32bit (unsigned int) address here.
  */
 
+#define ARCH_HAS_RELATIVE_EXTABLE
 struct exception_table_entry {
-       unsigned long insn;     /* address of insn that is allowed to fault. */
-       unsigned long fixup;    /* fixup routine */
+       int insn;       /* relative address of insn that is allowed to fault. */
+       int fixup;      /* relative address of fixup routine */
 };
 
 #define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\
        ".section __ex_table,\"aw\"\n"                     \
-       ASM_WORD_INSN #fault_addr ", " #except_addr "\n\t" \
+       ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \
        ".previous\n"
 
 /*
@@ -76,6 +77,7 @@ struct exception_table_entry {
  */
 struct exception_data {
        unsigned long fault_ip;
+       unsigned long fault_gp;
        unsigned long fault_space;
        unsigned long fault_addr;
 };
index d2f62570a7b16d4f4c6321515d980f048cd278f2..78d30d2ea2d8bb24116a7639a3d4bc5f90400058 100644 (file)
@@ -299,6 +299,7 @@ int main(void)
 #endif
        BLANK();
        DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
+       DEFINE(EXCDATA_GP, offsetof(struct exception_data, fault_gp));
        DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
        DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr));
        BLANK();
index 568b2c61ea0208de80bcd1f5fdc54f7aafa95a30..3cad8aadc69e7a1159c829a7e5e5cea9f6a1297b 100644 (file)
@@ -47,11 +47,11 @@ EXPORT_SYMBOL(__cmpxchg_u64);
 EXPORT_SYMBOL(lclear_user);
 EXPORT_SYMBOL(lstrnlen_user);
 
-/* Global fixups */
-extern void fixup_get_user_skip_1(void);
-extern void fixup_get_user_skip_2(void);
-extern void fixup_put_user_skip_1(void);
-extern void fixup_put_user_skip_2(void);
+/* Global fixups - defined as int to avoid creation of function pointers */
+extern int fixup_get_user_skip_1;
+extern int fixup_get_user_skip_2;
+extern int fixup_put_user_skip_1;
+extern int fixup_put_user_skip_2;
 EXPORT_SYMBOL(fixup_get_user_skip_1);
 EXPORT_SYMBOL(fixup_get_user_skip_2);
 EXPORT_SYMBOL(fixup_put_user_skip_1);
index 553b09855cfd8799acde0df3d9118afcfcf5cbb0..77e2262c97f644e38fcd5478af7c5885c2164fcc 100644 (file)
@@ -798,6 +798,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
 
            if (fault_space == 0 && !faulthandler_disabled())
            {
+               /* Clean up and return if in exception table. */
+               if (fixup_exception(regs))
+                       return;
                pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
                parisc_terminate("Kernel Fault", regs, code, fault_address);
            }
index 536ef66bb94b5aa8c46800a968514184b5e2d85d..1052b747e011336621c6ca9f7c9eaf78af7af6df 100644 (file)
@@ -26,6 +26,7 @@
 
 #ifdef CONFIG_SMP
        .macro  get_fault_ip t1 t2
+       loadgp
        addil LT%__per_cpu_offset,%r27
        LDREG RT%__per_cpu_offset(%r1),\t1
        /* t2 = smp_processor_id() */
        LDREG RT%exception_data(%r1),\t1
        /* t1 = this_cpu_ptr(&exception_data) */
        add,l \t1,\t2,\t1
+       /* %r27 = t1->fault_gp - restore gp */
+       LDREG EXCDATA_GP(\t1), %r27
        /* t1 = t1->fault_ip */
        LDREG EXCDATA_IP(\t1), \t1
        .endm
 #else
        .macro  get_fault_ip t1 t2
+       loadgp
        /* t1 = this_cpu_ptr(&exception_data) */
        addil LT%exception_data,%r27
        LDREG RT%exception_data(%r1),\t2
+       /* %r27 = t2->fault_gp - restore gp */
+       LDREG EXCDATA_GP(\t2), %r27
        /* t1 = t2->fault_ip */
        LDREG EXCDATA_IP(\t2), \t1
        .endm
index a762864ec92e9baf9bf2d2016474c21b94e026b8..16dbe81c97c9005df3cbb91045ccb6ed20878930 100644 (file)
@@ -140,21 +140,17 @@ int fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *fix;
 
-       /* If we only stored 32bit addresses in the exception table we can drop
-        * out if we faulted on a 64bit address. */
-       if ((sizeof(regs->iaoq[0]) > sizeof(fix->insn))
-               && (regs->iaoq[0] >> 32))
-                       return 0;
-
        fix = search_exception_tables(regs->iaoq[0]);
        if (fix) {
                struct exception_data *d;
                d = this_cpu_ptr(&exception_data);
                d->fault_ip = regs->iaoq[0];
+               d->fault_gp = regs->gr[27];
                d->fault_space = regs->isr;
                d->fault_addr = regs->ior;
 
-               regs->iaoq[0] = ((fix->fixup) & ~3);
+               regs->iaoq[0] = (unsigned long)&fix->fixup + fix->fixup;
+               regs->iaoq[0] &= ~3;
                /*
                 * NOTE: In some cases the faulting instruction
                 * may be in the delay slot of a branch. We
index e4396a7d0f7cf5627a92ea8c07756aba6bc52c7a..4afe66aa1400d5d7e3783e696a0a1de12d3a316c 100644 (file)
@@ -82,7 +82,7 @@ static inline unsigned long create_zero_mask(unsigned long bits)
            "andc       %1,%1,%2\n\t"
            "popcntd    %0,%1"
                : "=r" (leading_zero_bits), "=&r" (trailing_zero_bit_mask)
-               : "r" (bits));
+               : "b" (bits));
 
        return leading_zero_bits;
 }
index 43686043e29734b47b183882417e309e617d1039..2734c005da213faea5ffc465de094efbd3cc5e78 100644 (file)
@@ -31,6 +31,7 @@
 #define PPC_FEATURE_PSERIES_PERFMON_COMPAT \
                                        0x00000040
 
+/* Reserved - do not use               0x00000004 */
 #define PPC_FEATURE_TRUE_LE            0x00000002
 #define PPC_FEATURE_PPC_LE             0x00000001
 
index 36795d1e75586aa523f2c55ffabc09baeb1562f1..a7b91b54c8134d3f94ce2c2a1dce9b38db30ad59 100644 (file)
@@ -551,24 +551,6 @@ static void tm_reclaim_thread(struct thread_struct *thr,
                msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1;
        }
 
-       /*
-        * Use the current MSR TM suspended bit to track if we have
-        * checkpointed state outstanding.
-        * On signal delivery, we'd normally reclaim the checkpointed
-        * state to obtain stack pointer (see:get_tm_stackpointer()).
-        * This will then directly return to userspace without going
-        * through __switch_to(). However, if the stack frame is bad,
-        * we need to exit this thread which calls __switch_to() which
-        * will again attempt to reclaim the already saved tm state.
-        * Hence we need to check that we've not already reclaimed
-        * this state.
-        * We do this using the current MSR, rather tracking it in
-        * some specific thread_struct bit, as it has the additional
-        * benifit of checking for a potential TM bad thing exception.
-        */
-       if (!MSR_TM_SUSPENDED(mfmsr()))
-               return;
-
        /*
         * Use the current MSR TM suspended bit to track if we have
         * checkpointed state outstanding.
index 7030b035905dbf85b03bd36fa4bdc2a4a14982de..a15fe1d4e84aec9955622b603823fe44633da98d 100644 (file)
@@ -148,23 +148,25 @@ static struct ibm_pa_feature {
        unsigned long   cpu_features;   /* CPU_FTR_xxx bit */
        unsigned long   mmu_features;   /* MMU_FTR_xxx bit */
        unsigned int    cpu_user_ftrs;  /* PPC_FEATURE_xxx bit */
+       unsigned int    cpu_user_ftrs2; /* PPC_FEATURE2_xxx bit */
        unsigned char   pabyte;         /* byte number in ibm,pa-features */
        unsigned char   pabit;          /* bit number (big-endian) */
        unsigned char   invert;         /* if 1, pa bit set => clear feature */
 } ibm_pa_features[] __initdata = {
-       {0, 0, PPC_FEATURE_HAS_MMU,     0, 0, 0},
-       {0, 0, PPC_FEATURE_HAS_FPU,     0, 1, 0},
-       {CPU_FTR_CTRL, 0, 0,            0, 3, 0},
-       {CPU_FTR_NOEXECUTE, 0, 0,       0, 6, 0},
-       {CPU_FTR_NODSISRALIGN, 0, 0,    1, 1, 1},
-       {0, MMU_FTR_CI_LARGE_PAGE, 0,   1, 2, 0},
-       {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
+       {0, 0, PPC_FEATURE_HAS_MMU, 0,          0, 0, 0},
+       {0, 0, PPC_FEATURE_HAS_FPU, 0,          0, 1, 0},
+       {CPU_FTR_CTRL, 0, 0, 0,                 0, 3, 0},
+       {CPU_FTR_NOEXECUTE, 0, 0, 0,            0, 6, 0},
+       {CPU_FTR_NODSISRALIGN, 0, 0, 0,         1, 1, 1},
+       {0, MMU_FTR_CI_LARGE_PAGE, 0, 0,                1, 2, 0},
+       {CPU_FTR_REAL_LE, 0, PPC_FEATURE_TRUE_LE, 0, 5, 0, 0},
        /*
-        * If the kernel doesn't support TM (ie. CONFIG_PPC_TRANSACTIONAL_MEM=n),
-        * we don't want to turn on CPU_FTR_TM here, so we use CPU_FTR_TM_COMP
-        * which is 0 if the kernel doesn't support TM.
+        * If the kernel doesn't support TM (ie CONFIG_PPC_TRANSACTIONAL_MEM=n),
+        * we don't want to turn on TM here, so we use the *_COMP versions
+        * which are 0 if the kernel doesn't support TM.
         */
-       {CPU_FTR_TM_COMP, 0, 0,         22, 0, 0},
+       {CPU_FTR_TM_COMP, 0, 0,
+        PPC_FEATURE2_HTM_COMP|PPC_FEATURE2_HTM_NOSC_COMP, 22, 0, 0},
 };
 
 static void __init scan_features(unsigned long node, const unsigned char *ftrs,
@@ -195,10 +197,12 @@ static void __init scan_features(unsigned long node, const unsigned char *ftrs,
                if (bit ^ fp->invert) {
                        cur_cpu_spec->cpu_features |= fp->cpu_features;
                        cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs;
+                       cur_cpu_spec->cpu_user_features2 |= fp->cpu_user_ftrs2;
                        cur_cpu_spec->mmu_features |= fp->mmu_features;
                } else {
                        cur_cpu_spec->cpu_features &= ~fp->cpu_features;
                        cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs;
+                       cur_cpu_spec->cpu_user_features2 &= ~fp->cpu_user_ftrs2;
                        cur_cpu_spec->mmu_features &= ~fp->mmu_features;
                }
        }
index 9833fee493ec414be50c241153889d7ac4259402..807f1594701df4eb5892dbd8ce9d77305e377ac4 100644 (file)
@@ -486,13 +486,13 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte)
 {
        struct hugepd_freelist **batchp;
 
-       batchp = this_cpu_ptr(&hugepd_freelist_cur);
+       batchp = &get_cpu_var(hugepd_freelist_cur);
 
        if (atomic_read(&tlb->mm->mm_users) < 2 ||
            cpumask_equal(mm_cpumask(tlb->mm),
                          cpumask_of(smp_processor_id()))) {
                kmem_cache_free(hugepte_cache, hugepte);
-        put_cpu_var(hugepd_freelist_cur);
+               put_cpu_var(hugepd_freelist_cur);
                return;
        }
 
index c873e682b67f8e4063628a1726a896a167a9d8c4..6dafabb6ae1a504a09ce0c1574b6233a26722edf 100644 (file)
@@ -45,7 +45,8 @@ struct zpci_fmb {
        u64 rpcit_ops;
        u64 dma_rbytes;
        u64 dma_wbytes;
-} __packed __aligned(16);
+       u64 pad[2];
+} __packed __aligned(128);
 
 enum zpci_state {
        ZPCI_FN_STATE_RESERVED,
index 857b6526d29833507c3abec126b90a24e491956f..424e6809ad07af8a7ec8533fddb5b6501b9ea052 100644 (file)
@@ -1197,114 +1197,12 @@ cleanup_critical:
        .quad   .Lpsw_idle_lpsw
 
 .Lcleanup_save_fpu_regs:
-       TSTMSK  __LC_CPU_FLAGS,_CIF_FPU
-       bor     %r14
-       clg     %r9,BASED(.Lcleanup_save_fpu_regs_done)
-       jhe     5f
-       clg     %r9,BASED(.Lcleanup_save_fpu_regs_fp)
-       jhe     4f
-       clg     %r9,BASED(.Lcleanup_save_fpu_regs_vx_high)
-       jhe     3f
-       clg     %r9,BASED(.Lcleanup_save_fpu_regs_vx_low)
-       jhe     2f
-       clg     %r9,BASED(.Lcleanup_save_fpu_fpc_end)
-       jhe     1f
-       lg      %r2,__LC_CURRENT
-       aghi    %r2,__TASK_thread
-0:     # Store floating-point controls
-       stfpc   __THREAD_FPU_fpc(%r2)
-1:     # Load register save area and check if VX is active
-       lg      %r3,__THREAD_FPU_regs(%r2)
-       TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
-       jz      4f                        # no VX -> store FP regs
-2:     # Store vector registers (V0-V15)
-       VSTM    %v0,%v15,0,%r3            # vstm 0,15,0(3)
-3:     # Store vector registers (V16-V31)
-       VSTM    %v16,%v31,256,%r3         # vstm 16,31,256(3)
-       j       5f                        # -> done, set CIF_FPU flag
-4:     # Store floating-point registers
-       std     0,0(%r3)
-       std     1,8(%r3)
-       std     2,16(%r3)
-       std     3,24(%r3)
-       std     4,32(%r3)
-       std     5,40(%r3)
-       std     6,48(%r3)
-       std     7,56(%r3)
-       std     8,64(%r3)
-       std     9,72(%r3)
-       std     10,80(%r3)
-       std     11,88(%r3)
-       std     12,96(%r3)
-       std     13,104(%r3)
-       std     14,112(%r3)
-       std     15,120(%r3)
-5:     # Set CIF_FPU flag
-       oi      __LC_CPU_FLAGS+7,_CIF_FPU
-       lg      %r9,48(%r11)            # return from save_fpu_regs
+       larl    %r9,save_fpu_regs
        br      %r14
-.Lcleanup_save_fpu_fpc_end:
-       .quad   .Lsave_fpu_regs_fpc_end
-.Lcleanup_save_fpu_regs_vx_low:
-       .quad   .Lsave_fpu_regs_vx_low
-.Lcleanup_save_fpu_regs_vx_high:
-       .quad   .Lsave_fpu_regs_vx_high
-.Lcleanup_save_fpu_regs_fp:
-       .quad   .Lsave_fpu_regs_fp
-.Lcleanup_save_fpu_regs_done:
-       .quad   .Lsave_fpu_regs_done
 
 .Lcleanup_load_fpu_regs:
-       TSTMSK  __LC_CPU_FLAGS,_CIF_FPU
-       bnor    %r14
-       clg     %r9,BASED(.Lcleanup_load_fpu_regs_done)
-       jhe     1f
-       clg     %r9,BASED(.Lcleanup_load_fpu_regs_fp)
-       jhe     2f
-       clg     %r9,BASED(.Lcleanup_load_fpu_regs_vx_high)
-       jhe     3f
-       clg     %r9,BASED(.Lcleanup_load_fpu_regs_vx)
-       jhe     4f
-       lg      %r4,__LC_CURRENT
-       aghi    %r4,__TASK_thread
-       lfpc    __THREAD_FPU_fpc(%r4)
-       TSTMSK  __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
-       lg      %r4,__THREAD_FPU_regs(%r4)      # %r4 <- reg save area
-       jz      2f                              # -> no VX, load FP regs
-4:     # Load V0 ..V15 registers
-       VLM     %v0,%v15,0,%r4
-3:     # Load V16..V31 registers
-       VLM     %v16,%v31,256,%r4
-       j       1f
-2:     # Load floating-point registers
-       ld      0,0(%r4)
-       ld      1,8(%r4)
-       ld      2,16(%r4)
-       ld      3,24(%r4)
-       ld      4,32(%r4)
-       ld      5,40(%r4)
-       ld      6,48(%r4)
-       ld      7,56(%r4)
-       ld      8,64(%r4)
-       ld      9,72(%r4)
-       ld      10,80(%r4)
-       ld      11,88(%r4)
-       ld      12,96(%r4)
-       ld      13,104(%r4)
-       ld      14,112(%r4)
-       ld      15,120(%r4)
-1:     # Clear CIF_FPU bit
-       ni      __LC_CPU_FLAGS+7,255-_CIF_FPU
-       lg      %r9,48(%r11)            # return from load_fpu_regs
+       larl    %r9,load_fpu_regs
        br      %r14
-.Lcleanup_load_fpu_regs_vx:
-       .quad   .Lload_fpu_regs_vx
-.Lcleanup_load_fpu_regs_vx_high:
-       .quad   .Lload_fpu_regs_vx_high
-.Lcleanup_load_fpu_regs_fp:
-       .quad   .Lload_fpu_regs_fp
-.Lcleanup_load_fpu_regs_done:
-       .quad   .Lload_fpu_regs_done
 
 /*
  * Integer constants
index 58b719fa8067a5b7e2ec428c0babc758c6dc0eb4..1ad2407c7f7590fea27a8e94d541be5179161602 100644 (file)
@@ -16,7 +16,7 @@
 
 __HEAD
 ENTRY(startup_continue)
-       tm      __LC_STFL_FAC_LIST+6,0x80       # LPP available ?
+       tm      __LC_STFL_FAC_LIST+5,0x80       # LPP available ?
        jz      0f
        xc      __LC_LPP+1(7,0),__LC_LPP+1      # clear lpp and current_pid
        mvi     __LC_LPP,0x80                   #   and set LPP_MAGIC
index c837bcacf2188460a50754f3a75d1b485c25f671..1f581eb61bc20f928fffb6e065cfcf6100a9a2a8 100644 (file)
@@ -329,6 +329,7 @@ static void __init setup_lowcore(void)
                + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
        lc->thread_info = (unsigned long) &init_thread_union;
+       lc->lpp = LPP_MAGIC;
        lc->machine_flags = S390_lowcore.machine_flags;
        lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
        memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
index 7ef12a3ace3aef665bd7b1bb637cc0d9dafcc6bd..19442395f413b061c36ed848c0962c09624b7282 100644 (file)
@@ -871,8 +871,11 @@ static inline int barsize(u8 size)
 
 static int zpci_mem_init(void)
 {
+       BUILD_BUG_ON(!is_power_of_2(__alignof__(struct zpci_fmb)) ||
+                    __alignof__(struct zpci_fmb) < sizeof(struct zpci_fmb));
+
        zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
-                               16, 0, NULL);
+                                          __alignof__(struct zpci_fmb), 0, NULL);
        if (!zdev_fmb_cache)
                goto error_zdev;
 
index ec29e14ec5a85643b600952b3140f013ada5d258..bf25d7c79a2d82d5dd6b26ca95b79a72643f2791 100644 (file)
@@ -36,6 +36,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
 
        BUG_ON(!test_bit(PG_dcache_clean, &page->flags));
 
+       preempt_disable();
        pagefault_disable();
 
        idx = FIX_CMAP_END -
@@ -64,4 +65,5 @@ void kunmap_coherent(void *kvaddr)
        }
 
        pagefault_enable();
+       preempt_enable();
 }
index 29880c9b324ed33601c8af02340a4765d9d75b3b..e22e57298522b0ced2fbecd9dfc24830c4739e3a 100644 (file)
@@ -133,7 +133,7 @@ void mconsole_proc(struct mc_request *req)
        ptr += strlen("proc");
        ptr = skip_spaces(ptr);
 
-       file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
+       file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
        if (IS_ERR(file)) {
                mconsole_reply(req, "Failed to open file", 1, 0);
                printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
index d6d57a5b21387fccc506f33e9219a65562d4d8ad..d95759ac048303cea010701e0d81e6e49ef6b713 100644 (file)
@@ -1145,22 +1145,23 @@ config MICROCODE
        bool "CPU microcode loading support"
        default y
        depends on CPU_SUP_AMD || CPU_SUP_INTEL
-       depends on BLK_DEV_INITRD
        select FW_LOADER
        ---help---
-
          If you say Y here, you will be able to update the microcode on
-         certain Intel and AMD processors. The Intel support is for the
-         IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4,
-         Xeon etc. The AMD support is for families 0x10 and later. You will
-         obviously need the actual microcode binary data itself which is not
-         shipped with the Linux kernel.
-
-         This option selects the general module only, you need to select
-         at least one vendor specific module as well.
-
-         To compile this driver as a module, choose M here: the module
-         will be called microcode.
+         Intel and AMD processors. The Intel support is for the IA32 family,
+         e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, Xeon etc. The
+         AMD support is for families 0x10 and later. You will obviously need
+         the actual microcode binary data itself which is not shipped with
+         the Linux kernel.
+
+         The preferred method to load microcode from a detached initrd is described
+         in Documentation/x86/early-microcode.txt. For that you need to enable
+         CONFIG_BLK_DEV_INITRD in order for the loader to be able to scan the
+         initrd for microcode blobs.
+
+         In addition, you can build-in the microcode into the kernel. For that you
+         need to enable FIRMWARE_IN_KERNEL and add the vendor-supplied microcode
+         to the CONFIG_EXTRA_FIRMWARE config option.
 
 config MICROCODE_INTEL
        bool "Intel microcode loading support"
index a841e9765bd614b17befbcf647319e2020412d88..8381c09d28706eec94e976fd9a3b76b7b018889d 100644 (file)
@@ -453,10 +453,10 @@ static int sha_complete_job(struct mcryptd_hash_request_ctx *rctx,
 
                        req = cast_mcryptd_ctx_to_req(req_ctx);
                        if (irqs_disabled())
-                               rctx->complete(&req->base, ret);
+                               req_ctx->complete(&req->base, ret);
                        else {
                                local_bh_disable();
-                               rctx->complete(&req->base, ret);
+                               req_ctx->complete(&req->base, ret);
                                local_bh_enable();
                        }
                }
index 03663740c86655cabf21504578e97d73d98595be..1a4477cedc498c3139cc57d39bc8f7785125c565 100644 (file)
@@ -268,6 +268,7 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags)
 /* Called with IRQs disabled. */
 __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
 {
+       struct thread_info *ti = pt_regs_to_thread_info(regs);
        u32 cached_flags;
 
        if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled()))
@@ -275,12 +276,22 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
 
        lockdep_sys_exit();
 
-       cached_flags =
-               READ_ONCE(pt_regs_to_thread_info(regs)->flags);
+       cached_flags = READ_ONCE(ti->flags);
 
        if (unlikely(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS))
                exit_to_usermode_loop(regs, cached_flags);
 
+#ifdef CONFIG_COMPAT
+       /*
+        * Compat syscalls set TS_COMPAT.  Make sure we clear it before
+        * returning to user mode.  We need to clear it *after* signal
+        * handling, because syscall restart has a fixup for compat
+        * syscalls.  The fixup is exercised by the ptrace_syscall_32
+        * selftest.
+        */
+       ti->status &= ~TS_COMPAT;
+#endif
+
        user_enter();
 }
 
@@ -332,14 +343,6 @@ __visible inline void syscall_return_slowpath(struct pt_regs *regs)
        if (unlikely(cached_flags & SYSCALL_EXIT_WORK_FLAGS))
                syscall_slow_exit_work(regs, cached_flags);
 
-#ifdef CONFIG_COMPAT
-       /*
-        * Compat syscalls set TS_COMPAT.  Make sure we clear it before
-        * returning to user mode.
-        */
-       ti->status &= ~TS_COMPAT;
-#endif
-
        local_irq_disable();
        prepare_exit_to_usermode(regs);
 }
index a30316bf801ab9da14753425de67670f71feece0..163769d824754f459ad94ab0ea69c66f0fe8914e 100644 (file)
@@ -638,8 +638,8 @@ static inline void entering_irq(void)
 
 static inline void entering_ack_irq(void)
 {
-       ack_APIC_irq();
        entering_irq();
+       ack_APIC_irq();
 }
 
 static inline void ipi_entering_ack_irq(void)
index 0010c78c4998cf0702299ea2f8a9229e09bb6438..08b1f2f6ea50c186933d0d9e79c82da0b9da4f3f 100644 (file)
@@ -25,6 +25,8 @@
 #define EFI32_LOADER_SIGNATURE "EL32"
 #define EFI64_LOADER_SIGNATURE "EL64"
 
+#define MAX_CMDLINE_ADDRESS    UINT_MAX
+
 #ifdef CONFIG_X86_32
 
 
index f8a29d2c97b012febc3728809a5daa53de22cf0f..e6a8613fbfb0ea19f8d507c4ce6ae1f0d4a35be6 100644 (file)
@@ -4,6 +4,7 @@
 #include <asm/page.h>
 #include <asm-generic/hugetlb.h>
 
+#define hugepages_supported() cpu_has_pse
 
 static inline int is_hugepage_only_range(struct mm_struct *mm,
                                         unsigned long addr,
index 1e3408e88604cd5b18bb67884aaa496d5344b969..59caa55fb9b527449fd7f06c7961ef83a03ea1f0 100644 (file)
@@ -136,6 +136,7 @@ struct irq_alloc_info {
 struct irq_cfg {
        unsigned int            dest_apicid;
        u8                      vector;
+       u8                      old_vector;
 };
 
 extern struct irq_cfg *irq_cfg(unsigned int irq);
index 30cfd64295a0075ab9c4727721c0fc8c8b607f46..9d2abb2a41d2d18e9f55d97a5d5d4b7598af890f 100644 (file)
@@ -41,7 +41,7 @@
 
 #define KVM_PIO_PAGE_OFFSET 1
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2
-#define KVM_HALT_POLL_NS_DEFAULT 500000
+#define KVM_HALT_POLL_NS_DEFAULT 400000
 
 #define KVM_IRQCHIP_NUM_PINS  KVM_IOAPIC_NUM_PINS
 
index 34e62b1dcfce46a606fbe78d7d55131513d859d3..712b24ed3a64c95e18869717280ee72532191b35 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_X86_MICROCODE_H
 
 #include <linux/earlycpio.h>
+#include <linux/initrd.h>
 
 #define native_rdmsr(msr, val1, val2)                  \
 do {                                                   \
@@ -168,4 +169,29 @@ static inline void reload_early_microcode(void)                    { }
 static inline bool
 get_builtin_firmware(struct cpio_data *cd, const char *name)   { return false; }
 #endif
+
+static inline unsigned long get_initrd_start(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       return initrd_start;
+#else
+       return 0;
+#endif
+}
+
+static inline unsigned long get_initrd_start_addr(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+#ifdef CONFIG_X86_32
+       unsigned long *initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);
+
+       return (unsigned long)__pa_nodebug(*initrd_start_p);
+#else
+       return get_initrd_start();
+#endif
+#else /* CONFIG_BLK_DEV_INITRD */
+       return 0;
+#endif
+}
+
 #endif /* _ASM_X86_MICROCODE_H */
index fa1195dae42541aaa1d836782a3a65aa25640e74..164e3f8d3c3dbb6eb4fc0ea60e01cae15fe5116e 100644 (file)
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val);
index 7bcb861a04e5cf5b32c2c26919756fa29353cb07..5a2ed3ed2f261893d5de08022ea3259198c8c0fe 100644 (file)
@@ -165,6 +165,7 @@ struct x86_pmu_capability {
 #define GLOBAL_STATUS_ASIF                             BIT_ULL(60)
 #define GLOBAL_STATUS_COUNTERS_FROZEN                  BIT_ULL(59)
 #define GLOBAL_STATUS_LBRS_FROZEN                      BIT_ULL(58)
+#define GLOBAL_STATUS_TRACE_TOPAPMI                    BIT_ULL(55)
 
 /*
  * IBS cpuid feature detection
index 8b2d4bea996273e1a72ee78aaa1a2b6358ccd189..39171b3646bba09d5c9a76e98632ae7339f6fbe8 100644 (file)
@@ -62,4 +62,6 @@ void xen_arch_register_cpu(int num);
 void xen_arch_unregister_cpu(int num);
 #endif
 
+extern void xen_set_iopl_mask(unsigned mask);
+
 #endif /* _ASM_X86_XEN_HYPERVISOR_H */
index a35f6b5473f48d8833bd549a80c799260df3dc6a..df6b4eeac0bde402207f321491880edfb588ed77 100644 (file)
@@ -211,6 +211,7 @@ update:
         */
        cpumask_and(d->old_domain, d->old_domain, cpu_online_mask);
        d->move_in_progress = !cpumask_empty(d->old_domain);
+       d->cfg.old_vector = d->move_in_progress ? d->cfg.vector : 0;
        d->cfg.vector = vector;
        cpumask_copy(d->domain, vector_cpumask);
 success:
@@ -253,7 +254,8 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data)
        struct irq_desc *desc;
        int cpu, vector;
 
-       BUG_ON(!data->cfg.vector);
+       if (!data->cfg.vector)
+               return;
 
        vector = data->cfg.vector;
        for_each_cpu_and(cpu, data->domain, cpu_online_mask)
@@ -653,46 +655,97 @@ void irq_complete_move(struct irq_cfg *cfg)
 }
 
 /*
- * Called with @desc->lock held and interrupts disabled.
+ * Called from fixup_irqs() with @desc->lock held and interrupts disabled.
  */
 void irq_force_complete_move(struct irq_desc *desc)
 {
        struct irq_data *irqdata = irq_desc_get_irq_data(desc);
        struct apic_chip_data *data = apic_chip_data(irqdata);
        struct irq_cfg *cfg = data ? &data->cfg : NULL;
+       unsigned int cpu;
 
        if (!cfg)
                return;
 
-       __irq_complete_move(cfg, cfg->vector);
-
        /*
         * This is tricky. If the cleanup of @data->old_domain has not been
         * done yet, then the following setaffinity call will fail with
         * -EBUSY. This can leave the interrupt in a stale state.
         *
-        * The cleanup cannot make progress because we hold @desc->lock. So in
-        * case @data->old_domain is not yet cleaned up, we need to drop the
-        * lock and acquire it again. @desc cannot go away, because the
-        * hotplug code holds the sparse irq lock.
+        * All CPUs are stuck in stop machine with interrupts disabled so
+        * calling __irq_complete_move() would be completely pointless.
         */
        raw_spin_lock(&vector_lock);
-       /* Clean out all offline cpus (including ourself) first. */
+       /*
+        * Clean out all offline cpus (including the outgoing one) from the
+        * old_domain mask.
+        */
        cpumask_and(data->old_domain, data->old_domain, cpu_online_mask);
-       while (!cpumask_empty(data->old_domain)) {
+
+       /*
+        * If move_in_progress is cleared and the old_domain mask is empty,
+        * then there is nothing to cleanup. fixup_irqs() will take care of
+        * the stale vectors on the outgoing cpu.
+        */
+       if (!data->move_in_progress && cpumask_empty(data->old_domain)) {
                raw_spin_unlock(&vector_lock);
-               raw_spin_unlock(&desc->lock);
-               cpu_relax();
-               raw_spin_lock(&desc->lock);
+               return;
+       }
+
+       /*
+        * 1) The interrupt is in move_in_progress state. That means that we
+        *    have not seen an interrupt since the io_apic was reprogrammed to
+        *    the new vector.
+        *
+        * 2) The interrupt has fired on the new vector, but the cleanup IPIs
+        *    have not been processed yet.
+        */
+       if (data->move_in_progress) {
                /*
-                * Reevaluate apic_chip_data. It might have been cleared after
-                * we dropped @desc->lock.
+                * In theory there is a race:
+                *
+                * set_ioapic(new_vector) <-- Interrupt is raised before update
+                *                            is effective, i.e. it's raised on
+                *                            the old vector.
+                *
+                * So if the target cpu cannot handle that interrupt before
+                * the old vector is cleaned up, we get a spurious interrupt
+                * and in the worst case the ioapic irq line becomes stale.
+                *
+                * But in case of cpu hotplug this should be a non issue
+                * because if the affinity update happens right before all
+                * cpus rendevouz in stop machine, there is no way that the
+                * interrupt can be blocked on the target cpu because all cpus
+                * loops first with interrupts enabled in stop machine, so the
+                * old vector is not yet cleaned up when the interrupt fires.
+                *
+                * So the only way to run into this issue is if the delivery
+                * of the interrupt on the apic/system bus would be delayed
+                * beyond the point where the target cpu disables interrupts
+                * in stop machine. I doubt that it can happen, but at least
+                * there is a theroretical chance. Virtualization might be
+                * able to expose this, but AFAICT the IOAPIC emulation is not
+                * as stupid as the real hardware.
+                *
+                * Anyway, there is nothing we can do about that at this point
+                * w/o refactoring the whole fixup_irq() business completely.
+                * We print at least the irq number and the old vector number,
+                * so we have the necessary information when a problem in that
+                * area arises.
                 */
-               data = apic_chip_data(irqdata);
-               if (!data)
-                       return;
-               raw_spin_lock(&vector_lock);
+               pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
+                       irqdata->irq, cfg->old_vector);
        }
+       /*
+        * If old_domain is not empty, then other cpus still have the irq
+        * descriptor set in their vector array. Clean it up.
+        */
+       for_each_cpu(cpu, data->old_domain)
+               per_cpu(vector_irq, cpu)[cfg->old_vector] = VECTOR_UNUSED;
+
+       /* Cleanup the left overs of the (half finished) move */
+       cpumask_clear(data->old_domain);
+       data->move_in_progress = 0;
        raw_spin_unlock(&vector_lock);
 }
 #endif
index 0a850100c5944641717c797e5d4f129b2cf9a79f..2658e2af74ec4c3f433b9958b4498d7f7d603fed 100644 (file)
@@ -29,7 +29,7 @@ static char gen_pool_buf[MCE_POOLSZ];
 void mce_gen_pool_process(void)
 {
        struct llist_node *head;
-       struct mce_evt_llist *node;
+       struct mce_evt_llist *node, *tmp;
        struct mce *mce;
 
        head = llist_del_all(&mce_event_llist);
@@ -37,7 +37,7 @@ void mce_gen_pool_process(void)
                return;
 
        head = llist_reverse_order(head);
-       llist_for_each_entry(node, head, llnode) {
+       llist_for_each_entry_safe(node, tmp, head, llnode) {
                mce = &node->mce;
                atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
                gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
index 2c5aaf8c2e2f3dcc94d348dfe91da6d7d5000ae9..05538582a809b54a230e1a1d97b0a85b40837f28 100644 (file)
@@ -385,6 +385,9 @@ static void intel_thermal_interrupt(void)
 {
        __u64 msr_val;
 
+       if (static_cpu_has(X86_FEATURE_HWP))
+               wrmsrl_safe(MSR_HWP_STATUS, 0);
+
        rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
 
        /* Check for violation of core thermal thresholds*/
index ce47402eb2f90a70f44b9902687133da3acbad47..ac8975a652804a19eed6f84528b7ac8c93b0fcc0 100644 (file)
@@ -555,10 +555,14 @@ scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd,
        cd.data = NULL;
        cd.size = 0;
 
-       cd = find_cpio_data(p, (void *)start, size, &offset);
-       if (!cd.data) {
+       /* try built-in microcode if no initrd */
+       if (!size) {
                if (!load_builtin_intel_microcode(&cd))
                        return UCODE_ERROR;
+       } else {
+               cd = find_cpio_data(p, (void *)start, size, &offset);
+               if (!cd.data)
+                       return UCODE_ERROR;
        }
 
        return get_matching_model_microcode(0, start, cd.data, cd.size,
@@ -694,7 +698,7 @@ int __init save_microcode_in_initrd_intel(void)
        if (count == 0)
                return ret;
 
-       copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, initrd_start, count);
+       copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, get_initrd_start(), count);
        ret = save_microcode(&mc_saved_data, mc_saved, count);
        if (ret)
                pr_err("Cannot save microcode patches from initrd.\n");
@@ -732,16 +736,20 @@ void __init load_ucode_intel_bsp(void)
        struct boot_params *p;
 
        p       = (struct boot_params *)__pa_nodebug(&boot_params);
-       start   = p->hdr.ramdisk_image;
        size    = p->hdr.ramdisk_size;
 
-       _load_ucode_intel_bsp(
-                       (struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
-                       (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
-                       start, size);
+       /*
+        * Set start only if we have an initrd image. We cannot use initrd_start
+        * because it is not set that early yet.
+        */
+       start   = (size ? p->hdr.ramdisk_image : 0);
+
+       _load_ucode_intel_bsp((struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
+                             (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
+                             start, size);
 #else
-       start   = boot_params.hdr.ramdisk_image + PAGE_OFFSET;
        size    = boot_params.hdr.ramdisk_size;
+       start   = (size ? boot_params.hdr.ramdisk_image + PAGE_OFFSET : 0);
 
        _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, start, size);
 #endif
@@ -752,20 +760,14 @@ void load_ucode_intel_ap(void)
        struct mc_saved_data *mc_saved_data_p;
        struct ucode_cpu_info uci;
        unsigned long *mc_saved_in_initrd_p;
-       unsigned long initrd_start_addr;
        enum ucode_state ret;
 #ifdef CONFIG_X86_32
-       unsigned long *initrd_start_p;
 
-       mc_saved_in_initrd_p =
-               (unsigned long *)__pa_nodebug(mc_saved_in_initrd);
+       mc_saved_in_initrd_p = (unsigned long *)__pa_nodebug(mc_saved_in_initrd);
        mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data);
-       initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);
-       initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p);
 #else
-       mc_saved_data_p = &mc_saved_data;
        mc_saved_in_initrd_p = mc_saved_in_initrd;
-       initrd_start_addr = initrd_start;
+       mc_saved_data_p = &mc_saved_data;
 #endif
 
        /*
@@ -777,7 +779,7 @@ void load_ucode_intel_ap(void)
 
        collect_cpu_info_early(&uci);
        ret = load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
-                            initrd_start_addr, &uci);
+                            get_initrd_start_addr(), &uci);
 
        if (ret != UCODE_OK)
                return;
index 2bf79d7c97dfb8848b1e7b060a66ddedb4605a1a..a3aeb2cc361e90827b9c06d3cec228f6b714676c 100644 (file)
@@ -593,6 +593,19 @@ void x86_pmu_disable_all(void)
        }
 }
 
+/*
+ * There may be PMI landing after enabled=0. The PMI hitting could be before or
+ * after disable_all.
+ *
+ * If PMI hits before disable_all, the PMU will be disabled in the NMI handler.
+ * It will not be re-enabled in the NMI handler again, because enabled=0. After
+ * handling the NMI, disable_all will be called, which will not change the
+ * state either. If PMI hits after disable_all, the PMU is already disabled
+ * before entering NMI handler. The NMI handler will not change the state
+ * either.
+ *
+ * So either situation is harmless.
+ */
 static void x86_pmu_disable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
index d0e35ebb2adb1d34b526fcb04b2bc192c643fd55..ee70445fbb1f7fe305a786accf82294523d911d1 100644 (file)
@@ -591,6 +591,7 @@ struct x86_pmu {
                        pebs_active     :1,
                        pebs_broken     :1;
        int             pebs_record_size;
+       int             pebs_buffer_size;
        void            (*drain_pebs)(struct pt_regs *regs);
        struct event_constraint *pebs_constraints;
        void            (*pebs_aliases)(struct perf_event *event);
@@ -907,6 +908,8 @@ void intel_pmu_lbr_init_hsw(void);
 
 void intel_pmu_lbr_init_skl(void);
 
+void intel_pmu_pebs_data_source_nhm(void);
+
 int intel_pmu_setup_lbr_filter(struct perf_event *event);
 
 void intel_pt_interrupt(void);
index e2a430021e46e71eb2904af74ae5a7d50653d048..078de2e86b7ab30a4cc1045dc0936b53295b66ee 100644 (file)
@@ -1458,7 +1458,15 @@ static __initconst const u64 slm_hw_cache_event_ids
 };
 
 /*
- * Use from PMIs where the LBRs are already disabled.
+ * Used from PMIs where the LBRs are already disabled.
+ *
+ * This function could be called consecutively. It is required to remain in
+ * disabled state if called consecutively.
+ *
+ * During consecutive calls, the same disable value will be written to related
+ * registers, so the PMU state remains unchanged. hw.state in
+ * intel_bts_disable_local will remain PERF_HES_STOPPED too in consecutive
+ * calls.
  */
 static void __intel_pmu_disable_all(void)
 {
@@ -1840,6 +1848,16 @@ again:
        if (__test_and_clear_bit(62, (unsigned long *)&status)) {
                handled++;
                x86_pmu.drain_pebs(regs);
+               /*
+                * There are cases where, even though, the PEBS ovfl bit is set
+                * in GLOBAL_OVF_STATUS, the PEBS events may also have their
+                * overflow bits set for their counters. We must clear them
+                * here because they have been processed as exact samples in
+                * the drain_pebs() routine. They must not be processed again
+                * in the for_each_bit_set() loop for regular samples below.
+                */
+               status &= ~cpuc->pebs_enabled;
+               status &= x86_pmu.intel_ctrl | GLOBAL_STATUS_TRACE_TOPAPMI;
        }
 
        /*
@@ -1885,7 +1903,10 @@ again:
                goto again;
 
 done:
-       __intel_pmu_enable_all(0, true);
+       /* Only restore PMU state when it's active. See x86_pmu_disable(). */
+       if (cpuc->enabled)
+               __intel_pmu_enable_all(0, true);
+
        /*
         * Only unmask the NMI after the overflow counters
         * have been reset. This avoids spurious NMIs on
@@ -3315,6 +3336,7 @@ __init int intel_pmu_init(void)
                intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
                        X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1);
 
+               intel_pmu_pebs_data_source_nhm();
                x86_add_quirk(intel_nehalem_quirk);
 
                pr_cont("Nehalem events, ");
@@ -3377,6 +3399,7 @@ __init int intel_pmu_init(void)
                intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
                        X86_CONFIG(.event=0xb1, .umask=0x3f, .inv=1, .cmask=1);
 
+               intel_pmu_pebs_data_source_nhm();
                pr_cont("Westmere events, ");
                break;
 
index 5db1c7755548e2ad472b2fbe5541125a45d90376..7abb2b88572e04425722a214e1ee3925fe429e34 100644 (file)
@@ -51,7 +51,8 @@ union intel_x86_pebs_dse {
 #define OP_LH (P(OP, LOAD) | P(LVL, HIT))
 #define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS))
 
-static const u64 pebs_data_source[] = {
+/* Version for Sandy Bridge and later */
+static u64 pebs_data_source[] = {
        P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */
        OP_LH | P(LVL, L1)  | P(SNOOP, NONE),   /* 0x01: L1 local */
        OP_LH | P(LVL, LFB) | P(SNOOP, NONE),   /* 0x02: LFB hit */
@@ -70,6 +71,14 @@ static const u64 pebs_data_source[] = {
        OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */
 };
 
+/* Patch up minor differences in the bits */
+void __init intel_pmu_pebs_data_source_nhm(void)
+{
+       pebs_data_source[0x05] = OP_LH | P(LVL, L3)  | P(SNOOP, HIT);
+       pebs_data_source[0x06] = OP_LH | P(LVL, L3)  | P(SNOOP, HITM);
+       pebs_data_source[0x07] = OP_LH | P(LVL, L3)  | P(SNOOP, HITM);
+}
+
 static u64 precise_store_data(u64 status)
 {
        union intel_x86_pebs_dse dse;
@@ -269,7 +278,7 @@ static int alloc_pebs_buffer(int cpu)
        if (!x86_pmu.pebs)
                return 0;
 
-       buffer = kzalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL, node);
+       buffer = kzalloc_node(x86_pmu.pebs_buffer_size, GFP_KERNEL, node);
        if (unlikely(!buffer))
                return -ENOMEM;
 
@@ -286,7 +295,7 @@ static int alloc_pebs_buffer(int cpu)
                per_cpu(insn_buffer, cpu) = ibuffer;
        }
 
-       max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
+       max = x86_pmu.pebs_buffer_size / x86_pmu.pebs_record_size;
 
        ds->pebs_buffer_base = (u64)(unsigned long)buffer;
        ds->pebs_index = ds->pebs_buffer_base;
@@ -1296,6 +1305,7 @@ void __init intel_ds_init(void)
 
        x86_pmu.bts  = boot_cpu_has(X86_FEATURE_BTS);
        x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS);
+       x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
        if (x86_pmu.pebs) {
                char pebs_type = x86_pmu.intel_cap.pebs_trap ?  '+' : '-';
                int format = x86_pmu.intel_cap.pebs_format;
@@ -1304,6 +1314,14 @@ void __init intel_ds_init(void)
                case 0:
                        printk(KERN_CONT "PEBS fmt0%c, ", pebs_type);
                        x86_pmu.pebs_record_size = sizeof(struct pebs_record_core);
+                       /*
+                        * Using >PAGE_SIZE buffers makes the WRMSR to
+                        * PERF_GLOBAL_CTRL in intel_pmu_enable_all()
+                        * mysteriously hang on Core2.
+                        *
+                        * As a workaround, we don't do this.
+                        */
+                       x86_pmu.pebs_buffer_size = PAGE_SIZE;
                        x86_pmu.drain_pebs = intel_pmu_drain_pebs_core;
                        break;
 
index 5b0c232d1ee62e3e50223ba1d8ac27364e2d1ad5..b931095e86d4947a4c52f4a6ed983b7a076d8b00 100644 (file)
@@ -263,7 +263,9 @@ again:
                goto again;
 
 done:
-       knc_pmu_enable_all(0);
+       /* Only restore PMU state when it's active. See x86_pmu_disable(). */
+       if (cpuc->enabled)
+               knc_pmu_enable_all(0);
 
        return handled;
 }
index 37dae792dbbed00b480aa67a33cb0b2ae1699428..589b3193f1020b8389a5f64b296cff531e85e849 100644 (file)
@@ -96,9 +96,14 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 SYSCALL_DEFINE1(iopl, unsigned int, level)
 {
        struct pt_regs *regs = current_pt_regs();
-       unsigned int old = (regs->flags >> 12) & 3;
        struct thread_struct *t = &current->thread;
 
+       /*
+        * Careful: the IOPL bits in regs->flags are undefined under Xen PV
+        * and changing them has no effect.
+        */
+       unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT;
+
        if (level > 3)
                return -EINVAL;
        /* Trying to gain more privileges? */
@@ -106,8 +111,9 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
                if (!capable(CAP_SYS_RAWIO))
                        return -EPERM;
        }
-       regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
-       t->iopl = level << 12;
+       regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
+               (level << X86_EFLAGS_IOPL_BIT);
+       t->iopl = level << X86_EFLAGS_IOPL_BIT;
        set_iopl_mask(t->iopl);
 
        return 0;
index e835d263a33b43ccf7601698cfeadc447ede491e..4cbb60fbff3e361f3e1931a4ab6dae26363db871 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/syscalls.h>
 #include <asm/debugreg.h>
 #include <asm/switch_to.h>
+#include <asm/xen/hypervisor.h>
 
 asmlinkage extern void ret_from_fork(void);
 
@@ -411,6 +412,17 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                     task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV))
                __switch_to_xtra(prev_p, next_p, tss);
 
+#ifdef CONFIG_XEN
+       /*
+        * On Xen PV, IOPL bits in pt_regs->flags have no effect, and
+        * current_pt_regs()->flags may not match the current task's
+        * intended IOPL.  We need to switch it manually.
+        */
+       if (unlikely(static_cpu_has(X86_FEATURE_XENPV) &&
+                    prev->iopl != next->iopl))
+               xen_set_iopl_mask(next->iopl);
+#endif
+
        if (static_cpu_has_bug(X86_BUG_SYSRET_SS_ATTRS)) {
                /*
                 * AMD CPUs have a misfeature: SYSRET sets the SS selector but
index b285d4e8c68e33bf3d4f2b070fdbcbbce7036d9a..5da924bbf0a0f22aa676f5be5a3f97fe4811b087 100644 (file)
@@ -106,14 +106,24 @@ static int __init efifb_set_system(const struct dmi_system_id *id)
                                        continue;
                                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
                                        resource_size_t start, end;
+                                       unsigned long flags;
+
+                                       flags = pci_resource_flags(dev, i);
+                                       if (!(flags & IORESOURCE_MEM))
+                                               continue;
+
+                                       if (flags & IORESOURCE_UNSET)
+                                               continue;
+
+                                       if (pci_resource_len(dev, i) == 0)
+                                               continue;
 
                                        start = pci_resource_start(dev, i);
-                                       if (start == 0)
-                                               break;
                                        end = pci_resource_end(dev, i);
                                        if (screen_info.lfb_base >= start &&
                                            screen_info.lfb_base < end) {
                                                found_bar = 1;
+                                               break;
                                        }
                                }
                        }
index 92ae6acac8a7fbcb9b91cb386b3c23015c5377ea..6aa0f4d9eea6816bbf0c78514e0b76d8f4dc7def 100644 (file)
@@ -92,7 +92,7 @@ unsigned long try_msr_calibrate_tsc(void)
 
        if (freq_desc_tables[cpu_index].msr_plat) {
                rdmsr(MSR_PLATFORM_INFO, lo, hi);
-               ratio = (lo >> 8) & 0x1f;
+               ratio = (lo >> 8) & 0xff;
        } else {
                rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
                ratio = (hi >> 8) & 0x1f;
index b0ea42b78ccdb50879a10c440d5e3a7fe194fbe9..ab531872757944c6beb8321b97b88e3c74be9afe 100644 (file)
@@ -245,7 +245,7 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
                 * PIC is being reset.  Handle it gracefully here
                 */
                atomic_inc(&ps->pending);
-       else if (value > 0)
+       else if (value > 0 && ps->reinject)
                /* in this case, we had multiple outstanding pit interrupts
                 * that we needed to inject.  Reinject
                 */
@@ -288,7 +288,9 @@ static void pit_do_work(struct kthread_work *work)
         * last one has been acked.
         */
        spin_lock(&ps->inject_lock);
-       if (ps->irq_ack) {
+       if (!ps->reinject)
+               inject = 1;
+       else if (ps->irq_ack) {
                ps->irq_ack = 0;
                inject = 1;
        }
@@ -317,10 +319,10 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
        struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer);
        struct kvm_pit *pt = ps->kvm->arch.vpit;
 
-       if (ps->reinject || !atomic_read(&ps->pending)) {
+       if (ps->reinject)
                atomic_inc(&ps->pending);
-               queue_kthread_work(&pt->worker, &pt->expired);
-       }
+
+       queue_kthread_work(&pt->worker, &pt->expired);
 
        if (ps->is_periodic) {
                hrtimer_add_expires_ns(&ps->timer, ps->period);
index 0958fa2b7cb727195cd0e855503eb54c413a5767..f34ab71dfd57786e031ca2caf1fd4ff8b4e80482 100644 (file)
@@ -2637,8 +2637,15 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
        } else
                vmx->nested.nested_vmx_ept_caps = 0;
 
+       /*
+        * Old versions of KVM use the single-context version without
+        * checking for support, so declare that it is supported even
+        * though it is treated as global context.  The alternative is
+        * not failing the single-context invvpid, and it is worse.
+        */
        if (enable_vpid)
                vmx->nested.nested_vmx_vpid_caps = VMX_VPID_INVVPID_BIT |
+                               VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |
                                VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
        else
                vmx->nested.nested_vmx_vpid_caps = 0;
@@ -7340,6 +7347,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
        if (!(types & (1UL << type))) {
                nested_vmx_failValid(vcpu,
                                VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+               skip_emulated_instruction(vcpu);
                return 1;
        }
 
@@ -7398,6 +7406,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
        if (!(types & (1UL << type))) {
                nested_vmx_failValid(vcpu,
                        VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+               skip_emulated_instruction(vcpu);
                return 1;
        }
 
@@ -7414,12 +7423,17 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
        }
 
        switch (type) {
+       case VMX_VPID_EXTENT_SINGLE_CONTEXT:
+               /*
+                * Old versions of KVM use the single-context version so we
+                * have to support it; just treat it the same as all-context.
+                */
        case VMX_VPID_EXTENT_ALL_CONTEXT:
                __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
                nested_vmx_succeed(vcpu);
                break;
        default:
-               /* Trap single context invalidation invvpid calls */
+               /* Trap individual address invalidation invvpid calls */
                BUG_ON(1);
                break;
        }
index d2945024ed3378bd9e12ee35fc541c86d10b2963..605cea75eb0d1862f83e885af1efa55c5582707c 100644 (file)
@@ -697,7 +697,6 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
                if ((xcr0 & XFEATURE_MASK_AVX512) != XFEATURE_MASK_AVX512)
                        return 1;
        }
-       kvm_put_guest_xcr0(vcpu);
        vcpu->arch.xcr0 = xcr0;
 
        if ((xcr0 ^ old_xcr0) & XFEATURE_MASK_EXTEND)
@@ -2736,6 +2735,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        }
 
        kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
+       vcpu->arch.switch_db_regs |= KVM_DEBUGREG_RELOAD;
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -6023,12 +6023,10 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
        }
 
        /* try to inject new event if pending */
-       if (vcpu->arch.nmi_pending) {
-               if (kvm_x86_ops->nmi_allowed(vcpu)) {
-                       --vcpu->arch.nmi_pending;
-                       vcpu->arch.nmi_injected = true;
-                       kvm_x86_ops->set_nmi(vcpu);
-               }
+       if (vcpu->arch.nmi_pending && kvm_x86_ops->nmi_allowed(vcpu)) {
+               --vcpu->arch.nmi_pending;
+               vcpu->arch.nmi_injected = true;
+               kvm_x86_ops->set_nmi(vcpu);
        } else if (kvm_cpu_has_injectable_intr(vcpu)) {
                /*
                 * Because interrupts can be injected asynchronously, we are
@@ -6473,10 +6471,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                if (inject_pending_event(vcpu, req_int_win) != 0)
                        req_immediate_exit = true;
                /* enable NMI/IRQ window open exits if needed */
-               else if (vcpu->arch.nmi_pending)
-                       kvm_x86_ops->enable_nmi_window(vcpu);
-               else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
-                       kvm_x86_ops->enable_irq_window(vcpu);
+               else {
+                       if (vcpu->arch.nmi_pending)
+                               kvm_x86_ops->enable_nmi_window(vcpu);
+                       if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
+                               kvm_x86_ops->enable_irq_window(vcpu);
+               }
 
                if (kvm_lapic_enabled(vcpu)) {
                        update_cr8_intercept(vcpu);
@@ -6494,8 +6494,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        kvm_x86_ops->prepare_guest_switch(vcpu);
        if (vcpu->fpu_active)
                kvm_load_guest_fpu(vcpu);
-       kvm_load_guest_xcr0(vcpu);
-
        vcpu->mode = IN_GUEST_MODE;
 
        srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
@@ -6518,6 +6516,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                goto cancel_injection;
        }
 
+       kvm_load_guest_xcr0(vcpu);
+
        if (req_immediate_exit)
                smp_send_reschedule(vcpu->cpu);
 
@@ -6567,6 +6567,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
        vcpu->mode = OUTSIDE_GUEST_MODE;
        smp_wmb();
 
+       kvm_put_guest_xcr0(vcpu);
+
        /* Interrupt is enabled by handle_external_intr() */
        kvm_x86_ops->handle_external_intr(vcpu);
 
@@ -7214,7 +7216,6 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
         * and assume host would use all available bits.
         * Guest xcr0 would be loaded later.
         */
-       kvm_put_guest_xcr0(vcpu);
        vcpu->guest_fpu_loaded = 1;
        __kernel_fpu_begin();
        __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state);
@@ -7223,8 +7224,6 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
 {
-       kvm_put_guest_xcr0(vcpu);
-
        if (!vcpu->guest_fpu_loaded) {
                vcpu->fpu_counter = 0;
                return;
index 637ab34ed63284d1045f6031104aac7665be6427..ddb2244b06a1d618679d83a9133f72e8d884b3a2 100644 (file)
@@ -33,7 +33,7 @@
 struct kmmio_fault_page {
        struct list_head list;
        struct kmmio_fault_page *release_next;
-       unsigned long page; /* location of the fault page */
+       unsigned long addr; /* the requested address */
        pteval_t old_presence; /* page presence prior to arming */
        bool armed;
 
@@ -70,9 +70,16 @@ unsigned int kmmio_count;
 static struct list_head kmmio_page_table[KMMIO_PAGE_TABLE_SIZE];
 static LIST_HEAD(kmmio_probes);
 
-static struct list_head *kmmio_page_list(unsigned long page)
+static struct list_head *kmmio_page_list(unsigned long addr)
 {
-       return &kmmio_page_table[hash_long(page, KMMIO_PAGE_HASH_BITS)];
+       unsigned int l;
+       pte_t *pte = lookup_address(addr, &l);
+
+       if (!pte)
+               return NULL;
+       addr &= page_level_mask(l);
+
+       return &kmmio_page_table[hash_long(addr, KMMIO_PAGE_HASH_BITS)];
 }
 
 /* Accessed per-cpu */
@@ -98,15 +105,19 @@ static struct kmmio_probe *get_kmmio_probe(unsigned long addr)
 }
 
 /* You must be holding RCU read lock. */
-static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page)
+static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long addr)
 {
        struct list_head *head;
        struct kmmio_fault_page *f;
+       unsigned int l;
+       pte_t *pte = lookup_address(addr, &l);
 
-       page &= PAGE_MASK;
-       head = kmmio_page_list(page);
+       if (!pte)
+               return NULL;
+       addr &= page_level_mask(l);
+       head = kmmio_page_list(addr);
        list_for_each_entry_rcu(f, head, list) {
-               if (f->page == page)
+               if (f->addr == addr)
                        return f;
        }
        return NULL;
@@ -137,10 +148,10 @@ static void clear_pte_presence(pte_t *pte, bool clear, pteval_t *old)
 static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
 {
        unsigned int level;
-       pte_t *pte = lookup_address(f->page, &level);
+       pte_t *pte = lookup_address(f->addr, &level);
 
        if (!pte) {
-               pr_err("no pte for page 0x%08lx\n", f->page);
+               pr_err("no pte for addr 0x%08lx\n", f->addr);
                return -1;
        }
 
@@ -156,7 +167,7 @@ static int clear_page_presence(struct kmmio_fault_page *f, bool clear)
                return -1;
        }
 
-       __flush_tlb_one(f->page);
+       __flush_tlb_one(f->addr);
        return 0;
 }
 
@@ -176,12 +187,12 @@ static int arm_kmmio_fault_page(struct kmmio_fault_page *f)
        int ret;
        WARN_ONCE(f->armed, KERN_ERR pr_fmt("kmmio page already armed.\n"));
        if (f->armed) {
-               pr_warning("double-arm: page 0x%08lx, ref %d, old %d\n",
-                          f->page, f->count, !!f->old_presence);
+               pr_warning("double-arm: addr 0x%08lx, ref %d, old %d\n",
+                          f->addr, f->count, !!f->old_presence);
        }
        ret = clear_page_presence(f, true);
-       WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming 0x%08lx failed.\n"),
-                 f->page);
+       WARN_ONCE(ret < 0, KERN_ERR pr_fmt("arming at 0x%08lx failed.\n"),
+                 f->addr);
        f->armed = true;
        return ret;
 }
@@ -191,7 +202,7 @@ static void disarm_kmmio_fault_page(struct kmmio_fault_page *f)
 {
        int ret = clear_page_presence(f, false);
        WARN_ONCE(ret < 0,
-                       KERN_ERR "kmmio disarming 0x%08lx failed.\n", f->page);
+                       KERN_ERR "kmmio disarming at 0x%08lx failed.\n", f->addr);
        f->armed = false;
 }
 
@@ -215,6 +226,12 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
        struct kmmio_context *ctx;
        struct kmmio_fault_page *faultpage;
        int ret = 0; /* default to fault not handled */
+       unsigned long page_base = addr;
+       unsigned int l;
+       pte_t *pte = lookup_address(addr, &l);
+       if (!pte)
+               return -EINVAL;
+       page_base &= page_level_mask(l);
 
        /*
         * Preemption is now disabled to prevent process switch during
@@ -227,7 +244,7 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
        preempt_disable();
        rcu_read_lock();
 
-       faultpage = get_kmmio_fault_page(addr);
+       faultpage = get_kmmio_fault_page(page_base);
        if (!faultpage) {
                /*
                 * Either this page fault is not caused by kmmio, or
@@ -239,7 +256,7 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
 
        ctx = &get_cpu_var(kmmio_ctx);
        if (ctx->active) {
-               if (addr == ctx->addr) {
+               if (page_base == ctx->addr) {
                        /*
                         * A second fault on the same page means some other
                         * condition needs handling by do_page_fault(), the
@@ -267,9 +284,9 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
        ctx->active++;
 
        ctx->fpage = faultpage;
-       ctx->probe = get_kmmio_probe(addr);
+       ctx->probe = get_kmmio_probe(page_base);
        ctx->saved_flags = (regs->flags & (X86_EFLAGS_TF | X86_EFLAGS_IF));
-       ctx->addr = addr;
+       ctx->addr = page_base;
 
        if (ctx->probe && ctx->probe->pre_handler)
                ctx->probe->pre_handler(ctx->probe, regs, addr);
@@ -354,12 +371,11 @@ out:
 }
 
 /* You must be holding kmmio_lock. */
-static int add_kmmio_fault_page(unsigned long page)
+static int add_kmmio_fault_page(unsigned long addr)
 {
        struct kmmio_fault_page *f;
 
-       page &= PAGE_MASK;
-       f = get_kmmio_fault_page(page);
+       f = get_kmmio_fault_page(addr);
        if (f) {
                if (!f->count)
                        arm_kmmio_fault_page(f);
@@ -372,26 +388,25 @@ static int add_kmmio_fault_page(unsigned long page)
                return -1;
 
        f->count = 1;
-       f->page = page;
+       f->addr = addr;
 
        if (arm_kmmio_fault_page(f)) {
                kfree(f);
                return -1;
        }
 
-       list_add_rcu(&f->list, kmmio_page_list(f->page));
+       list_add_rcu(&f->list, kmmio_page_list(f->addr));
 
        return 0;
 }
 
 /* You must be holding kmmio_lock. */
-static void release_kmmio_fault_page(unsigned long page,
+static void release_kmmio_fault_page(unsigned long addr,
                                struct kmmio_fault_page **release_list)
 {
        struct kmmio_fault_page *f;
 
-       page &= PAGE_MASK;
-       f = get_kmmio_fault_page(page);
+       f = get_kmmio_fault_page(addr);
        if (!f)
                return;
 
@@ -420,18 +435,27 @@ int register_kmmio_probe(struct kmmio_probe *p)
        int ret = 0;
        unsigned long size = 0;
        const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
+       unsigned int l;
+       pte_t *pte;
 
        spin_lock_irqsave(&kmmio_lock, flags);
        if (get_kmmio_probe(p->addr)) {
                ret = -EEXIST;
                goto out;
        }
+
+       pte = lookup_address(p->addr, &l);
+       if (!pte) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        kmmio_count++;
        list_add_rcu(&p->list, &kmmio_probes);
        while (size < size_lim) {
                if (add_kmmio_fault_page(p->addr + size))
                        pr_err("Unable to set page fault.\n");
-               size += PAGE_SIZE;
+               size += page_level_size(l);
        }
 out:
        spin_unlock_irqrestore(&kmmio_lock, flags);
@@ -506,11 +530,17 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
        const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
        struct kmmio_fault_page *release_list = NULL;
        struct kmmio_delayed_release *drelease;
+       unsigned int l;
+       pte_t *pte;
+
+       pte = lookup_address(p->addr, &l);
+       if (!pte)
+               return;
 
        spin_lock_irqsave(&kmmio_lock, flags);
        while (size < size_lim) {
                release_kmmio_fault_page(p->addr + size, &release_list);
-               size += PAGE_SIZE;
+               size += page_level_size(l);
        }
        list_del_rcu(&p->list);
        kmmio_count--;
index 8f4cc3dfac322a2911ab2b2e8471c6e8e87d8af0..5fb6adaaa7964d68c1bd7cbc81d6c2ed6bd44bcd 100644 (file)
@@ -106,8 +106,6 @@ static void flush_tlb_func(void *info)
 
        if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
                return;
-       if (!f->flush_end)
-               f->flush_end = f->flush_start + PAGE_SIZE;
 
        count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
        if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
@@ -135,12 +133,20 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
                                 unsigned long end)
 {
        struct flush_tlb_info info;
+
+       if (end == 0)
+               end = start + PAGE_SIZE;
        info.flush_mm = mm;
        info.flush_start = start;
        info.flush_end = end;
 
        count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
-       trace_tlb_flush(TLB_REMOTE_SEND_IPI, end - start);
+       if (end == TLB_FLUSH_ALL)
+               trace_tlb_flush(TLB_REMOTE_SEND_IPI, TLB_FLUSH_ALL);
+       else
+               trace_tlb_flush(TLB_REMOTE_SEND_IPI,
+                               (end - start) >> PAGE_SHIFT);
+
        if (is_uv_system()) {
                unsigned int cpu;
 
index eccd4d99e6a4a7182bf74469f5ecd580e8f22417..8fd6f44aee8370958076fb4a8af3e13a2781fe33 100644 (file)
@@ -673,28 +673,22 @@ int pcibios_add_device(struct pci_dev *dev)
        return 0;
 }
 
-int pcibios_alloc_irq(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-       /*
-        * If the PCI device was already claimed by core code and has
-        * MSI enabled, probing of the pcibios IRQ will overwrite
-        * dev->irq.  So bail out if MSI is already enabled.
-        */
-       if (pci_dev_msi_enabled(dev))
-               return -EBUSY;
+       int err;
 
-       return pcibios_enable_irq(dev);
-}
+       if ((err = pci_enable_resources(dev, mask)) < 0)
+               return err;
 
-void pcibios_free_irq(struct pci_dev *dev)
-{
-       if (pcibios_disable_irq)
-               pcibios_disable_irq(dev);
+       if (!pci_dev_msi_enabled(dev))
+               return pcibios_enable_irq(dev);
+       return 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
+void pcibios_disable_device (struct pci_dev *dev)
 {
-       return pci_enable_resources(dev, mask);
+       if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+               pcibios_disable_irq(dev);
 }
 
 int pci_ext_cfg_avail(void)
index e58565556703bfc781e29f4e387cbd0e2ea1ced8..0ae7e9fa348dfaf04de014e4e5c17b13b8c8e0b1 100644 (file)
@@ -540,3 +540,10 @@ static void twinhead_reserve_killing_zone(struct pci_dev *dev)
         }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
+
+static void pci_bdwep_bar(struct pci_dev *dev)
+{
+       dev->non_compliant_bars = 1;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_bdwep_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_bdwep_bar);
index 0d24e7c101454057f432dd976ea7e3d537e0a38c..8b93e634af84c4698e6f7c6ab718a018e2cdc9db 100644 (file)
@@ -215,7 +215,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
        int polarity;
        int ret;
 
-       if (pci_has_managed_irq(dev))
+       if (dev->irq_managed && dev->irq > 0)
                return 0;
 
        switch (intel_mid_identify_cpu()) {
@@ -256,13 +256,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (pci_has_managed_irq(dev)) {
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+           dev->irq > 0) {
                mp_unmap_irq(dev->irq);
                dev->irq_managed = 0;
-               /*
-                * Don't reset dev->irq here, otherwise
-                * intel_mid_pci_irq_enable() will fail on next call.
-                */
        }
 }
 
index 32e70343e6fdd0e58ab80644284dd01000dccd82..9bd115484745703791c6515b289938546d2478ab 100644 (file)
@@ -1202,7 +1202,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
                        struct pci_dev *temp_dev;
                        int irq;
 
-                       if (pci_has_managed_irq(dev))
+                       if (dev->irq_managed && dev->irq > 0)
                                return 0;
 
                        irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
@@ -1230,7 +1230,8 @@ static int pirq_enable_irq(struct pci_dev *dev)
                        }
                        dev = temp_dev;
                        if (irq >= 0) {
-                               pci_set_managed_irq(dev, irq);
+                               dev->irq_managed = 1;
+                               dev->irq = irq;
                                dev_info(&dev->dev, "PCI->APIC IRQ transform: "
                                         "INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
                                return 0;
@@ -1256,10 +1257,24 @@ static int pirq_enable_irq(struct pci_dev *dev)
        return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && pci_has_managed_irq(dev)) {
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+           dev->irq_managed && dev->irq) {
                mp_unmap_irq(dev->irq);
-               pci_reset_managed_irq(dev);
+               dev->irq = 0;
+               dev->irq_managed = 0;
        }
 }
index b7de78bdc09c12b3e6cea070e4d35b346d24c8be..beab8c706ac95070f02b683df74b056f0d53ca64 100644 (file)
@@ -961,7 +961,7 @@ static void xen_load_sp0(struct tss_struct *tss,
        tss->x86_tss.sp0 = thread->sp0;
 }
 
-static void xen_set_iopl_mask(unsigned mask)
+void xen_set_iopl_mask(unsigned mask)
 {
        struct physdev_set_iopl set_iopl;
 
index 9ed55649ac8ef1d8e6befae8f5d50498f6f5f35b..05e1df943856fbe449d77177d5f1e0eeaf734776 100644 (file)
@@ -128,7 +128,7 @@ ENTRY(_startup)
        wsr     a0, icountlevel
 
        .set    _index, 0
-       .rept   XCHAL_NUM_DBREAK - 1
+       .rept   XCHAL_NUM_DBREAK
        wsr     a0, SREG_DBREAKC + _index
        .set    _index, _index + 1
        .endr
index d75aa1476da7595d224c02576a8ee5fcb3fe716e..1a804a2f9a5be6212c57febc01f6d28f47b8c91a 100644 (file)
@@ -97,11 +97,11 @@ void clear_user_highpage(struct page *page, unsigned long vaddr)
        unsigned long paddr;
        void *kvaddr = coherent_kvaddr(page, TLBTEMP_BASE_1, vaddr, &paddr);
 
-       pagefault_disable();
+       preempt_disable();
        kmap_invalidate_coherent(page, vaddr);
        set_bit(PG_arch_1, &page->flags);
        clear_page_alias(kvaddr, paddr);
-       pagefault_enable();
+       preempt_enable();
 }
 
 void copy_user_highpage(struct page *dst, struct page *src,
@@ -113,11 +113,11 @@ void copy_user_highpage(struct page *dst, struct page *src,
        void *src_vaddr = coherent_kvaddr(src, TLBTEMP_BASE_2, vaddr,
                                          &src_paddr);
 
-       pagefault_disable();
+       preempt_disable();
        kmap_invalidate_coherent(dst, vaddr);
        set_bit(PG_arch_1, &dst->flags);
        copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
-       pagefault_enable();
+       preempt_enable();
 }
 
 #endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
index 70cb408bc20dc8fc593fbbcebf68d3a06cb967b0..92d785fefb6d0634db9ef891f0ffbedbe2421a40 100644 (file)
@@ -100,21 +100,23 @@ static void rs_poll(unsigned long priv)
 {
        struct tty_port *port = (struct tty_port *)priv;
        int i = 0;
+       int rd = 1;
        unsigned char c;
 
        spin_lock(&timer_lock);
 
        while (simc_poll(0)) {
-               simc_read(0, &c, 1);
+               rd = simc_read(0, &c, 1);
+               if (rd <= 0)
+                       break;
                tty_insert_flip_char(port, c, TTY_NORMAL);
                i++;
        }
 
        if (i)
                tty_flip_buffer_push(port);
-
-
-       mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
+       if (rd)
+               mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
        spin_unlock(&timer_lock);
 }
 
index 33e2f62d50622ea8b40153175d0f44d96df399a6..f8e64cac981ae4cb8d5e7860eeef257d53d8ce53 100644 (file)
@@ -2189,7 +2189,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
        if (q->mq_ops) {
                if (blk_queue_io_stat(q))
                        blk_account_io_start(rq, true);
-               blk_mq_insert_request(rq, false, true, true);
+               blk_mq_insert_request(rq, false, true, false);
                return 0;
        }
 
index ae95e963c5bb15df14a96b77a50c8a9302f23f53..91327dbfbb1d5f61002b6028914fc2e4bb81d1da 100644 (file)
@@ -360,15 +360,20 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
                        goto out_del;
        }
 
+       err = hd_ref_init(p);
+       if (err) {
+               if (flags & ADDPART_FLAG_WHOLEDISK)
+                       goto out_remove_file;
+               goto out_del;
+       }
+
        /* everything is up and running, commence */
        rcu_assign_pointer(ptbl->part[partno], p);
 
        /* suppress uevent if the disk suppresses it */
        if (!dev_get_uevent_suppress(ddev))
                kobject_uevent(&pdev->kobj, KOBJ_ADD);
-
-       if (!hd_ref_init(p))
-               return p;
+       return p;
 
 out_free_info:
        free_part_info(p);
@@ -377,6 +382,8 @@ out_free_stats:
 out_free:
        kfree(p);
        return ERR_PTR(err);
+out_remove_file:
+       device_remove_file(pdev, &dev_attr_whole_disk);
 out_del:
        kobject_put(p->holder_dir);
        device_del(pdev);
index 90d6d47965b0826d40e795bc68f563aa2f033856..ecdb5a2ce085844dcdcc25a3032582b955cf410c 100644 (file)
@@ -178,6 +178,8 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
        int cached_ret = -ENOKEY;
        int ret;
 
+       *_trusted = false;
+
        for (p = pkcs7->certs; p; p = p->next)
                p->seen = false;
 
index 021d39c0ba75a8ce3c8c6cb4ea2c41cddd954ad7..13c4e5a5fe8c47b546bc34cbc109279dfa81fb4a 100644 (file)
@@ -494,7 +494,7 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
                     unsigned char tag,
                     const unsigned char *value, size_t vlen)
 {
-       static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30,
+       static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
                                                       31, 31, 30, 31, 30, 31 };
        const unsigned char *p = value;
        unsigned year, mon, day, hour, min, sec, mon_len;
@@ -540,9 +540,9 @@ int x509_decode_time(time64_t *_t,  size_t hdrlen,
                if (year % 4 == 0) {
                        mon_len = 29;
                        if (year % 100 == 0) {
-                               year /= 100;
-                               if (year % 4 != 0)
-                                       mon_len = 28;
+                               mon_len = 28;
+                               if (year % 400 == 0)
+                                       mon_len = 29;
                        }
                }
        }
index b1d106ce55f3d9c98bba9a54f301d4d94f12d982..72014f963ba7a65cbb3dd856a63f25ab647c3209 100644 (file)
@@ -212,7 +212,7 @@ static int crypto_kw_decrypt(struct blkcipher_desc *desc,
                          SEMIBSIZE))
                ret = -EBADMSG;
 
-       memzero_explicit(&block, sizeof(struct crypto_kw_block));
+       memzero_explicit(block, sizeof(struct crypto_kw_block));
 
        return ret;
 }
@@ -297,7 +297,7 @@ static int crypto_kw_encrypt(struct blkcipher_desc *desc,
        /* establish the IV for the caller to pick up */
        memcpy(desc->info, block->A, SEMIBSIZE);
 
-       memzero_explicit(&block, sizeof(struct crypto_kw_block));
+       memzero_explicit(block, sizeof(struct crypto_kw_block));
 
        return 0;
 }
index 6979186dbd4b45bd19b60b51d4fd76c76abd683f..9f77943653fb70f4393fe82bb630adfe687d3142 100644 (file)
@@ -491,6 +491,58 @@ static void acpi_processor_remove(struct acpi_device *device)
 }
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
+#ifdef CONFIG_X86
+static bool acpi_hwp_native_thermal_lvt_set;
+static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle,
+                                                         u32 lvl,
+                                                         void *context,
+                                                         void **rv)
+{
+       u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953";
+       u32 capbuf[2];
+       struct acpi_osc_context osc_context = {
+               .uuid_str = sb_uuid_str,
+               .rev = 1,
+               .cap.length = 8,
+               .cap.pointer = capbuf,
+       };
+
+       if (acpi_hwp_native_thermal_lvt_set)
+               return AE_CTRL_TERMINATE;
+
+       capbuf[0] = 0x0000;
+       capbuf[1] = 0x1000; /* set bit 12 */
+
+       if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) {
+               if (osc_context.ret.pointer && osc_context.ret.length > 1) {
+                       u32 *capbuf_ret = osc_context.ret.pointer;
+
+                       if (capbuf_ret[1] & 0x1000) {
+                               acpi_handle_info(handle,
+                                       "_OSC native thermal LVT Acked\n");
+                               acpi_hwp_native_thermal_lvt_set = true;
+                       }
+               }
+               kfree(osc_context.ret.pointer);
+       }
+
+       return AE_OK;
+}
+
+void __init acpi_early_processor_osc(void)
+{
+       if (boot_cpu_has(X86_FEATURE_HWP)) {
+               acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+                                   ACPI_UINT32_MAX,
+                                   acpi_hwp_native_thermal_lvt_osc,
+                                   NULL, NULL, NULL);
+               acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID,
+                                acpi_hwp_native_thermal_lvt_osc,
+                                NULL, NULL);
+       }
+}
+#endif
+
 /*
  * The following ACPI IDs are known to be suitable for representing as
  * processor devices.
index bc32f3194afe1675bdc767d9f1dbd26a2959b3aa..28c50c6b5f4525bd9dc2a658bff870f099c892e9 100644 (file)
@@ -417,6 +417,9 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
                                obj_desc->method.mutex->mutex.
                                    original_sync_level =
                                    obj_desc->method.mutex->mutex.sync_level;
+
+                               obj_desc->method.mutex->mutex.thread_id =
+                                   acpi_os_get_thread_id();
                        }
                }
 
index a212cefae524f8d2daaa2b4161ee16c2fae90cf8..ca4f28432d87a8dcf2ecd4504a0fdde9e61ff40b 100644 (file)
@@ -1004,6 +1004,9 @@ static int __init acpi_bus_init(void)
                goto error1;
        }
 
+       /* Set capability bits for _OSC under processor scope */
+       acpi_early_processor_osc();
+
        /*
         * _OSC method may exist in module level code,
         * so it must be run after ACPI_FULL_INITIALIZATION
index 11d87bf67e738ce7e7a07541993b92bbb66e423a..0f3f41c13b38c18b75fde119af64acf7aa731589 100644 (file)
@@ -130,6 +130,12 @@ void acpi_early_processor_set_pdc(void);
 static inline void acpi_early_processor_set_pdc(void) {}
 #endif
 
+#ifdef CONFIG_X86
+void acpi_early_processor_osc(void);
+#else
+static inline void acpi_early_processor_osc(void) {}
+#endif
+
 /* --------------------------------------------------------------------------
                                   Embedded Controller
    -------------------------------------------------------------------------- */
index c9336751e5e3708f96e9f972ab05fc5454970adb..8a10a7ae6a8ad8780e76e46a8522044d41e91f96 100644 (file)
@@ -409,7 +409,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                return 0;
        }
 
-       if (pci_has_managed_irq(dev))
+       if (dev->irq_managed && dev->irq > 0)
                return 0;
 
        entry = acpi_pci_irq_lookup(dev, pin);
@@ -454,7 +454,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                kfree(entry);
                return rc;
        }
-       pci_set_managed_irq(dev, rc);
+       dev->irq = rc;
+       dev->irq_managed = 1;
 
        if (link)
                snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
@@ -477,9 +478,17 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        u8 pin;
 
        pin = dev->pin;
-       if (!pin || !pci_has_managed_irq(dev))
+       if (!pin || !dev->irq_managed || dev->irq <= 0)
                return;
 
+       /* Keep IOAPIC pin configuration when suspending */
+       if (dev->dev.power.is_prepared)
+               return;
+#ifdef CONFIG_PM
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
                return;
@@ -499,6 +508,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
-               pci_reset_managed_irq(dev);
+               dev->irq_managed = 0;
        }
 }
index cdc5c2599bebcc1a95ca2f29a525a5e63fab3b0f..627f8fbb5e9a2753a06948836295a06af9b937b0 100644 (file)
 
 #ifdef CONFIG_X86
 #define valid_IRQ(i) (((i) != 0) && ((i) != 2))
+static inline bool acpi_iospace_resource_valid(struct resource *res)
+{
+       /* On X86 IO space is limited to the [0 - 64K] IO port range */
+       return res->end < 0x10003;
+}
 #else
 #define valid_IRQ(i) (true)
+/*
+ * ACPI IO descriptors on arches other than X86 contain MMIO CPU physical
+ * addresses mapping IO space in CPU physical address space, IO space
+ * resources can be placed anywhere in the 64-bit physical address space.
+ */
+static inline bool
+acpi_iospace_resource_valid(struct resource *res) { return true; }
 #endif
 
 static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
@@ -126,7 +138,7 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
        if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
                res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
-       if (res->end >= 0x10003)
+       if (!acpi_iospace_resource_valid(res))
                res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
        if (io_decode == ACPI_DECODE_16)
index 0d94621dc856080a0a3715040b7b5339c1edb248..e3322adaaae009aaea259b0931c3dd0b405e2517 100644 (file)
@@ -714,6 +714,7 @@ static int acpi_hibernation_enter(void)
 
 static void acpi_hibernation_leave(void)
 {
+       pm_set_resume_via_firmware();
        /*
         * If ACPI is not enabled by the BIOS and the boot kernel, we need to
         * enable it here.
index 04975b851c237c4894282f94feed4ad19a1c9b01..639adb1f8abdc08e7a4a958868457f35164cfb4d 100644 (file)
@@ -51,6 +51,9 @@ static int ahci_probe(struct platform_device *pdev)
        if (rc)
                return rc;
 
+       of_property_read_u32(dev->of_node,
+                            "ports-implemented", &hpriv->force_port_map);
+
        if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
                hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
 
index e2c6d9e0c5ac5ce5ce389b0ae1b0597ae979ee8b..e916bff6cee871fa69ac1107e7bf13f12b0ebdef 100644 (file)
@@ -739,9 +739,9 @@ static int xgene_ahci_probe(struct platform_device *pdev)
                                dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
                                        __func__);
                                version = XGENE_AHCI_V1;
-                       }
-                       if (info->valid & ACPI_VALID_CID)
+                       } else if (info->valid & ACPI_VALID_CID) {
                                version = XGENE_AHCI_V2;
+                       }
                }
        }
 #endif
index 998c6a85ad8943104e37a98a33bbc72ad8e36211..9628fa131757883cb1a6d3dbde51cef15be71438 100644 (file)
@@ -467,6 +467,7 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
                dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
                         port_map, hpriv->force_port_map);
                port_map = hpriv->force_port_map;
+               hpriv->saved_port_map = port_map;
        }
 
        if (hpriv->mask_port_map) {
index 65f50eccd49b0aa4b6801912fd8d21a73f79a7b9..a48824deabc53c24acb23f5e0732399526fd459e 100644 (file)
@@ -1381,7 +1381,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 
        mutex_lock(&genpd->lock);
 
-       if (!list_empty(&subdomain->slave_links) || subdomain->device_count) {
+       if (!list_empty(&subdomain->master_links) || subdomain->device_count) {
                pr_warn("%s: unable to remove subdomain %s\n", genpd->name,
                        subdomain->name);
                ret = -EBUSY;
index 33c1e18c41a4d467259fb438911418372b7e82a4..19837ef04d8ef21a355e22171117398b2f966f80 100644 (file)
@@ -1,2 +1,3 @@
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 obj-y                          += core.o cpu.o
+obj-$(CONFIG_DEBUG_FS)         += debugfs.o
index b8e76f75073b47a945b695506bb68176c586a161..433b60092972d56abba55897158d6c22156cf631 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/clk.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/of.h>
 #include <linux/export.h>
+#include <linux/regulator/consumer.h>
 
 #include "opp.h"
 
 /*
- * The root of the list of all devices. All device_opp structures branch off
- * from here, with each device_opp containing the list of opp it supports in
+ * The root of the list of all opp-tables. All opp_table structures branch off
+ * from here, with each opp_table containing the list of opps it supports in
  * various states of availability.
  */
-static LIST_HEAD(dev_opp_list);
+static LIST_HEAD(opp_tables);
 /* Lock to allow exclusive modification to the device and opp lists */
-DEFINE_MUTEX(dev_opp_list_lock);
+DEFINE_MUTEX(opp_table_lock);
 
 #define opp_rcu_lockdep_assert()                                       \
 do {                                                                   \
        RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&                       \
-                               !lockdep_is_held(&dev_opp_list_lock),   \
-                          "Missing rcu_read_lock() or "                \
-                          "dev_opp_list_lock protection");             \
+                        !lockdep_is_held(&opp_table_lock),             \
+                        "Missing rcu_read_lock() or "                  \
+                        "opp_table_lock protection");                  \
 } while (0)
 
-static struct device_list_opp *_find_list_dev(const struct device *dev,
-                                             struct device_opp *dev_opp)
+static struct opp_device *_find_opp_dev(const struct device *dev,
+                                       struct opp_table *opp_table)
 {
-       struct device_list_opp *list_dev;
+       struct opp_device *opp_dev;
 
-       list_for_each_entry(list_dev, &dev_opp->dev_list, node)
-               if (list_dev->dev == dev)
-                       return list_dev;
+       list_for_each_entry(opp_dev, &opp_table->dev_list, node)
+               if (opp_dev->dev == dev)
+                       return opp_dev;
 
        return NULL;
 }
 
-static struct device_opp *_managed_opp(const struct device_node *np)
+static struct opp_table *_managed_opp(const struct device_node *np)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
 
-       list_for_each_entry_rcu(dev_opp, &dev_opp_list, node) {
-               if (dev_opp->np == np) {
+       list_for_each_entry_rcu(opp_table, &opp_tables, node) {
+               if (opp_table->np == np) {
                        /*
                         * Multiple devices can point to the same OPP table and
                         * so will have same node-pointer, np.
@@ -64,7 +66,7 @@ static struct device_opp *_managed_opp(const struct device_node *np)
                         * But the OPPs will be considered as shared only if the
                         * OPP table contains a "opp-shared" property.
                         */
-                       return dev_opp->shared_opp ? dev_opp : NULL;
+                       return opp_table->shared_opp ? opp_table : NULL;
                }
        }
 
@@ -72,24 +74,24 @@ static struct device_opp *_managed_opp(const struct device_node *np)
 }
 
 /**
- * _find_device_opp() - find device_opp struct using device pointer
- * @dev:       device pointer used to lookup device OPPs
+ * _find_opp_table() - find opp_table struct using device pointer
+ * @dev:       device pointer used to lookup OPP table
  *
- * Search list of device OPPs for one containing matching device. Does a RCU
- * reader operation to grab the pointer needed.
+ * Search OPP table for one containing matching device. Does a RCU reader
+ * operation to grab the pointer needed.
  *
- * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
  * -EINVAL based on type of error.
  *
  * Locking: For readers, this function must be called under rcu_read_lock().
- * device_opp is a RCU protected pointer, which means that device_opp is valid
+ * opp_table is a RCU protected pointer, which means that opp_table is valid
  * as long as we are under RCU lock.
  *
- * For Writers, this function must be called with dev_opp_list_lock held.
+ * For Writers, this function must be called with opp_table_lock held.
  */
-struct device_opp *_find_device_opp(struct device *dev)
+struct opp_table *_find_opp_table(struct device *dev)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
 
        opp_rcu_lockdep_assert();
 
@@ -98,9 +100,9 @@ struct device_opp *_find_device_opp(struct device *dev)
                return ERR_PTR(-EINVAL);
        }
 
-       list_for_each_entry_rcu(dev_opp, &dev_opp_list, node)
-               if (_find_list_dev(dev, dev_opp))
-                       return dev_opp;
+       list_for_each_entry_rcu(opp_table, &opp_tables, node)
+               if (_find_opp_dev(dev, opp_table))
+                       return opp_table;
 
        return ERR_PTR(-ENODEV);
 }
@@ -213,22 +215,98 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
  */
 unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        unsigned long clock_latency_ns;
 
        rcu_read_lock();
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp))
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table))
                clock_latency_ns = 0;
        else
-               clock_latency_ns = dev_opp->clock_latency_ns_max;
+               clock_latency_ns = opp_table->clock_latency_ns_max;
 
        rcu_read_unlock();
        return clock_latency_ns;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
 
+/**
+ * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
+ * @dev: device for which we do this operation
+ *
+ * Return: This function returns the max voltage latency in nanoseconds.
+ *
+ * Locking: This function takes rcu_read_lock().
+ */
+unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
+{
+       struct opp_table *opp_table;
+       struct dev_pm_opp *opp;
+       struct regulator *reg;
+       unsigned long latency_ns = 0;
+       unsigned long min_uV = ~0, max_uV = 0;
+       int ret;
+
+       rcu_read_lock();
+
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               rcu_read_unlock();
+               return 0;
+       }
+
+       reg = opp_table->regulator;
+       if (IS_ERR(reg)) {
+               /* Regulator may not be required for device */
+               if (reg)
+                       dev_err(dev, "%s: Invalid regulator (%ld)\n", __func__,
+                               PTR_ERR(reg));
+               rcu_read_unlock();
+               return 0;
+       }
+
+       list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+               if (!opp->available)
+                       continue;
+
+               if (opp->u_volt_min < min_uV)
+                       min_uV = opp->u_volt_min;
+               if (opp->u_volt_max > max_uV)
+                       max_uV = opp->u_volt_max;
+       }
+
+       rcu_read_unlock();
+
+       /*
+        * The caller needs to ensure that opp_table (and hence the regulator)
+        * isn't freed, while we are executing this routine.
+        */
+       ret = regulator_set_voltage_time(reg, min_uV, max_uV);
+       if (ret > 0)
+               latency_ns = ret * 1000;
+
+       return latency_ns;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_volt_latency);
+
+/**
+ * dev_pm_opp_get_max_transition_latency() - Get max transition latency in
+ *                                          nanoseconds
+ * @dev: device for which we do this operation
+ *
+ * Return: This function returns the max transition latency, in nanoseconds, to
+ * switch from one OPP to other.
+ *
+ * Locking: This function takes rcu_read_lock().
+ */
+unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
+{
+       return dev_pm_opp_get_max_volt_latency(dev) +
+               dev_pm_opp_get_max_clock_latency(dev);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_transition_latency);
+
 /**
  * dev_pm_opp_get_suspend_opp() - Get suspend opp
  * @dev:       device for which we do this operation
@@ -244,21 +322,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
  */
 struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
 
        opp_rcu_lockdep_assert();
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp) || !dev_opp->suspend_opp ||
-           !dev_opp->suspend_opp->available)
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table) || !opp_table->suspend_opp ||
+           !opp_table->suspend_opp->available)
                return NULL;
 
-       return dev_opp->suspend_opp;
+       return opp_table->suspend_opp;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp);
 
 /**
- * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list
+ * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
  * @dev:       device for which we do this operation
  *
  * Return: This function returns the number of available opps if there are any,
@@ -268,21 +346,21 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp);
  */
 int dev_pm_opp_get_opp_count(struct device *dev)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *temp_opp;
        int count = 0;
 
        rcu_read_lock();
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp)) {
-               count = PTR_ERR(dev_opp);
-               dev_err(dev, "%s: device OPP not found (%d)\n",
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               count = PTR_ERR(opp_table);
+               dev_err(dev, "%s: OPP table not found (%d)\n",
                        __func__, count);
                goto out_unlock;
        }
 
-       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available)
                        count++;
        }
@@ -299,7 +377,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
  * @freq:              frequency to search for
  * @available:         true/false - match for available opp
  *
- * Return: Searches for exact match in the opp list and returns pointer to the
+ * Return: Searches for exact match in the opp table and returns pointer to the
  * matching opp if found, else returns ERR_PTR in case of error and should
  * be handled using IS_ERR. Error return values can be:
  * EINVAL:     for bad pointer
@@ -323,19 +401,20 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
                                              unsigned long freq,
                                              bool available)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
        opp_rcu_lockdep_assert();
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp)) {
-               int r = PTR_ERR(dev_opp);
-               dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               int r = PTR_ERR(opp_table);
+
+               dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
                return ERR_PTR(r);
        }
 
-       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available == available &&
                                temp_opp->rate == freq) {
                        opp = temp_opp;
@@ -371,7 +450,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
 struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                                             unsigned long *freq)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
        opp_rcu_lockdep_assert();
@@ -381,11 +460,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp))
-               return ERR_CAST(dev_opp);
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table))
+               return ERR_CAST(opp_table);
 
-       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available && temp_opp->rate >= *freq) {
                        opp = temp_opp;
                        *freq = opp->rate;
@@ -421,7 +500,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
                                              unsigned long *freq)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
        opp_rcu_lockdep_assert();
@@ -431,11 +510,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp))
-               return ERR_CAST(dev_opp);
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table))
+               return ERR_CAST(opp_table);
 
-       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available) {
                        /* go to the next node, before choosing prev */
                        if (temp_opp->rate > *freq)
@@ -451,116 +530,343 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
 
-/* List-dev Helpers */
-static void _kfree_list_dev_rcu(struct rcu_head *head)
+/*
+ * The caller needs to ensure that opp_table (and hence the clk) isn't freed,
+ * while clk returned here is used.
+ */
+static struct clk *_get_opp_clk(struct device *dev)
+{
+       struct opp_table *opp_table;
+       struct clk *clk;
+
+       rcu_read_lock();
+
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "%s: device opp doesn't exist\n", __func__);
+               clk = ERR_CAST(opp_table);
+               goto unlock;
+       }
+
+       clk = opp_table->clk;
+       if (IS_ERR(clk))
+               dev_err(dev, "%s: No clock available for the device\n",
+                       __func__);
+
+unlock:
+       rcu_read_unlock();
+       return clk;
+}
+
+static int _set_opp_voltage(struct device *dev, struct regulator *reg,
+                           unsigned long u_volt, unsigned long u_volt_min,
+                           unsigned long u_volt_max)
+{
+       int ret;
+
+       /* Regulator not available for device */
+       if (IS_ERR(reg)) {
+               dev_dbg(dev, "%s: regulator not available: %ld\n", __func__,
+                       PTR_ERR(reg));
+               return 0;
+       }
+
+       dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, u_volt_min,
+               u_volt, u_volt_max);
+
+       ret = regulator_set_voltage_triplet(reg, u_volt_min, u_volt,
+                                           u_volt_max);
+       if (ret)
+               dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
+                       __func__, u_volt_min, u_volt, u_volt_max, ret);
+
+       return ret;
+}
+
+/**
+ * dev_pm_opp_set_rate() - Configure new OPP based on frequency
+ * @dev:        device for which we do this operation
+ * @target_freq: frequency to achieve
+ *
+ * This configures the power-supplies and clock source to the levels specified
+ * by the OPP corresponding to the target_freq.
+ *
+ * Locking: This function takes rcu_read_lock().
+ */
+int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
+{
+       struct opp_table *opp_table;
+       struct dev_pm_opp *old_opp, *opp;
+       struct regulator *reg;
+       struct clk *clk;
+       unsigned long freq, old_freq;
+       unsigned long u_volt, u_volt_min, u_volt_max;
+       unsigned long ou_volt, ou_volt_min, ou_volt_max;
+       int ret;
+
+       if (unlikely(!target_freq)) {
+               dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
+                       target_freq);
+               return -EINVAL;
+       }
+
+       clk = _get_opp_clk(dev);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       freq = clk_round_rate(clk, target_freq);
+       if ((long)freq <= 0)
+               freq = target_freq;
+
+       old_freq = clk_get_rate(clk);
+
+       /* Return early if nothing to do */
+       if (old_freq == freq) {
+               dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do\n",
+                       __func__, freq);
+               return 0;
+       }
+
+       rcu_read_lock();
+
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "%s: device opp doesn't exist\n", __func__);
+               rcu_read_unlock();
+               return PTR_ERR(opp_table);
+       }
+
+       old_opp = dev_pm_opp_find_freq_ceil(dev, &old_freq);
+       if (!IS_ERR(old_opp)) {
+               ou_volt = old_opp->u_volt;
+               ou_volt_min = old_opp->u_volt_min;
+               ou_volt_max = old_opp->u_volt_max;
+       } else {
+               dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n",
+                       __func__, old_freq, PTR_ERR(old_opp));
+       }
+
+       opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+       if (IS_ERR(opp)) {
+               ret = PTR_ERR(opp);
+               dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n",
+                       __func__, freq, ret);
+               rcu_read_unlock();
+               return ret;
+       }
+
+       u_volt = opp->u_volt;
+       u_volt_min = opp->u_volt_min;
+       u_volt_max = opp->u_volt_max;
+
+       reg = opp_table->regulator;
+
+       rcu_read_unlock();
+
+       /* Scaling up? Scale voltage before frequency */
+       if (freq > old_freq) {
+               ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
+                                      u_volt_max);
+               if (ret)
+                       goto restore_voltage;
+       }
+
+       /* Change frequency */
+
+       dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
+               __func__, old_freq, freq);
+
+       ret = clk_set_rate(clk, freq);
+       if (ret) {
+               dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+                       ret);
+               goto restore_voltage;
+       }
+
+       /* Scaling down? Scale voltage after frequency */
+       if (freq < old_freq) {
+               ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
+                                      u_volt_max);
+               if (ret)
+                       goto restore_freq;
+       }
+
+       return 0;
+
+restore_freq:
+       if (clk_set_rate(clk, old_freq))
+               dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+                       __func__, old_freq);
+restore_voltage:
+       /* This shouldn't harm even if the voltages weren't updated earlier */
+       if (!IS_ERR(old_opp))
+               _set_opp_voltage(dev, reg, ou_volt, ou_volt_min, ou_volt_max);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
+
+/* OPP-dev Helpers */
+static void _kfree_opp_dev_rcu(struct rcu_head *head)
 {
-       struct device_list_opp *list_dev;
+       struct opp_device *opp_dev;
 
-       list_dev = container_of(head, struct device_list_opp, rcu_head);
-       kfree_rcu(list_dev, rcu_head);
+       opp_dev = container_of(head, struct opp_device, rcu_head);
+       kfree_rcu(opp_dev, rcu_head);
 }
 
-static void _remove_list_dev(struct device_list_opp *list_dev,
-                            struct device_opp *dev_opp)
+static void _remove_opp_dev(struct opp_device *opp_dev,
+                           struct opp_table *opp_table)
 {
-       list_del(&list_dev->node);
-       call_srcu(&dev_opp->srcu_head.srcu, &list_dev->rcu_head,
-                 _kfree_list_dev_rcu);
+       opp_debug_unregister(opp_dev, opp_table);
+       list_del(&opp_dev->node);
+       call_srcu(&opp_table->srcu_head.srcu, &opp_dev->rcu_head,
+                 _kfree_opp_dev_rcu);
 }
 
-struct device_list_opp *_add_list_dev(const struct device *dev,
-                                     struct device_opp *dev_opp)
+struct opp_device *_add_opp_dev(const struct device *dev,
+                               struct opp_table *opp_table)
 {
-       struct device_list_opp *list_dev;
+       struct opp_device *opp_dev;
+       int ret;
 
-       list_dev = kzalloc(sizeof(*list_dev), GFP_KERNEL);
-       if (!list_dev)
+       opp_dev = kzalloc(sizeof(*opp_dev), GFP_KERNEL);
+       if (!opp_dev)
                return NULL;
 
-       /* Initialize list-dev */
-       list_dev->dev = dev;
-       list_add_rcu(&list_dev->node, &dev_opp->dev_list);
+       /* Initialize opp-dev */
+       opp_dev->dev = dev;
+       list_add_rcu(&opp_dev->node, &opp_table->dev_list);
+
+       /* Create debugfs entries for the opp_table */
+       ret = opp_debug_register(opp_dev, opp_table);
+       if (ret)
+               dev_err(dev, "%s: Failed to register opp debugfs (%d)\n",
+                       __func__, ret);
 
-       return list_dev;
+       return opp_dev;
 }
 
 /**
- * _add_device_opp() - Find device OPP table or allocate a new one
+ * _add_opp_table() - Find OPP table or allocate a new one
  * @dev:       device for which we do this operation
  *
  * It tries to find an existing table first, if it couldn't find one, it
  * allocates a new OPP table and returns that.
  *
- * Return: valid device_opp pointer if success, else NULL.
+ * Return: valid opp_table pointer if success, else NULL.
  */
-static struct device_opp *_add_device_opp(struct device *dev)
+static struct opp_table *_add_opp_table(struct device *dev)
 {
-       struct device_opp *dev_opp;
-       struct device_list_opp *list_dev;
+       struct opp_table *opp_table;
+       struct opp_device *opp_dev;
+       struct device_node *np;
+       int ret;
 
-       /* Check for existing list for 'dev' first */
-       dev_opp = _find_device_opp(dev);
-       if (!IS_ERR(dev_opp))
-               return dev_opp;
+       /* Check for existing table for 'dev' first */
+       opp_table = _find_opp_table(dev);
+       if (!IS_ERR(opp_table))
+               return opp_table;
 
        /*
-        * Allocate a new device OPP table. In the infrequent case where a new
+        * Allocate a new OPP table. In the infrequent case where a new
         * device is needed to be added, we pay this penalty.
         */
-       dev_opp = kzalloc(sizeof(*dev_opp), GFP_KERNEL);
-       if (!dev_opp)
+       opp_table = kzalloc(sizeof(*opp_table), GFP_KERNEL);
+       if (!opp_table)
                return NULL;
 
-       INIT_LIST_HEAD(&dev_opp->dev_list);
+       INIT_LIST_HEAD(&opp_table->dev_list);
 
-       list_dev = _add_list_dev(dev, dev_opp);
-       if (!list_dev) {
-               kfree(dev_opp);
+       opp_dev = _add_opp_dev(dev, opp_table);
+       if (!opp_dev) {
+               kfree(opp_table);
                return NULL;
        }
 
-       srcu_init_notifier_head(&dev_opp->srcu_head);
-       INIT_LIST_HEAD(&dev_opp->opp_list);
+       /*
+        * Only required for backward compatibility with v1 bindings, but isn't
+        * harmful for other cases. And so we do it unconditionally.
+        */
+       np = of_node_get(dev->of_node);
+       if (np) {
+               u32 val;
+
+               if (!of_property_read_u32(np, "clock-latency", &val))
+                       opp_table->clock_latency_ns_max = val;
+               of_property_read_u32(np, "voltage-tolerance",
+                                    &opp_table->voltage_tolerance_v1);
+               of_node_put(np);
+       }
+
+       /* Set regulator to a non-NULL error value */
+       opp_table->regulator = ERR_PTR(-ENXIO);
+
+       /* Find clk for the device */
+       opp_table->clk = clk_get(dev, NULL);
+       if (IS_ERR(opp_table->clk)) {
+               ret = PTR_ERR(opp_table->clk);
+               if (ret != -EPROBE_DEFER)
+                       dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__,
+                               ret);
+       }
+
+       srcu_init_notifier_head(&opp_table->srcu_head);
+       INIT_LIST_HEAD(&opp_table->opp_list);
 
-       /* Secure the device list modification */
-       list_add_rcu(&dev_opp->node, &dev_opp_list);
-       return dev_opp;
+       /* Secure the device table modification */
+       list_add_rcu(&opp_table->node, &opp_tables);
+       return opp_table;
 }
 
 /**
- * _kfree_device_rcu() - Free device_opp RCU handler
+ * _kfree_device_rcu() - Free opp_table RCU handler
  * @head:      RCU head
  */
 static void _kfree_device_rcu(struct rcu_head *head)
 {
-       struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
+       struct opp_table *opp_table = container_of(head, struct opp_table,
+                                                  rcu_head);
 
-       kfree_rcu(device_opp, rcu_head);
+       kfree_rcu(opp_table, rcu_head);
 }
 
 /**
- * _remove_device_opp() - Removes a device OPP table
- * @dev_opp: device OPP table to be removed.
+ * _remove_opp_table() - Removes a OPP table
+ * @opp_table: OPP table to be removed.
  *
- * Removes/frees device OPP table it it doesn't contain any OPPs.
+ * Removes/frees OPP table if it doesn't contain any OPPs.
  */
-static void _remove_device_opp(struct device_opp *dev_opp)
+static void _remove_opp_table(struct opp_table *opp_table)
 {
-       struct device_list_opp *list_dev;
+       struct opp_device *opp_dev;
+
+       if (!list_empty(&opp_table->opp_list))
+               return;
 
-       if (!list_empty(&dev_opp->opp_list))
+       if (opp_table->supported_hw)
                return;
 
-       list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp,
-                                   node);
+       if (opp_table->prop_name)
+               return;
+
+       if (!IS_ERR(opp_table->regulator))
+               return;
 
-       _remove_list_dev(list_dev, dev_opp);
+       /* Release clk */
+       if (!IS_ERR(opp_table->clk))
+               clk_put(opp_table->clk);
+
+       opp_dev = list_first_entry(&opp_table->dev_list, struct opp_device,
+                                  node);
+
+       _remove_opp_dev(opp_dev, opp_table);
 
        /* dev_list must be empty now */
-       WARN_ON(!list_empty(&dev_opp->dev_list));
+       WARN_ON(!list_empty(&opp_table->dev_list));
 
-       list_del_rcu(&dev_opp->node);
-       call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
+       list_del_rcu(&opp_table->node);
+       call_srcu(&opp_table->srcu_head.srcu, &opp_table->rcu_head,
                  _kfree_device_rcu);
 }
 
@@ -577,17 +883,17 @@ static void _kfree_opp_rcu(struct rcu_head *head)
 
 /**
  * _opp_remove()  - Remove an OPP from a table definition
- * @dev_opp:   points back to the device_opp struct this opp belongs to
+ * @opp_table: points back to the opp_table struct this opp belongs to
  * @opp:       pointer to the OPP to remove
  * @notify:    OPP_EVENT_REMOVE notification should be sent or not
  *
- * This function removes an opp definition from the opp list.
+ * This function removes an opp definition from the opp table.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * It is assumed that the caller holds required mutex for an RCU updater
  * strategy.
  */
-static void _opp_remove(struct device_opp *dev_opp,
+static void _opp_remove(struct opp_table *opp_table,
                        struct dev_pm_opp *opp, bool notify)
 {
        /*
@@ -595,21 +901,23 @@ static void _opp_remove(struct device_opp *dev_opp,
         * frequency/voltage list.
         */
        if (notify)
-               srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
+               srcu_notifier_call_chain(&opp_table->srcu_head,
+                                        OPP_EVENT_REMOVE, opp);
+       opp_debug_remove_one(opp);
        list_del_rcu(&opp->node);
-       call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
+       call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
 
-       _remove_device_opp(dev_opp);
+       _remove_opp_table(opp_table);
 }
 
 /**
- * dev_pm_opp_remove()  - Remove an OPP from OPP list
+ * dev_pm_opp_remove()  - Remove an OPP from OPP table
  * @dev:       device for which we do this operation
  * @freq:      OPP to remove with matching 'freq'
  *
- * This function removes an opp from the opp list.
+ * This function removes an opp from the opp table.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks
  * to keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
@@ -618,17 +926,17 @@ static void _opp_remove(struct device_opp *dev_opp,
 void dev_pm_opp_remove(struct device *dev, unsigned long freq)
 {
        struct dev_pm_opp *opp;
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        bool found = false;
 
-       /* Hold our list modification lock here */
-       mutex_lock(&dev_opp_list_lock);
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
 
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp))
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table))
                goto unlock;
 
-       list_for_each_entry(opp, &dev_opp->opp_list, node) {
+       list_for_each_entry(opp, &opp_table->opp_list, node) {
                if (opp->rate == freq) {
                        found = true;
                        break;
@@ -641,14 +949,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
                goto unlock;
        }
 
-       _opp_remove(dev_opp, opp, true);
+       _opp_remove(opp_table, opp, true);
 unlock:
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 
 static struct dev_pm_opp *_allocate_opp(struct device *dev,
-                                       struct device_opp **dev_opp)
+                                       struct opp_table **opp_table)
 {
        struct dev_pm_opp *opp;
 
@@ -659,8 +967,8 @@ static struct dev_pm_opp *_allocate_opp(struct device *dev,
 
        INIT_LIST_HEAD(&opp->node);
 
-       *dev_opp = _add_device_opp(dev);
-       if (!*dev_opp) {
+       *opp_table = _add_opp_table(dev);
+       if (!*opp_table) {
                kfree(opp);
                return NULL;
        }
@@ -668,21 +976,38 @@ static struct dev_pm_opp *_allocate_opp(struct device *dev,
        return opp;
 }
 
+static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
+                                        struct opp_table *opp_table)
+{
+       struct regulator *reg = opp_table->regulator;
+
+       if (!IS_ERR(reg) &&
+           !regulator_is_supported_voltage(reg, opp->u_volt_min,
+                                           opp->u_volt_max)) {
+               pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
+                       __func__, opp->u_volt_min, opp->u_volt_max);
+               return false;
+       }
+
+       return true;
+}
+
 static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
-                   struct device_opp *dev_opp)
+                   struct opp_table *opp_table)
 {
        struct dev_pm_opp *opp;
-       struct list_head *head = &dev_opp->opp_list;
+       struct list_head *head = &opp_table->opp_list;
+       int ret;
 
        /*
         * Insert new OPP in order of increasing frequency and discard if
         * already present.
         *
-        * Need to use &dev_opp->opp_list in the condition part of the 'for'
+        * Need to use &opp_table->opp_list in the condition part of the 'for'
         * loop, don't replace it with head otherwise it will become an infinite
         * loop.
         */
-       list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
+       list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
                if (new_opp->rate > opp->rate) {
                        head = &opp->node;
                        continue;
@@ -700,9 +1025,20 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
                        0 : -EEXIST;
        }
 
-       new_opp->dev_opp = dev_opp;
+       new_opp->opp_table = opp_table;
        list_add_rcu(&new_opp->node, head);
 
+       ret = opp_debug_create_one(new_opp, opp_table);
+       if (ret)
+               dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n",
+                       __func__, ret);
+
+       if (!_opp_supported_by_regulators(new_opp, opp_table)) {
+               new_opp->available = false;
+               dev_warn(dev, "%s: OPP not supported by regulators (%lu)\n",
+                        __func__, new_opp->rate);
+       }
+
        return 0;
 }
 
@@ -713,14 +1049,14 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
  * @u_volt:    Voltage in uVolts for this OPP
  * @dynamic:   Dynamically added OPPs.
  *
- * This function adds an opp definition to the opp list and returns status.
+ * This function adds an opp definition to the opp table and returns status.
  * The opp is made available by default and it can be controlled using
  * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove.
  *
  * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table
  * and freed by dev_pm_opp_of_remove_table.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks
  * to keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
@@ -736,14 +1072,15 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
 static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
                       bool dynamic)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *new_opp;
+       unsigned long tol;
        int ret;
 
-       /* Hold our list modification lock here */
-       mutex_lock(&dev_opp_list_lock);
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
 
-       new_opp = _allocate_opp(dev, &dev_opp);
+       new_opp = _allocate_opp(dev, &opp_table);
        if (!new_opp) {
                ret = -ENOMEM;
                goto unlock;
@@ -751,83 +1088,475 @@ static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
 
        /* populate the opp table */
        new_opp->rate = freq;
+       tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
        new_opp->u_volt = u_volt;
+       new_opp->u_volt_min = u_volt - tol;
+       new_opp->u_volt_max = u_volt + tol;
        new_opp->available = true;
        new_opp->dynamic = dynamic;
 
-       ret = _opp_add(dev, new_opp, dev_opp);
+       ret = _opp_add(dev, new_opp, opp_table);
        if (ret)
                goto free_opp;
 
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 
        /*
         * Notify the changes in the availability of the operable
         * frequency/voltage list.
         */
-       srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
+       srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
        return 0;
 
 free_opp:
-       _opp_remove(dev_opp, new_opp, false);
+       _opp_remove(opp_table, new_opp, false);
 unlock:
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
        return ret;
 }
 
 /* TODO: Support multiple regulators */
-static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev)
+static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
+                             struct opp_table *opp_table)
 {
        u32 microvolt[3] = {0};
        u32 val;
        int count, ret;
+       struct property *prop = NULL;
+       char name[NAME_MAX];
+
+       /* Search for "opp-microvolt-<name>" */
+       if (opp_table->prop_name) {
+               snprintf(name, sizeof(name), "opp-microvolt-%s",
+                        opp_table->prop_name);
+               prop = of_find_property(opp->np, name, NULL);
+       }
 
-       /* Missing property isn't a problem, but an invalid entry is */
-       if (!of_find_property(opp->np, "opp-microvolt", NULL))
-               return 0;
+       if (!prop) {
+               /* Search for "opp-microvolt" */
+               sprintf(name, "opp-microvolt");
+               prop = of_find_property(opp->np, name, NULL);
+
+               /* Missing property isn't a problem, but an invalid entry is */
+               if (!prop)
+                       return 0;
+       }
 
-       count = of_property_count_u32_elems(opp->np, "opp-microvolt");
+       count = of_property_count_u32_elems(opp->np, name);
        if (count < 0) {
-               dev_err(dev, "%s: Invalid opp-microvolt property (%d)\n",
-                       __func__, count);
+               dev_err(dev, "%s: Invalid %s property (%d)\n",
+                       __func__, name, count);
                return count;
        }
 
        /* There can be one or three elements here */
        if (count != 1 && count != 3) {
-               dev_err(dev, "%s: Invalid number of elements in opp-microvolt property (%d)\n",
-                       __func__, count);
+               dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n",
+                       __func__, name, count);
                return -EINVAL;
        }
 
-       ret = of_property_read_u32_array(opp->np, "opp-microvolt", microvolt,
-                                        count);
+       ret = of_property_read_u32_array(opp->np, name, microvolt, count);
        if (ret) {
-               dev_err(dev, "%s: error parsing opp-microvolt: %d\n", __func__,
-                       ret);
+               dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
                return -EINVAL;
        }
 
        opp->u_volt = microvolt[0];
-       opp->u_volt_min = microvolt[1];
-       opp->u_volt_max = microvolt[2];
 
-       if (!of_property_read_u32(opp->np, "opp-microamp", &val))
+       if (count == 1) {
+               opp->u_volt_min = opp->u_volt;
+               opp->u_volt_max = opp->u_volt;
+       } else {
+               opp->u_volt_min = microvolt[1];
+               opp->u_volt_max = microvolt[2];
+       }
+
+       /* Search for "opp-microamp-<name>" */
+       prop = NULL;
+       if (opp_table->prop_name) {
+               snprintf(name, sizeof(name), "opp-microamp-%s",
+                        opp_table->prop_name);
+               prop = of_find_property(opp->np, name, NULL);
+       }
+
+       if (!prop) {
+               /* Search for "opp-microamp" */
+               sprintf(name, "opp-microamp");
+               prop = of_find_property(opp->np, name, NULL);
+       }
+
+       if (prop && !of_property_read_u32(opp->np, name, &val))
                opp->u_amp = val;
 
        return 0;
 }
 
+/**
+ * dev_pm_opp_set_supported_hw() - Set supported platforms
+ * @dev: Device for which supported-hw has to be set.
+ * @versions: Array of hierarchy of versions to match.
+ * @count: Number of elements in the array.
+ *
+ * This is required only for the V2 bindings, and it enables a platform to
+ * specify the hierarchy of versions it supports. OPP layer will then enable
+ * OPPs, which are available for those versions, based on its 'opp-supported-hw'
+ * property.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
+                               unsigned int count)
+{
+       struct opp_table *opp_table;
+       int ret = 0;
+
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
+
+       opp_table = _add_opp_table(dev);
+       if (!opp_table) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+       /* Make sure there are no concurrent readers while updating opp_table */
+       WARN_ON(!list_empty(&opp_table->opp_list));
+
+       /* Do we already have a version hierarchy associated with opp_table? */
+       if (opp_table->supported_hw) {
+               dev_err(dev, "%s: Already have supported hardware list\n",
+                       __func__);
+               ret = -EBUSY;
+               goto err;
+       }
+
+       opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
+                                       GFP_KERNEL);
+       if (!opp_table->supported_hw) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       opp_table->supported_hw_count = count;
+       mutex_unlock(&opp_table_lock);
+       return 0;
+
+err:
+       _remove_opp_table(opp_table);
+unlock:
+       mutex_unlock(&opp_table_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
+
+/**
+ * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw
+ * @dev: Device for which supported-hw has to be put.
+ *
+ * This is required only for the V2 bindings, and is called for a matching
+ * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure
+ * will not be freed.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+void dev_pm_opp_put_supported_hw(struct device *dev)
+{
+       struct opp_table *opp_table;
+
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
+
+       /* Check for existing table for 'dev' first */
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "Failed to find opp_table: %ld\n",
+                       PTR_ERR(opp_table));
+               goto unlock;
+       }
+
+       /* Make sure there are no concurrent readers while updating opp_table */
+       WARN_ON(!list_empty(&opp_table->opp_list));
+
+       if (!opp_table->supported_hw) {
+               dev_err(dev, "%s: Doesn't have supported hardware list\n",
+                       __func__);
+               goto unlock;
+       }
+
+       kfree(opp_table->supported_hw);
+       opp_table->supported_hw = NULL;
+       opp_table->supported_hw_count = 0;
+
+       /* Try freeing opp_table if this was the last blocking resource */
+       _remove_opp_table(opp_table);
+
+unlock:
+       mutex_unlock(&opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
+
+/**
+ * dev_pm_opp_set_prop_name() - Set prop-extn name
+ * @dev: Device for which the prop-name has to be set.
+ * @name: name to postfix to properties.
+ *
+ * This is required only for the V2 bindings, and it enables a platform to
+ * specify the extn to be used for certain property names. The properties to
+ * which the extension will apply are opp-microvolt and opp-microamp. OPP core
+ * should postfix the property name with -<name> while looking for them.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+{
+       struct opp_table *opp_table;
+       int ret = 0;
+
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
+
+       opp_table = _add_opp_table(dev);
+       if (!opp_table) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+       /* Make sure there are no concurrent readers while updating opp_table */
+       WARN_ON(!list_empty(&opp_table->opp_list));
+
+       /* Do we already have a prop-name associated with opp_table? */
+       if (opp_table->prop_name) {
+               dev_err(dev, "%s: Already have prop-name %s\n", __func__,
+                       opp_table->prop_name);
+               ret = -EBUSY;
+               goto err;
+       }
+
+       opp_table->prop_name = kstrdup(name, GFP_KERNEL);
+       if (!opp_table->prop_name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       mutex_unlock(&opp_table_lock);
+       return 0;
+
+err:
+       _remove_opp_table(opp_table);
+unlock:
+       mutex_unlock(&opp_table_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
+
+/**
+ * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name
+ * @dev: Device for which the prop-name has to be put.
+ *
+ * This is required only for the V2 bindings, and is called for a matching
+ * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure
+ * will not be freed.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+void dev_pm_opp_put_prop_name(struct device *dev)
+{
+       struct opp_table *opp_table;
+
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
+
+       /* Check for existing table for 'dev' first */
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "Failed to find opp_table: %ld\n",
+                       PTR_ERR(opp_table));
+               goto unlock;
+       }
+
+       /* Make sure there are no concurrent readers while updating opp_table */
+       WARN_ON(!list_empty(&opp_table->opp_list));
+
+       if (!opp_table->prop_name) {
+               dev_err(dev, "%s: Doesn't have a prop-name\n", __func__);
+               goto unlock;
+       }
+
+       kfree(opp_table->prop_name);
+       opp_table->prop_name = NULL;
+
+       /* Try freeing opp_table if this was the last blocking resource */
+       _remove_opp_table(opp_table);
+
+unlock:
+       mutex_unlock(&opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
+
+/**
+ * dev_pm_opp_set_regulator() - Set regulator name for the device
+ * @dev: Device for which regulator name is being set.
+ * @name: Name of the regulator.
+ *
+ * In order to support OPP switching, OPP layer needs to know the name of the
+ * device's regulator, as the core would be required to switch voltages as well.
+ *
+ * This must be called before any OPPs are initialized for the device.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int dev_pm_opp_set_regulator(struct device *dev, const char *name)
+{
+       struct opp_table *opp_table;
+       struct regulator *reg;
+       int ret;
+
+       mutex_lock(&opp_table_lock);
+
+       opp_table = _add_opp_table(dev);
+       if (!opp_table) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+       /* This should be called before OPPs are initialized */
+       if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* Already have a regulator set */
+       if (WARN_ON(!IS_ERR(opp_table->regulator))) {
+               ret = -EBUSY;
+               goto err;
+       }
+       /* Allocate the regulator */
+       reg = regulator_get_optional(dev, name);
+       if (IS_ERR(reg)) {
+               ret = PTR_ERR(reg);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "%s: no regulator (%s) found: %d\n",
+                               __func__, name, ret);
+               goto err;
+       }
+
+       opp_table->regulator = reg;
+
+       mutex_unlock(&opp_table_lock);
+       return 0;
+
+err:
+       _remove_opp_table(opp_table);
+unlock:
+       mutex_unlock(&opp_table_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
+
+/**
+ * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
+ * @dev: Device for which regulator was set.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+void dev_pm_opp_put_regulator(struct device *dev)
+{
+       struct opp_table *opp_table;
+
+       mutex_lock(&opp_table_lock);
+
+       /* Check for existing table for 'dev' first */
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "Failed to find opp_table: %ld\n",
+                       PTR_ERR(opp_table));
+               goto unlock;
+       }
+
+       if (IS_ERR(opp_table->regulator)) {
+               dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
+               goto unlock;
+       }
+
+       /* Make sure there are no concurrent readers while updating opp_table */
+       WARN_ON(!list_empty(&opp_table->opp_list));
+
+       regulator_put(opp_table->regulator);
+       opp_table->regulator = ERR_PTR(-ENXIO);
+
+       /* Try freeing opp_table if this was the last blocking resource */
+       _remove_opp_table(opp_table);
+
+unlock:
+       mutex_unlock(&opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
+
+static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
+                             struct device_node *np)
+{
+       unsigned int count = opp_table->supported_hw_count;
+       u32 version;
+       int ret;
+
+       if (!opp_table->supported_hw)
+               return true;
+
+       while (count--) {
+               ret = of_property_read_u32_index(np, "opp-supported-hw", count,
+                                                &version);
+               if (ret) {
+                       dev_warn(dev, "%s: failed to read opp-supported-hw property at index %d: %d\n",
+                                __func__, count, ret);
+                       return false;
+               }
+
+               /* Both of these are bitwise masks of the versions */
+               if (!(version & opp_table->supported_hw[count]))
+                       return false;
+       }
+
+       return true;
+}
+
 /**
  * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
  * @dev:       device for which we do this operation
  * @np:                device node
  *
- * This function adds an opp definition to the opp list and returns status. The
+ * This function adds an opp definition to the opp table and returns status. The
  * opp can be controlled using dev_pm_opp_enable/disable functions and may be
  * removed by dev_pm_opp_remove.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks
  * to keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
@@ -843,16 +1572,16 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev)
  */
 static int _opp_add_static_v2(struct device *dev, struct device_node *np)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *new_opp;
        u64 rate;
        u32 val;
        int ret;
 
-       /* Hold our list modification lock here */
-       mutex_lock(&dev_opp_list_lock);
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
 
-       new_opp = _allocate_opp(dev, &dev_opp);
+       new_opp = _allocate_opp(dev, &opp_table);
        if (!new_opp) {
                ret = -ENOMEM;
                goto unlock;
@@ -864,6 +1593,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
                goto free_opp;
        }
 
+       /* Check if the OPP supports hardware's hierarchy of versions or not */
+       if (!_opp_is_supported(dev, opp_table, np)) {
+               dev_dbg(dev, "OPP not supported by hardware: %llu\n", rate);
+               goto free_opp;
+       }
+
        /*
         * Rate is defined as an unsigned long in clk API, and so casting
         * explicitly to its type. Must be fixed once rate is 64 bit
@@ -879,28 +1614,30 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
        if (!of_property_read_u32(np, "clock-latency-ns", &val))
                new_opp->clock_latency_ns = val;
 
-       ret = opp_parse_supplies(new_opp, dev);
+       ret = opp_parse_supplies(new_opp, dev, opp_table);
        if (ret)
                goto free_opp;
 
-       ret = _opp_add(dev, new_opp, dev_opp);
+       ret = _opp_add(dev, new_opp, opp_table);
        if (ret)
                goto free_opp;
 
        /* OPP to select on device suspend */
        if (of_property_read_bool(np, "opp-suspend")) {
-               if (dev_opp->suspend_opp)
+               if (opp_table->suspend_opp) {
                        dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n",
-                                __func__, dev_opp->suspend_opp->rate,
+                                __func__, opp_table->suspend_opp->rate,
                                 new_opp->rate);
-               else
-                       dev_opp->suspend_opp = new_opp;
+               } else {
+                       new_opp->suspend = true;
+                       opp_table->suspend_opp = new_opp;
+               }
        }
 
-       if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max)
-               dev_opp->clock_latency_ns_max = new_opp->clock_latency_ns;
+       if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
+               opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
 
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 
        pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
                 __func__, new_opp->turbo, new_opp->rate, new_opp->u_volt,
@@ -911,13 +1648,13 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
         * Notify the changes in the availability of the operable
         * frequency/voltage list.
         */
-       srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
+       srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
        return 0;
 
 free_opp:
-       _opp_remove(dev_opp, new_opp, false);
+       _opp_remove(opp_table, new_opp, false);
 unlock:
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
        return ret;
 }
 
@@ -927,11 +1664,11 @@ unlock:
  * @freq:      Frequency in Hz for this OPP
  * @u_volt:    Voltage in uVolts for this OPP
  *
- * This function adds an opp definition to the opp list and returns status.
+ * This function adds an opp definition to the opp table and returns status.
  * The opp is made available by default and it can be controlled using
  * dev_pm_opp_enable/disable functions.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks
  * to keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
@@ -963,7 +1700,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add);
  * copy operation, returns 0 if no modification was done OR modification was
  * successful.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function internally uses RCU updater strategy with mutex locks to
  * keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
@@ -972,7 +1709,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add);
 static int _opp_set_availability(struct device *dev, unsigned long freq,
                                 bool availability_req)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
        int r = 0;
 
@@ -981,18 +1718,18 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
        if (!new_opp)
                return -ENOMEM;
 
-       mutex_lock(&dev_opp_list_lock);
+       mutex_lock(&opp_table_lock);
 
-       /* Find the device_opp */
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp)) {
-               r = PTR_ERR(dev_opp);
+       /* Find the opp_table */
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               r = PTR_ERR(opp_table);
                dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
                goto unlock;
        }
 
        /* Do we have the frequency? */
-       list_for_each_entry(tmp_opp, &dev_opp->opp_list, node) {
+       list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
                if (tmp_opp->rate == freq) {
                        opp = tmp_opp;
                        break;
@@ -1013,21 +1750,21 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
        new_opp->available = availability_req;
 
        list_replace_rcu(&opp->node, &new_opp->node);
-       mutex_unlock(&dev_opp_list_lock);
-       call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
+       mutex_unlock(&opp_table_lock);
+       call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
 
        /* Notify the change of the OPP availability */
        if (availability_req)
-               srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ENABLE,
-                                        new_opp);
+               srcu_notifier_call_chain(&opp_table->srcu_head,
+                                        OPP_EVENT_ENABLE, new_opp);
        else
-               srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_DISABLE,
-                                        new_opp);
+               srcu_notifier_call_chain(&opp_table->srcu_head,
+                                        OPP_EVENT_DISABLE, new_opp);
 
        return 0;
 
 unlock:
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
        kfree(new_opp);
        return r;
 }
@@ -1041,7 +1778,7 @@ unlock:
  * corresponding error value. It is meant to be used for users an OPP available
  * after being temporarily made unavailable with dev_pm_opp_disable.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function indirectly uses RCU and mutex locks to keep the
  * integrity of the internal data structures. Callers should ensure that
  * this function is *NOT* called under RCU protection or in contexts where
@@ -1067,7 +1804,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
  * control by users to make this OPP not available until the circumstances are
  * right to make it available again (with a call to dev_pm_opp_enable).
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function indirectly uses RCU and mutex locks to keep the
  * integrity of the internal data structures. Callers should ensure that
  * this function is *NOT* called under RCU protection or in contexts where
@@ -1085,26 +1822,26 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
 
 /**
  * dev_pm_opp_get_notifier() - find notifier_head of the device with opp
- * @dev:       device pointer used to lookup device OPPs.
+ * @dev:       device pointer used to lookup OPP table.
  *
  * Return: pointer to  notifier head if found, otherwise -ENODEV or
  * -EINVAL based on type of error casted as pointer. value must be checked
  *  with IS_ERR to determine valid pointer or error result.
  *
- * Locking: This function must be called under rcu_read_lock(). dev_opp is a RCU
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * Locking: This function must be called under rcu_read_lock(). opp_table is a
+ * RCU protected pointer. The reason for the same is that the opp pointer which
+ * is returned will remain valid for use with opp_get_{voltage, freq} only while
  * under the locked area. The pointer returned must be used prior to unlocking
  * with rcu_read_unlock() to maintain the integrity of the pointer.
  */
 struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
 {
-       struct device_opp *dev_opp = _find_device_opp(dev);
+       struct opp_table *opp_table = _find_opp_table(dev);
 
-       if (IS_ERR(dev_opp))
-               return ERR_CAST(dev_opp); /* matching type */
+       if (IS_ERR(opp_table))
+               return ERR_CAST(opp_table); /* matching type */
 
-       return &dev_opp->srcu_head;
+       return &opp_table->srcu_head;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
 
@@ -1112,11 +1849,11 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
 /**
  * dev_pm_opp_of_remove_table() - Free OPP table entries created from static DT
  *                               entries
- * @dev:       device pointer used to lookup device OPPs.
+ * @dev:       device pointer used to lookup OPP table.
  *
  * Free OPPs created using static entries present in DT.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function indirectly uses RCU updater strategy with mutex locks
  * to keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
@@ -1124,38 +1861,38 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
  */
 void dev_pm_opp_of_remove_table(struct device *dev)
 {
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct dev_pm_opp *opp, *tmp;
 
-       /* Hold our list modification lock here */
-       mutex_lock(&dev_opp_list_lock);
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
 
-       /* Check for existing list for 'dev' */
-       dev_opp = _find_device_opp(dev);
-       if (IS_ERR(dev_opp)) {
-               int error = PTR_ERR(dev_opp);
+       /* Check for existing table for 'dev' */
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               int error = PTR_ERR(opp_table);
 
                if (error != -ENODEV)
-                       WARN(1, "%s: dev_opp: %d\n",
+                       WARN(1, "%s: opp_table: %d\n",
                             IS_ERR_OR_NULL(dev) ?
                                        "Invalid device" : dev_name(dev),
                             error);
                goto unlock;
        }
 
-       /* Find if dev_opp manages a single device */
-       if (list_is_singular(&dev_opp->dev_list)) {
+       /* Find if opp_table manages a single device */
+       if (list_is_singular(&opp_table->dev_list)) {
                /* Free static OPPs */
-               list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
+               list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
                        if (!opp->dynamic)
-                               _opp_remove(dev_opp, opp, true);
+                               _opp_remove(opp_table, opp, true);
                }
        } else {
-               _remove_list_dev(_find_list_dev(dev, dev_opp), dev_opp);
+               _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
        }
 
 unlock:
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
 
@@ -1176,22 +1913,22 @@ struct device_node *_of_get_opp_desc_node(struct device *dev)
 static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
 {
        struct device_node *np;
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        int ret = 0, count = 0;
 
-       mutex_lock(&dev_opp_list_lock);
+       mutex_lock(&opp_table_lock);
 
-       dev_opp = _managed_opp(opp_np);
-       if (dev_opp) {
+       opp_table = _managed_opp(opp_np);
+       if (opp_table) {
                /* OPPs are already managed */
-               if (!_add_list_dev(dev, dev_opp))
+               if (!_add_opp_dev(dev, opp_table))
                        ret = -ENOMEM;
-               mutex_unlock(&dev_opp_list_lock);
+               mutex_unlock(&opp_table_lock);
                return ret;
        }
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 
-       /* We have opp-list node now, iterate over it and add OPPs */
+       /* We have opp-table node now, iterate over it and add OPPs */
        for_each_available_child_of_node(opp_np, np) {
                count++;
 
@@ -1207,19 +1944,19 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
        if (WARN_ON(!count))
                return -ENOENT;
 
-       mutex_lock(&dev_opp_list_lock);
+       mutex_lock(&opp_table_lock);
 
-       dev_opp = _find_device_opp(dev);
-       if (WARN_ON(IS_ERR(dev_opp))) {
-               ret = PTR_ERR(dev_opp);
-               mutex_unlock(&dev_opp_list_lock);
+       opp_table = _find_opp_table(dev);
+       if (WARN_ON(IS_ERR(opp_table))) {
+               ret = PTR_ERR(opp_table);
+               mutex_unlock(&opp_table_lock);
                goto free_table;
        }
 
-       dev_opp->np = opp_np;
-       dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared");
+       opp_table->np = opp_np;
+       opp_table->shared_opp = of_property_read_bool(opp_np, "opp-shared");
 
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 
        return 0;
 
@@ -1248,7 +1985,7 @@ static int _of_add_opp_table_v1(struct device *dev)
         */
        nr = prop->length / sizeof(u32);
        if (nr % 2) {
-               dev_err(dev, "%s: Invalid OPP list\n", __func__);
+               dev_err(dev, "%s: Invalid OPP table\n", __func__);
                return -EINVAL;
        }
 
@@ -1268,11 +2005,11 @@ static int _of_add_opp_table_v1(struct device *dev)
 
 /**
  * dev_pm_opp_of_add_table() - Initialize opp table from device tree
- * @dev:       device pointer used to lookup device OPPs.
+ * @dev:       device pointer used to lookup OPP table.
  *
  * Register the initial OPP table with the OPP library for given device.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Hence this function indirectly uses RCU updater strategy with mutex locks
  * to keep the integrity of the internal data structures. Callers should ensure
  * that this function is *NOT* called under RCU protection or in contexts where
index 7b445e88a0d559f091918be5e841f6a1380a33da..ba2bdbd932ef3c1ebaff47c6203bddb27fe9c03b 100644 (file)
@@ -31,7 +31,7 @@
  * @table:     Cpufreq table returned back to caller
  *
  * Generate a cpufreq table for a provided device- this assumes that the
- * opp list is already initialized and ready for usage.
+ * opp table is already initialized and ready for usage.
  *
  * This function allocates required memory for the cpufreq table. It is
  * expected that the caller does the required maintenance such as freeing
@@ -44,7 +44,7 @@
  * WARNING: It is  important for the callers to ensure refreshing their copy of
  * the table if any of the mentioned functions have been invoked in the interim.
  *
- * Locking: The internal device_opp and opp structures are RCU protected.
+ * Locking: The internal opp_table and opp structures are RCU protected.
  * Since we just use the regular accessor functions to access the internal data
  * structures, we use RCU read lock inside this function. As a result, users of
  * this function DONOT need to use explicit locks for invoking.
@@ -122,15 +122,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
 /* Required only for V1 bindings, as v2 can manage it from DT itself */
 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
 {
-       struct device_list_opp *list_dev;
-       struct device_opp *dev_opp;
+       struct opp_device *opp_dev;
+       struct opp_table *opp_table;
        struct device *dev;
        int cpu, ret = 0;
 
-       mutex_lock(&dev_opp_list_lock);
+       mutex_lock(&opp_table_lock);
 
-       dev_opp = _find_device_opp(cpu_dev);
-       if (IS_ERR(dev_opp)) {
+       opp_table = _find_opp_table(cpu_dev);
+       if (IS_ERR(opp_table)) {
                ret = -EINVAL;
                goto unlock;
        }
@@ -146,15 +146,15 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
                        continue;
                }
 
-               list_dev = _add_list_dev(dev, dev_opp);
-               if (!list_dev) {
-                       dev_err(dev, "%s: failed to add list-dev for cpu%d device\n",
+               opp_dev = _add_opp_dev(dev, opp_table);
+               if (!opp_dev) {
+                       dev_err(dev, "%s: failed to add opp-dev for cpu%d device\n",
                                __func__, cpu);
                        continue;
                }
        }
 unlock:
-       mutex_unlock(&dev_opp_list_lock);
+       mutex_unlock(&opp_table_lock);
 
        return ret;
 }
@@ -214,7 +214,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
 /*
  * Works only for OPP v2 bindings.
  *
- * cpumask should be already set to mask of cpu_dev->id.
  * Returns -ENOENT if operating-points-v2 bindings aren't supported.
  */
 int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
@@ -230,6 +229,8 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask
                return -ENOENT;
        }
 
+       cpumask_set_cpu(cpu_dev->id, cpumask);
+
        /* OPPs are shared ? */
        if (!of_property_read_bool(np, "opp-shared"))
                goto put_cpu_node;
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
new file mode 100644 (file)
index 0000000..ef1ae6b
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Generic OPP debugfs interface
+ *
+ * Copyright (C) 2015-2016 Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/limits.h>
+
+#include "opp.h"
+
+static struct dentry *rootdir;
+
+static void opp_set_dev_name(const struct device *dev, char *name)
+{
+       if (dev->parent)
+               snprintf(name, NAME_MAX, "%s-%s", dev_name(dev->parent),
+                        dev_name(dev));
+       else
+               snprintf(name, NAME_MAX, "%s", dev_name(dev));
+}
+
+void opp_debug_remove_one(struct dev_pm_opp *opp)
+{
+       debugfs_remove_recursive(opp->dentry);
+}
+
+int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
+{
+       struct dentry *pdentry = opp_table->dentry;
+       struct dentry *d;
+       char name[25];  /* 20 chars for 64 bit value + 5 (opp:\0) */
+
+       /* Rate is unique to each OPP, use it to give opp-name */
+       snprintf(name, sizeof(name), "opp:%lu", opp->rate);
+
+       /* Create per-opp directory */
+       d = debugfs_create_dir(name, pdentry);
+       if (!d)
+               return -ENOMEM;
+
+       if (!debugfs_create_bool("available", S_IRUGO, d, &opp->available))
+               return -ENOMEM;
+
+       if (!debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic))
+               return -ENOMEM;
+
+       if (!debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo))
+               return -ENOMEM;
+
+       if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend))
+               return -ENOMEM;
+
+       if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
+               return -ENOMEM;
+
+       if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->u_volt))
+               return -ENOMEM;
+
+       if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->u_volt_min))
+               return -ENOMEM;
+
+       if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->u_volt_max))
+               return -ENOMEM;
+
+       if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->u_amp))
+               return -ENOMEM;
+
+       if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
+                                 &opp->clock_latency_ns))
+               return -ENOMEM;
+
+       opp->dentry = d;
+       return 0;
+}
+
+static int opp_list_debug_create_dir(struct opp_device *opp_dev,
+                                    struct opp_table *opp_table)
+{
+       const struct device *dev = opp_dev->dev;
+       struct dentry *d;
+
+       opp_set_dev_name(dev, opp_table->dentry_name);
+
+       /* Create device specific directory */
+       d = debugfs_create_dir(opp_table->dentry_name, rootdir);
+       if (!d) {
+               dev_err(dev, "%s: Failed to create debugfs dir\n", __func__);
+               return -ENOMEM;
+       }
+
+       opp_dev->dentry = d;
+       opp_table->dentry = d;
+
+       return 0;
+}
+
+static int opp_list_debug_create_link(struct opp_device *opp_dev,
+                                     struct opp_table *opp_table)
+{
+       const struct device *dev = opp_dev->dev;
+       char name[NAME_MAX];
+       struct dentry *d;
+
+       opp_set_dev_name(opp_dev->dev, name);
+
+       /* Create device specific directory link */
+       d = debugfs_create_symlink(name, rootdir, opp_table->dentry_name);
+       if (!d) {
+               dev_err(dev, "%s: Failed to create link\n", __func__);
+               return -ENOMEM;
+       }
+
+       opp_dev->dentry = d;
+
+       return 0;
+}
+
+/**
+ * opp_debug_register - add a device opp node to the debugfs 'opp' directory
+ * @opp_dev: opp-dev pointer for device
+ * @opp_table: the device-opp being added
+ *
+ * Dynamically adds device specific directory in debugfs 'opp' directory. If the
+ * device-opp is shared with other devices, then links will be created for all
+ * devices except the first.
+ *
+ * Return: 0 on success, otherwise negative error.
+ */
+int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table)
+{
+       if (!rootdir) {
+               pr_debug("%s: Uninitialized rootdir\n", __func__);
+               return -EINVAL;
+       }
+
+       if (opp_table->dentry)
+               return opp_list_debug_create_link(opp_dev, opp_table);
+
+       return opp_list_debug_create_dir(opp_dev, opp_table);
+}
+
+static void opp_migrate_dentry(struct opp_device *opp_dev,
+                              struct opp_table *opp_table)
+{
+       struct opp_device *new_dev;
+       const struct device *dev;
+       struct dentry *dentry;
+
+       /* Look for next opp-dev */
+       list_for_each_entry(new_dev, &opp_table->dev_list, node)
+               if (new_dev != opp_dev)
+                       break;
+
+       /* new_dev is guaranteed to be valid here */
+       dev = new_dev->dev;
+       debugfs_remove_recursive(new_dev->dentry);
+
+       opp_set_dev_name(dev, opp_table->dentry_name);
+
+       dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir,
+                               opp_table->dentry_name);
+       if (!dentry) {
+               dev_err(dev, "%s: Failed to rename link from: %s to %s\n",
+                       __func__, dev_name(opp_dev->dev), dev_name(dev));
+               return;
+       }
+
+       new_dev->dentry = dentry;
+       opp_table->dentry = dentry;
+}
+
+/**
+ * opp_debug_unregister - remove a device opp node from debugfs opp directory
+ * @opp_dev: opp-dev pointer for device
+ * @opp_table: the device-opp being removed
+ *
+ * Dynamically removes device specific directory from debugfs 'opp' directory.
+ */
+void opp_debug_unregister(struct opp_device *opp_dev,
+                         struct opp_table *opp_table)
+{
+       if (opp_dev->dentry == opp_table->dentry) {
+               /* Move the real dentry object under another device */
+               if (!list_is_singular(&opp_table->dev_list)) {
+                       opp_migrate_dentry(opp_dev, opp_table);
+                       goto out;
+               }
+               opp_table->dentry = NULL;
+       }
+
+       debugfs_remove_recursive(opp_dev->dentry);
+
+out:
+       opp_dev->dentry = NULL;
+}
+
+static int __init opp_debug_init(void)
+{
+       /* Create /sys/kernel/debug/opp directory */
+       rootdir = debugfs_create_dir("opp", NULL);
+       if (!rootdir) {
+               pr_err("%s: Failed to create root directory\n", __func__);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+core_initcall(opp_debug_init);
index 7366b2aa8997897f89890cf99a4990d83e61a5a6..f67f806fcf3ae8f13866336cdc54958bd57f59b9 100644 (file)
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/limits.h>
 #include <linux/pm_opp.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 
+struct clk;
+struct regulator;
+
 /* Lock to allow exclusive modification to the device and opp lists */
-extern struct mutex dev_opp_list_lock;
+extern struct mutex opp_table_lock;
 
 /*
  * Internal data structure organization with the OPP layer library is as
  * follows:
- * dev_opp_list (root)
+ * opp_tables (root)
  *     |- device 1 (represents voltage domain 1)
  *     |       |- opp 1 (availability, freq, voltage)
  *     |       |- opp 2 ..
@@ -36,23 +40,24 @@ extern struct mutex dev_opp_list_lock;
  *     |- device 2 (represents the next voltage domain)
  *     ...
  *     `- device m (represents mth voltage domain)
- * device 1, 2.. are represented by dev_opp structure while each opp
+ * device 1, 2.. are represented by opp_table structure while each opp
  * is represented by the opp structure.
  */
 
 /**
  * struct dev_pm_opp - Generic OPP description structure
- * @node:      opp list node. The nodes are maintained throughout the lifetime
+ * @node:      opp table node. The nodes are maintained throughout the lifetime
  *             of boot. It is expected only an optimal set of OPPs are
  *             added to the library by the SoC framework.
- *             RCU usage: opp list is traversed with RCU locks. node
+ *             RCU usage: opp table is traversed with RCU locks. node
  *             modification is possible realtime, hence the modifications
- *             are protected by the dev_opp_list_lock for integrity.
+ *             are protected by the opp_table_lock for integrity.
  *             IMPORTANT: the opp nodes should be maintained in increasing
  *             order.
- * @dynamic:   not-created from static DT entries.
  * @available: true/false - marks if this OPP as available or not
+ * @dynamic:   not-created from static DT entries.
  * @turbo:     true if turbo (boost) OPP
+ * @suspend:   true if suspend OPP
  * @rate:      Frequency in hertz
  * @u_volt:    Target voltage in microvolts corresponding to this OPP
  * @u_volt_min:        Minimum voltage in microvolts corresponding to this OPP
@@ -60,9 +65,10 @@ extern struct mutex dev_opp_list_lock;
  * @u_amp:     Maximum current drawn by the device in microamperes
  * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
  *             frequency from any other OPP's frequency.
- * @dev_opp:   points back to the device_opp struct this opp belongs to
+ * @opp_table: points back to the opp_table struct this opp belongs to
  * @rcu_head:  RCU callback head used for deferred freeing
  * @np:                OPP's device node.
+ * @dentry:    debugfs dentry pointer (per opp)
  *
  * This structure stores the OPP information for a given device.
  */
@@ -72,6 +78,7 @@ struct dev_pm_opp {
        bool available;
        bool dynamic;
        bool turbo;
+       bool suspend;
        unsigned long rate;
 
        unsigned long u_volt;
@@ -80,40 +87,60 @@ struct dev_pm_opp {
        unsigned long u_amp;
        unsigned long clock_latency_ns;
 
-       struct device_opp *dev_opp;
+       struct opp_table *opp_table;
        struct rcu_head rcu_head;
 
        struct device_node *np;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *dentry;
+#endif
 };
 
 /**
- * struct device_list_opp - devices managed by 'struct device_opp'
+ * struct opp_device - devices managed by 'struct opp_table'
  * @node:      list node
  * @dev:       device to which the struct object belongs
  * @rcu_head:  RCU callback head used for deferred freeing
+ * @dentry:    debugfs dentry pointer (per device)
  *
- * This is an internal data structure maintaining the list of devices that are
- * managed by 'struct device_opp'.
+ * This is an internal data structure maintaining the devices that are managed
+ * by 'struct opp_table'.
  */
-struct device_list_opp {
+struct opp_device {
        struct list_head node;
        const struct device *dev;
        struct rcu_head rcu_head;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *dentry;
+#endif
 };
 
 /**
- * struct device_opp - Device opp structure
- * @node:      list node - contains the devices with OPPs that
+ * struct opp_table - Device opp structure
+ * @node:      table node - contains the devices with OPPs that
  *             have been registered. Nodes once added are not modified in this
- *             list.
- *             RCU usage: nodes are not modified in the list of device_opp,
- *             however addition is possible and is secured by dev_opp_list_lock
+ *             table.
+ *             RCU usage: nodes are not modified in the table of opp_table,
+ *             however addition is possible and is secured by opp_table_lock
  * @srcu_head: notifier head to notify the OPP availability changes.
  * @rcu_head:  RCU callback head used for deferred freeing
  * @dev_list:  list of devices that share these OPPs
- * @opp_list:  list of opps
+ * @opp_list:  table of opps
  * @np:                struct device_node pointer for opp's DT node.
+ * @clock_latency_ns_max: Max clock latency in nanoseconds.
  * @shared_opp: OPP is shared between multiple devices.
+ * @suspend_opp: Pointer to OPP to be used during device suspend.
+ * @supported_hw: Array of version number to support.
+ * @supported_hw_count: Number of elements in supported_hw array.
+ * @prop_name: A name to postfix to many DT properties, while parsing them.
+ * @clk: Device's clock handle
+ * @regulator: Supply regulator
+ * @dentry:    debugfs dentry pointer of the real device directory (not links).
+ * @dentry_name: Name of the real dentry.
+ *
+ * @voltage_tolerance_v1: In percentage, for v1 bindings only.
  *
  * This is an internal data structure maintaining the link to opps attached to
  * a device. This structure is not meant to be shared to users as it is
@@ -123,7 +150,7 @@ struct device_list_opp {
  * need to wait for the grace period of both of them before freeing any
  * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
  */
-struct device_opp {
+struct opp_table {
        struct list_head node;
 
        struct srcu_notifier_head srcu_head;
@@ -133,14 +160,48 @@ struct device_opp {
 
        struct device_node *np;
        unsigned long clock_latency_ns_max;
+
+       /* For backward compatibility with v1 bindings */
+       unsigned int voltage_tolerance_v1;
+
        bool shared_opp;
        struct dev_pm_opp *suspend_opp;
+
+       unsigned int *supported_hw;
+       unsigned int supported_hw_count;
+       const char *prop_name;
+       struct clk *clk;
+       struct regulator *regulator;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *dentry;
+       char dentry_name[NAME_MAX];
+#endif
 };
 
 /* Routines internal to opp core */
-struct device_opp *_find_device_opp(struct device *dev);
-struct device_list_opp *_add_list_dev(const struct device *dev,
-                                     struct device_opp *dev_opp);
+struct opp_table *_find_opp_table(struct device *dev);
+struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
 struct device_node *_of_get_opp_desc_node(struct device *dev);
 
+#ifdef CONFIG_DEBUG_FS
+void opp_debug_remove_one(struct dev_pm_opp *opp);
+int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table);
+int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table);
+void opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table);
+#else
+static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {}
+
+static inline int opp_debug_create_one(struct dev_pm_opp *opp,
+                                      struct opp_table *opp_table)
+{ return 0; }
+static inline int opp_debug_register(struct opp_device *opp_dev,
+                                    struct opp_table *opp_table)
+{ return 0; }
+
+static inline void opp_debug_unregister(struct opp_device *opp_dev,
+                                       struct opp_table *opp_table)
+{ }
+#endif         /* DEBUG_FS */
+
 #endif         /* __DRIVER_OPP_H__ */
index a5880f4ab40eb069bda60d6403b223d61ff1db80..1914c63ca8b1d858b07ae102f7b0715785004038 100644 (file)
@@ -338,7 +338,7 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
 
        if (unlikely(bio->bi_rw & REQ_DISCARD)) {
                if (sector & ((PAGE_SIZE >> SECTOR_SHIFT) - 1) ||
-                   bio->bi_iter.bi_size & PAGE_MASK)
+                   bio->bi_iter.bi_size & ~PAGE_MASK)
                        goto io_error;
                discard_from_brd(brd, sector, bio->bi_iter.bi_size);
                goto out;
index 423f4ca7d712dda6f012c32954f19c9ce3af9d9c..80cf8add46ff3667d896fca88aaea3fbf338ad27 100644 (file)
@@ -488,6 +488,12 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
        bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
        iov_iter_bvec(&iter, ITER_BVEC | rw, bvec,
                      bio_segments(bio), blk_rq_bytes(cmd->rq));
+       /*
+        * This bio may be started from the middle of the 'bvec'
+        * because of bio splitting, so offset from the bvec must
+        * be passed to iov iterator
+        */
+       iter.iov_offset = bio->bi_iter.bi_bvec_done;
 
        cmd->iocb.ki_pos = pos;
        cmd->iocb.ki_filp = file;
index 3457ac8c03e2f3cfe10c8a2ccc26f9a706039831..55d3d1da72dee7aa071eaf8dd9dcb2d31b76892e 100644 (file)
@@ -173,7 +173,13 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
 {
        struct request *rq;
 
+       if (mtip_check_surprise_removal(dd->pdev))
+               return NULL;
+
        rq = blk_mq_alloc_request(dd->queue, 0, __GFP_RECLAIM, true);
+       if (IS_ERR(rq))
+               return NULL;
+
        return blk_mq_rq_to_pdu(rq);
 }
 
@@ -233,15 +239,9 @@ static void mtip_async_complete(struct mtip_port *port,
                        "Command tag %d failed due to TFE\n", tag);
        }
 
-       /* Unmap the DMA scatter list entries */
-       dma_unmap_sg(&dd->pdev->dev, cmd->sg, cmd->scatter_ents, cmd->direction);
-
        rq = mtip_rq_from_tag(dd, tag);
 
-       if (unlikely(cmd->unaligned))
-               up(&port->cmd_slot_unal);
-
-       blk_mq_end_request(rq, status ? -EIO : 0);
+       blk_mq_complete_request(rq, status);
 }
 
 /*
@@ -581,6 +581,8 @@ static void mtip_completion(struct mtip_port *port,
                dev_warn(&port->dd->pdev->dev,
                        "Internal command %d completed with TFE\n", tag);
 
+       command->comp_func = NULL;
+       command->comp_data = NULL;
        complete(waiting);
 }
 
@@ -618,8 +620,6 @@ static void mtip_handle_tfe(struct driver_data *dd)
 
        port = dd->port;
 
-       set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
-
        if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
                cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
                dbg_printk(MTIP_DRV_NAME " TFE for the internal command\n");
@@ -628,7 +628,7 @@ static void mtip_handle_tfe(struct driver_data *dd)
                        cmd->comp_func(port, MTIP_TAG_INTERNAL,
                                        cmd, PORT_IRQ_TF_ERR);
                }
-               goto handle_tfe_exit;
+               return;
        }
 
        /* clear the tag accumulator */
@@ -701,7 +701,7 @@ static void mtip_handle_tfe(struct driver_data *dd)
                        fail_reason = "thermal shutdown";
                }
                if (buf[288] == 0xBF) {
-                       set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag);
+                       set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag);
                        dev_info(&dd->pdev->dev,
                                "Drive indicates rebuild has failed. Secure erase required.\n");
                        fail_all_ncq_cmds = 1;
@@ -771,11 +771,6 @@ static void mtip_handle_tfe(struct driver_data *dd)
                }
        }
        print_tags(dd, "reissued (TFE)", tagaccum, cmd_cnt);
-
-handle_tfe_exit:
-       /* clear eh_active */
-       clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
-       wake_up_interruptible(&port->svc_wait);
 }
 
 /*
@@ -1007,6 +1002,7 @@ static bool mtip_pause_ncq(struct mtip_port *port,
                        (fis->features == 0x27 || fis->features == 0x72 ||
                         fis->features == 0x62 || fis->features == 0x26))) {
                clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
+               clear_bit(MTIP_DDF_REBUILD_FAILED_BIT, &port->dd->dd_flag);
                /* Com reset after secure erase or lowlevel format */
                mtip_restart_port(port);
                clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
@@ -1021,12 +1017,14 @@ static bool mtip_pause_ncq(struct mtip_port *port,
  *
  * @port    Pointer to port data structure
  * @timeout Max duration to wait (ms)
+ * @atomic  gfp_t flag to indicate blockable context or not
  *
  * return value
  *     0       Success
  *     -EBUSY  Commands still active
  */
-static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout)
+static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout,
+                                                               gfp_t atomic)
 {
        unsigned long to;
        unsigned int n;
@@ -1037,16 +1035,21 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout)
        to = jiffies + msecs_to_jiffies(timeout);
        do {
                if (test_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags) &&
-                       test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) {
+                       test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags) &&
+                       atomic == GFP_KERNEL) {
                        msleep(20);
                        continue; /* svc thd is actively issuing commands */
                }
 
-               msleep(100);
+               if (atomic == GFP_KERNEL)
+                       msleep(100);
+               else {
+                       cpu_relax();
+                       udelay(100);
+               }
+
                if (mtip_check_surprise_removal(port->dd->pdev))
                        goto err_fault;
-               if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag))
-                       goto err_fault;
 
                /*
                 * Ignore s_active bit 0 of array element 0.
@@ -1099,6 +1102,7 @@ static int mtip_exec_internal_command(struct mtip_port *port,
        struct mtip_cmd *int_cmd;
        struct driver_data *dd = port->dd;
        int rv = 0;
+       unsigned long start;
 
        /* Make sure the buffer is 8 byte aligned. This is asic specific. */
        if (buffer & 0x00000007) {
@@ -1107,6 +1111,10 @@ static int mtip_exec_internal_command(struct mtip_port *port,
        }
 
        int_cmd = mtip_get_int_command(dd);
+       if (!int_cmd) {
+               dbg_printk(MTIP_DRV_NAME "Unable to allocate tag for PIO cmd\n");
+               return -EFAULT;
+       }
 
        set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
 
@@ -1119,7 +1127,7 @@ static int mtip_exec_internal_command(struct mtip_port *port,
                if (fis->command != ATA_CMD_STANDBYNOW1) {
                        /* wait for io to complete if non atomic */
                        if (mtip_quiesce_io(port,
-                                       MTIP_QUIESCE_IO_TIMEOUT_MS) < 0) {
+                               MTIP_QUIESCE_IO_TIMEOUT_MS, atomic) < 0) {
                                dev_warn(&dd->pdev->dev,
                                        "Failed to quiesce IO\n");
                                mtip_put_int_command(dd, int_cmd);
@@ -1162,6 +1170,8 @@ static int mtip_exec_internal_command(struct mtip_port *port,
        /* Populate the command header */
        int_cmd->command_header->byte_count = 0;
 
+       start = jiffies;
+
        /* Issue the command to the hardware */
        mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL);
 
@@ -1170,10 +1180,12 @@ static int mtip_exec_internal_command(struct mtip_port *port,
                if ((rv = wait_for_completion_interruptible_timeout(
                                &wait,
                                msecs_to_jiffies(timeout))) <= 0) {
+
                        if (rv == -ERESTARTSYS) { /* interrupted */
                                dev_err(&dd->pdev->dev,
-                                       "Internal command [%02X] was interrupted after %lu ms\n",
-                                       fis->command, timeout);
+                                       "Internal command [%02X] was interrupted after %u ms\n",
+                                       fis->command,
+                                       jiffies_to_msecs(jiffies - start));
                                rv = -EINTR;
                                goto exec_ic_exit;
                        } else if (rv == 0) /* timeout */
@@ -2897,6 +2909,42 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd)
        return -EFAULT;
 }
 
+static void mtip_softirq_done_fn(struct request *rq)
+{
+       struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
+       struct driver_data *dd = rq->q->queuedata;
+
+       /* Unmap the DMA scatter list entries */
+       dma_unmap_sg(&dd->pdev->dev, cmd->sg, cmd->scatter_ents,
+                                                       cmd->direction);
+
+       if (unlikely(cmd->unaligned))
+               up(&dd->port->cmd_slot_unal);
+
+       blk_mq_end_request(rq, rq->errors);
+}
+
+static void mtip_abort_cmd(struct request *req, void *data,
+                                                       bool reserved)
+{
+       struct driver_data *dd = data;
+
+       dbg_printk(MTIP_DRV_NAME " Aborting request, tag = %d\n", req->tag);
+
+       clear_bit(req->tag, dd->port->cmds_to_issue);
+       req->errors = -EIO;
+       mtip_softirq_done_fn(req);
+}
+
+static void mtip_queue_cmd(struct request *req, void *data,
+                                                       bool reserved)
+{
+       struct driver_data *dd = data;
+
+       set_bit(req->tag, dd->port->cmds_to_issue);
+       blk_abort_request(req);
+}
+
 /*
  * service thread to issue queued commands
  *
@@ -2909,7 +2957,7 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd)
 static int mtip_service_thread(void *data)
 {
        struct driver_data *dd = (struct driver_data *)data;
-       unsigned long slot, slot_start, slot_wrap;
+       unsigned long slot, slot_start, slot_wrap, to;
        unsigned int num_cmd_slots = dd->slot_groups * 32;
        struct mtip_port *port = dd->port;
 
@@ -2924,9 +2972,7 @@ static int mtip_service_thread(void *data)
                 * is in progress nor error handling is active
                 */
                wait_event_interruptible(port->svc_wait, (port->flags) &&
-                       !(port->flags & MTIP_PF_PAUSE_IO));
-
-               set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags);
+                       (port->flags & MTIP_PF_SVC_THD_WORK));
 
                if (kthread_should_stop() ||
                        test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags))
@@ -2936,6 +2982,8 @@ static int mtip_service_thread(void *data)
                                &dd->dd_flag)))
                        goto st_out;
 
+               set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags);
+
 restart_eh:
                /* Demux bits: start with error handling */
                if (test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags)) {
@@ -2946,6 +2994,32 @@ restart_eh:
                if (test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags))
                        goto restart_eh;
 
+               if (test_bit(MTIP_PF_TO_ACTIVE_BIT, &port->flags)) {
+                       to = jiffies + msecs_to_jiffies(5000);
+
+                       do {
+                               mdelay(100);
+                       } while (atomic_read(&dd->irq_workers_active) != 0 &&
+                               time_before(jiffies, to));
+
+                       if (atomic_read(&dd->irq_workers_active) != 0)
+                               dev_warn(&dd->pdev->dev,
+                                       "Completion workers still active!");
+
+                       spin_lock(dd->queue->queue_lock);
+                       blk_mq_all_tag_busy_iter(*dd->tags.tags,
+                                                       mtip_queue_cmd, dd);
+                       spin_unlock(dd->queue->queue_lock);
+
+                       set_bit(MTIP_PF_ISSUE_CMDS_BIT, &dd->port->flags);
+
+                       if (mtip_device_reset(dd))
+                               blk_mq_all_tag_busy_iter(*dd->tags.tags,
+                                                       mtip_abort_cmd, dd);
+
+                       clear_bit(MTIP_PF_TO_ACTIVE_BIT, &dd->port->flags);
+               }
+
                if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) {
                        slot = 1;
                        /* used to restrict the loop to one iteration */
@@ -2978,10 +3052,8 @@ restart_eh:
                }
 
                if (test_bit(MTIP_PF_REBUILD_BIT, &port->flags)) {
-                       if (mtip_ftl_rebuild_poll(dd) < 0)
-                               set_bit(MTIP_DDF_REBUILD_FAILED_BIT,
-                                                       &dd->dd_flag);
-                       clear_bit(MTIP_PF_REBUILD_BIT, &port->flags);
+                       if (mtip_ftl_rebuild_poll(dd) == 0)
+                               clear_bit(MTIP_PF_REBUILD_BIT, &port->flags);
                }
        }
 
@@ -3096,7 +3168,7 @@ static int mtip_hw_get_identify(struct driver_data *dd)
                if (buf[288] == 0xBF) {
                        dev_info(&dd->pdev->dev,
                                "Drive indicates rebuild has failed.\n");
-                       /* TODO */
+                       set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag);
                }
        }
 
@@ -3270,20 +3342,25 @@ out1:
        return rv;
 }
 
-static void mtip_standby_drive(struct driver_data *dd)
+static int mtip_standby_drive(struct driver_data *dd)
 {
-       if (dd->sr)
-               return;
+       int rv = 0;
 
+       if (dd->sr || !dd->port)
+               return -ENODEV;
        /*
         * Send standby immediate (E0h) to the drive so that it
         * saves its state.
         */
        if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags) &&
-           !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))
-               if (mtip_standby_immediate(dd->port))
+           !test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag) &&
+           !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)) {
+               rv = mtip_standby_immediate(dd->port);
+               if (rv)
                        dev_warn(&dd->pdev->dev,
                                "STANDBY IMMEDIATE failed\n");
+       }
+       return rv;
 }
 
 /*
@@ -3296,10 +3373,6 @@ static void mtip_standby_drive(struct driver_data *dd)
  */
 static int mtip_hw_exit(struct driver_data *dd)
 {
-       /*
-        * Send standby immediate (E0h) to the drive so that it
-        * saves its state.
-        */
        if (!dd->sr) {
                /* de-initialize the port. */
                mtip_deinit_port(dd->port);
@@ -3341,8 +3414,7 @@ static int mtip_hw_shutdown(struct driver_data *dd)
         * Send standby immediate (E0h) to the drive so that it
         * saves its state.
         */
-       if (!dd->sr && dd->port)
-               mtip_standby_immediate(dd->port);
+       mtip_standby_drive(dd);
 
        return 0;
 }
@@ -3365,7 +3437,7 @@ static int mtip_hw_suspend(struct driver_data *dd)
         * Send standby immediate (E0h) to the drive
         * so that it saves its state.
         */
-       if (mtip_standby_immediate(dd->port) != 0) {
+       if (mtip_standby_drive(dd) != 0) {
                dev_err(&dd->pdev->dev,
                        "Failed standby-immediate command\n");
                return -EFAULT;
@@ -3603,6 +3675,28 @@ static int mtip_block_getgeo(struct block_device *dev,
        return 0;
 }
 
+static int mtip_block_open(struct block_device *dev, fmode_t mode)
+{
+       struct driver_data *dd;
+
+       if (dev && dev->bd_disk) {
+               dd = (struct driver_data *) dev->bd_disk->private_data;
+
+               if (dd) {
+                       if (test_bit(MTIP_DDF_REMOVAL_BIT,
+                                                       &dd->dd_flag)) {
+                               return -ENODEV;
+                       }
+                       return 0;
+               }
+       }
+       return -ENODEV;
+}
+
+void mtip_block_release(struct gendisk *disk, fmode_t mode)
+{
+}
+
 /*
  * Block device operation function.
  *
@@ -3610,6 +3704,8 @@ static int mtip_block_getgeo(struct block_device *dev,
  * layer.
  */
 static const struct block_device_operations mtip_block_ops = {
+       .open           = mtip_block_open,
+       .release        = mtip_block_release,
        .ioctl          = mtip_block_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = mtip_block_compat_ioctl,
@@ -3671,10 +3767,9 @@ static int mtip_submit_request(struct blk_mq_hw_ctx *hctx, struct request *rq)
                                rq_data_dir(rq))) {
                        return -ENODATA;
                }
-               if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag)))
+               if (unlikely(test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag) ||
+                       test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)))
                        return -ENODATA;
-               if (test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag))
-                       return -ENXIO;
        }
 
        if (rq->cmd_flags & REQ_DISCARD) {
@@ -3786,11 +3881,33 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx,
        return 0;
 }
 
+static enum blk_eh_timer_return mtip_cmd_timeout(struct request *req,
+                                                               bool reserved)
+{
+       struct driver_data *dd = req->q->queuedata;
+       int ret = BLK_EH_RESET_TIMER;
+
+       if (reserved)
+               goto exit_handler;
+
+       if (test_bit(req->tag, dd->port->cmds_to_issue))
+               goto exit_handler;
+
+       if (test_and_set_bit(MTIP_PF_TO_ACTIVE_BIT, &dd->port->flags))
+               goto exit_handler;
+
+       wake_up_interruptible(&dd->port->svc_wait);
+exit_handler:
+       return ret;
+}
+
 static struct blk_mq_ops mtip_mq_ops = {
        .queue_rq       = mtip_queue_rq,
        .map_queue      = blk_mq_map_queue,
        .init_request   = mtip_init_cmd,
        .exit_request   = mtip_free_cmd,
+       .complete       = mtip_softirq_done_fn,
+       .timeout        = mtip_cmd_timeout,
 };
 
 /*
@@ -3857,7 +3974,6 @@ static int mtip_block_initialize(struct driver_data *dd)
 
        mtip_hw_debugfs_init(dd);
 
-skip_create_disk:
        memset(&dd->tags, 0, sizeof(dd->tags));
        dd->tags.ops = &mtip_mq_ops;
        dd->tags.nr_hw_queues = 1;
@@ -3867,12 +3983,13 @@ skip_create_disk:
        dd->tags.numa_node = dd->numa_node;
        dd->tags.flags = BLK_MQ_F_SHOULD_MERGE;
        dd->tags.driver_data = dd;
+       dd->tags.timeout = MTIP_NCQ_CMD_TIMEOUT_MS;
 
        rv = blk_mq_alloc_tag_set(&dd->tags);
        if (rv) {
                dev_err(&dd->pdev->dev,
                        "Unable to allocate request queue\n");
-               goto block_queue_alloc_init_error;
+               goto block_queue_alloc_tag_error;
        }
 
        /* Allocate the request queue. */
@@ -3887,6 +4004,7 @@ skip_create_disk:
        dd->disk->queue         = dd->queue;
        dd->queue->queuedata    = dd;
 
+skip_create_disk:
        /* Initialize the protocol layer. */
        wait_for_rebuild = mtip_hw_get_identify(dd);
        if (wait_for_rebuild < 0) {
@@ -3983,8 +4101,9 @@ kthread_run_error:
 read_capacity_error:
 init_hw_cmds_error:
        blk_cleanup_queue(dd->queue);
-       blk_mq_free_tag_set(&dd->tags);
 block_queue_alloc_init_error:
+       blk_mq_free_tag_set(&dd->tags);
+block_queue_alloc_tag_error:
        mtip_hw_debugfs_exit(dd);
 disk_index_error:
        spin_lock(&rssd_index_lock);
@@ -4001,6 +4120,22 @@ protocol_init_error:
        return rv;
 }
 
+static void mtip_no_dev_cleanup(struct request *rq, void *data, bool reserv)
+{
+       struct driver_data *dd = (struct driver_data *)data;
+       struct mtip_cmd *cmd;
+
+       if (likely(!reserv))
+               blk_mq_complete_request(rq, -ENODEV);
+       else if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &dd->port->flags)) {
+
+               cmd = mtip_cmd_from_tag(dd, MTIP_TAG_INTERNAL);
+               if (cmd->comp_func)
+                       cmd->comp_func(dd->port, MTIP_TAG_INTERNAL,
+                                       cmd, -ENODEV);
+       }
+}
+
 /*
  * Block layer deinitialization function.
  *
@@ -4032,12 +4167,23 @@ static int mtip_block_remove(struct driver_data *dd)
                }
        }
 
-       if (!dd->sr)
-               mtip_standby_drive(dd);
+       if (!dd->sr) {
+               /*
+                * Explicitly wait here for IOs to quiesce,
+                * as mtip_standby_drive usually won't wait for IOs.
+                */
+               if (!mtip_quiesce_io(dd->port, MTIP_QUIESCE_IO_TIMEOUT_MS,
+                                                               GFP_KERNEL))
+                       mtip_standby_drive(dd);
+       }
        else
                dev_info(&dd->pdev->dev, "device %s surprise removal\n",
                                                dd->disk->disk_name);
 
+       blk_mq_freeze_queue_start(dd->queue);
+       blk_mq_stop_hw_queues(dd->queue);
+       blk_mq_all_tag_busy_iter(dd->tags.tags[0], mtip_no_dev_cleanup, dd);
+
        /*
         * Delete our gendisk structure. This also removes the device
         * from /dev
@@ -4047,7 +4193,8 @@ static int mtip_block_remove(struct driver_data *dd)
                dd->bdev = NULL;
        }
        if (dd->disk) {
-               del_gendisk(dd->disk);
+               if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
+                       del_gendisk(dd->disk);
                if (dd->disk->queue) {
                        blk_cleanup_queue(dd->queue);
                        blk_mq_free_tag_set(&dd->tags);
@@ -4088,7 +4235,8 @@ static int mtip_block_shutdown(struct driver_data *dd)
                dev_info(&dd->pdev->dev,
                        "Shutting down %s ...\n", dd->disk->disk_name);
 
-               del_gendisk(dd->disk);
+               if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag))
+                       del_gendisk(dd->disk);
                if (dd->disk->queue) {
                        blk_cleanup_queue(dd->queue);
                        blk_mq_free_tag_set(&dd->tags);
@@ -4433,7 +4581,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
        struct driver_data *dd = pci_get_drvdata(pdev);
        unsigned long flags, to;
 
-       set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
+       set_bit(MTIP_DDF_REMOVAL_BIT, &dd->dd_flag);
 
        spin_lock_irqsave(&dev_lock, flags);
        list_del_init(&dd->online_list);
@@ -4450,12 +4598,17 @@ static void mtip_pci_remove(struct pci_dev *pdev)
        } while (atomic_read(&dd->irq_workers_active) != 0 &&
                time_before(jiffies, to));
 
+       if (!dd->sr)
+               fsync_bdev(dd->bdev);
+
        if (atomic_read(&dd->irq_workers_active) != 0) {
                dev_warn(&dd->pdev->dev,
                        "Completion workers still active!\n");
        }
 
-       blk_mq_stop_hw_queues(dd->queue);
+       blk_set_queue_dying(dd->queue);
+       set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
+
        /* Clean up the block layer. */
        mtip_block_remove(dd);
 
index 3274784008ebc9ef4fcfe65b47ee1bc0306223f9..7617888f79449d55ac9402bfef7f01788ef138cf 100644 (file)
@@ -134,16 +134,24 @@ enum {
        MTIP_PF_EH_ACTIVE_BIT       = 1, /* error handling */
        MTIP_PF_SE_ACTIVE_BIT       = 2, /* secure erase */
        MTIP_PF_DM_ACTIVE_BIT       = 3, /* download microcde */
+       MTIP_PF_TO_ACTIVE_BIT       = 9, /* timeout handling */
        MTIP_PF_PAUSE_IO      = ((1 << MTIP_PF_IC_ACTIVE_BIT) |
                                (1 << MTIP_PF_EH_ACTIVE_BIT) |
                                (1 << MTIP_PF_SE_ACTIVE_BIT) |
-                               (1 << MTIP_PF_DM_ACTIVE_BIT)),
+                               (1 << MTIP_PF_DM_ACTIVE_BIT) |
+                               (1 << MTIP_PF_TO_ACTIVE_BIT)),
 
        MTIP_PF_SVC_THD_ACTIVE_BIT  = 4,
        MTIP_PF_ISSUE_CMDS_BIT      = 5,
        MTIP_PF_REBUILD_BIT         = 6,
        MTIP_PF_SVC_THD_STOP_BIT    = 8,
 
+       MTIP_PF_SVC_THD_WORK    = ((1 << MTIP_PF_EH_ACTIVE_BIT) |
+                                 (1 << MTIP_PF_ISSUE_CMDS_BIT) |
+                                 (1 << MTIP_PF_REBUILD_BIT) |
+                                 (1 << MTIP_PF_SVC_THD_STOP_BIT) |
+                                 (1 << MTIP_PF_TO_ACTIVE_BIT)),
+
        /* below are bit numbers in 'dd_flag' defined in driver_data */
        MTIP_DDF_SEC_LOCK_BIT       = 0,
        MTIP_DDF_REMOVE_PENDING_BIT = 1,
@@ -153,6 +161,7 @@ enum {
        MTIP_DDF_RESUME_BIT         = 6,
        MTIP_DDF_INIT_DONE_BIT      = 7,
        MTIP_DDF_REBUILD_FAILED_BIT = 8,
+       MTIP_DDF_REMOVAL_BIT        = 9,
 
        MTIP_DDF_STOP_IO      = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) |
                                (1 << MTIP_DDF_SEC_LOCK_BIT) |
index 93b3f99b6865fe721f7124412553cadf3c328e7a..8f1ce6d57a08066878c171028564c49b288ac574 100644 (file)
@@ -618,8 +618,8 @@ static void nbd_request_handler(struct request_queue *q)
                        req, req->cmd_type);
 
                if (unlikely(!nbd->sock)) {
-                       dev_err(disk_to_dev(nbd->disk),
-                               "Attempted send on closed socket\n");
+                       dev_err_ratelimited(disk_to_dev(nbd->disk),
+                                           "Attempted send on closed socket\n");
                        req->errors++;
                        nbd_end_request(nbd, req);
                        spin_lock_irq(q->queue_lock);
index 562b5a4ca7b712f6b2b4440375904d8be1ac5200..78a39f736c64f7edb6eb5d721e391d9e25f4a113 100644 (file)
 */
 #include <linux/types.h>
 
-static bool verbose = 0;
+static int verbose = 0;
 static int major = PD_MAJOR;
 static char *name = PD_NAME;
 static int cluster = 64;
@@ -161,7 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
 static DEFINE_MUTEX(pd_mutex);
 static DEFINE_SPINLOCK(pd_lock);
 
-module_param(verbose, bool, 0);
+module_param(verbose, int, 0);
 module_param(major, int, 0);
 module_param(name, charp, 0);
 module_param(cluster, int, 0);
index 1740d75e8a3239d80ed1580e96fe92028da2f827..216a94fed5b420bd59627643730d3284308367e7 100644 (file)
 
 */
 
-static bool verbose = 0;
+static int verbose = 0;
 static int major = PT_MAJOR;
 static char *name = PT_NAME;
 static int disable = 0;
@@ -152,7 +152,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
 
 #include <asm/uaccess.h>
 
-module_param(verbose, bool, 0);
+module_param(verbose, int, 0);
 module_param(major, int, 0);
 module_param(name, charp, 0);
 module_param_array(drive0, int, NULL, 0);
index 81ea69fee7ca183313b8e8322833062262279187..fbdddd6f94b8dcabfca98d0204e65b9c85485da5 100644 (file)
@@ -1955,7 +1955,7 @@ static struct ceph_osd_request *rbd_osd_req_create(
 
        osdc = &rbd_dev->rbd_client->client->osdc;
        osd_req = ceph_osdc_alloc_request(osdc, snapc, num_ops, false,
-                                         GFP_ATOMIC);
+                                         GFP_NOIO);
        if (!osd_req)
                return NULL;    /* ENOMEM */
 
@@ -2004,7 +2004,7 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
        rbd_dev = img_request->rbd_dev;
        osdc = &rbd_dev->rbd_client->client->osdc;
        osd_req = ceph_osdc_alloc_request(osdc, snapc, num_osd_ops,
-                                               false, GFP_ATOMIC);
+                                               false, GFP_NOIO);
        if (!osd_req)
                return NULL;    /* ENOMEM */
 
@@ -2506,7 +2506,7 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                                        bio_chain_clone_range(&bio_list,
                                                                &bio_offset,
                                                                clone_size,
-                                                               GFP_ATOMIC);
+                                                               GFP_NOIO);
                        if (!obj_request->bio_list)
                                goto out_unwind;
                } else if (type == OBJ_REQUEST_PAGES) {
index fa893c3ec4087f39382f3dc83b968c9859f41cca..0beaa52df66be95ede3725e0d84315df3ef368d2 100644 (file)
@@ -82,6 +82,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0489, 0xe05f) },
        { USB_DEVICE(0x0489, 0xe076) },
        { USB_DEVICE(0x0489, 0xe078) },
+       { USB_DEVICE(0x0489, 0xe095) },
        { USB_DEVICE(0x04c5, 0x1330) },
        { USB_DEVICE(0x04CA, 0x3004) },
        { USB_DEVICE(0x04CA, 0x3005) },
@@ -92,6 +93,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x300d) },
        { USB_DEVICE(0x04CA, 0x300f) },
        { USB_DEVICE(0x04CA, 0x3010) },
+       { USB_DEVICE(0x04CA, 0x3014) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0930, 0x021c) },
        { USB_DEVICE(0x0930, 0x0220) },
@@ -113,10 +115,12 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x13d3, 0x3375) },
        { USB_DEVICE(0x13d3, 0x3393) },
+       { USB_DEVICE(0x13d3, 0x3395) },
        { USB_DEVICE(0x13d3, 0x3402) },
        { USB_DEVICE(0x13d3, 0x3408) },
        { USB_DEVICE(0x13d3, 0x3423) },
        { USB_DEVICE(0x13d3, 0x3432) },
+       { USB_DEVICE(0x13d3, 0x3472) },
        { USB_DEVICE(0x13d3, 0x3474) },
 
        /* Atheros AR5BBU12 with sflash firmware */
@@ -144,6 +148,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe095), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
@@ -154,6 +159,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -175,10 +181,12 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3395), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
index 968897108c76c00d39ac528edfa29012a27ec5a5..79107597a594425196c6d3ecf17fbd930209219a 100644 (file)
@@ -196,6 +196,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe095), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
@@ -206,6 +207,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -227,10 +229,12 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3395), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
index e98d15eaa7994c7349d1db8df4dd19f684b85ba6..1827fc4d15c1a710103c4daf7a62a6067989422a 100644 (file)
@@ -150,7 +150,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
                        return ret;
        }
 
-       for_each_child_of_node(pdev->dev.of_node, child) {
+       for_each_available_child_of_node(pdev->dev.of_node, child) {
                if (!child->name)
                        continue;
 
index 45cc39aabeeeb8fde7967971516a4efad50d2caa..252142524ff21606687a51f5cfab829ccc83c7f6 100644 (file)
@@ -136,11 +136,13 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
        chip->cdev.owner = chip->pdev->driver->owner;
        chip->cdev.kobj.parent = &chip->dev.kobj;
 
+       devm_add_action(dev, (void (*)(void *)) put_device, &chip->dev);
+
        return chip;
 }
 EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
 
-static int tpm_dev_add_device(struct tpm_chip *chip)
+static int tpm_add_char_device(struct tpm_chip *chip)
 {
        int rc;
 
@@ -151,7 +153,6 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
-               device_unregister(&chip->dev);
                return rc;
        }
 
@@ -162,16 +163,17 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
                        chip->devname, MAJOR(chip->dev.devt),
                        MINOR(chip->dev.devt), rc);
 
+               cdev_del(&chip->cdev);
                return rc;
        }
 
        return rc;
 }
 
-static void tpm_dev_del_device(struct tpm_chip *chip)
+static void tpm_del_char_device(struct tpm_chip *chip)
 {
        cdev_del(&chip->cdev);
-       device_unregister(&chip->dev);
+       device_del(&chip->dev);
 }
 
 static int tpm1_chip_register(struct tpm_chip *chip)
@@ -222,7 +224,7 @@ int tpm_chip_register(struct tpm_chip *chip)
 
        tpm_add_ppi(chip);
 
-       rc = tpm_dev_add_device(chip);
+       rc = tpm_add_char_device(chip);
        if (rc)
                goto out_err;
 
@@ -274,6 +276,6 @@ void tpm_chip_unregister(struct tpm_chip *chip)
                sysfs_remove_link(&chip->pdev->kobj, "ppi");
 
        tpm1_chip_unregister(chip);
-       tpm_dev_del_device(chip);
+       tpm_del_char_device(chip);
 }
 EXPORT_SYMBOL_GPL(tpm_chip_unregister);
index 4bb9727c1047172f70b77db1649729597da1ce52..61e64293b7654b36d5db6b320d1bc78100379eb3 100644 (file)
@@ -310,11 +310,11 @@ static int crb_acpi_remove(struct acpi_device *device)
        struct device *dev = &device->dev;
        struct tpm_chip *chip = dev_get_drvdata(dev);
 
-       tpm_chip_unregister(chip);
-
        if (chip->flags & TPM_CHIP_FLAG_TPM2)
                tpm2_shutdown(chip, TPM2_SU_CLEAR);
 
+       tpm_chip_unregister(chip);
+
        return 0;
 }
 
index bd72fb04225e43f8ae21acba1cc5ddb351701c5d..4e6940acf639b00333baed9660567d81e4b75bf0 100644 (file)
@@ -232,7 +232,7 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
 {
        struct tcpa_event *event = v;
        struct tcpa_event temp_event;
-       char *tempPtr;
+       char *temp_ptr;
        int i;
 
        memcpy(&temp_event, event, sizeof(struct tcpa_event));
@@ -242,10 +242,16 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
        temp_event.event_type = do_endian_conversion(event->event_type);
        temp_event.event_size = do_endian_conversion(event->event_size);
 
-       tempPtr = (char *)&temp_event;
+       temp_ptr = (char *) &temp_event;
 
-       for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++)
-               seq_putc(m, tempPtr[i]);
+       for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
+               seq_putc(m, temp_ptr[i]);
+
+       temp_ptr = (char *) v;
+
+       for (i = (sizeof(struct tcpa_event) - 1);
+            i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
+               seq_putc(m, temp_ptr[i]);
 
        return 0;
 
index 39bf5820297e472d95e88ddc28c868a0c80b5f6c..4f9830c1b121f76c60a95203eb4ea906999b97f3 100644 (file)
@@ -1097,13 +1097,15 @@ static int bcm2835_pll_divider_set_rate(struct clk_hw *hw,
        struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw);
        struct bcm2835_cprman *cprman = divider->cprman;
        const struct bcm2835_pll_divider_data *data = divider->data;
-       u32 cm;
-       int ret;
+       u32 cm, div, max_div = 1 << A2W_PLL_DIV_BITS;
 
-       ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
-       if (ret)
-               return ret;
+       div = DIV_ROUND_UP_ULL(parent_rate, rate);
+
+       div = min(div, max_div);
+       if (div == max_div)
+               div = 0;
 
+       cprman_write(cprman, data->a2w_reg, div);
        cm = cprman_read(cprman, data->cm_reg);
        cprman_write(cprman, data->cm_reg, cm | data->load_mask);
        cprman_write(cprman, data->cm_reg, cm & ~data->load_mask);
index c83ae1367abc1791618b858fe3544211c12dfaaf..d920d410b51d2fb586c26a41fb989b68836d9751 100644 (file)
@@ -198,7 +198,7 @@ meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
 }
 
 void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
-                                   size_t nr_confs,
+                                   unsigned int nr_confs,
                                    void __iomem *clk_base)
 {
        unsigned int i;
index 66c18bc97857d8d7cf75318fe91a153dcb3945d1..bdc4b2d07a23e6ed10122dd2d04d1c865dd4b1c8 100644 (file)
@@ -2753,7 +2753,7 @@ static struct clk_rcg ce3_src = {
        },
        .freq_tbl = clk_tbl_ce3,
        .clkr = {
-               .enable_reg = 0x2c08,
+               .enable_reg = 0x36c0,
                .enable_mask = BIT(7),
                .hw.init = &(struct clk_init_data){
                        .name = "ce3_src",
@@ -2769,7 +2769,7 @@ static struct clk_branch ce3_core_clk = {
        .halt_reg = 0x2fdc,
        .halt_bit = 5,
        .clkr = {
-               .enable_reg = 0x36c4,
+               .enable_reg = 0x36cc,
                .enable_mask = BIT(4),
                .hw.init = &(struct clk_init_data){
                        .name = "ce3_core_clk",
index 0f78d7353d17e8d950bb457247ffa9feb14ed2e5..2643a85b38fe68c529a925d68e6b340c326b0dc7 100644 (file)
@@ -754,6 +754,7 @@ static const char *const rk3188_critical_clocks[] __initconst = {
        "hclk_peri",
        "pclk_cpu",
        "pclk_peri",
+       "hclk_cpubus"
 };
 
 static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np)
index c5fd146c8cf2afc7c59f14710cf1fe1ba273eccf..277f9270bf728f4bdc804fea58d037d3627ccedd 100644 (file)
@@ -73,7 +73,7 @@ static struct clk *rockchip_clk_register_branch(const char *name,
        if (gate_offset >= 0) {
                gate = kzalloc(sizeof(*gate), GFP_KERNEL);
                if (!gate)
-                       return ERR_PTR(-ENOMEM);
+                       goto err_gate;
 
                gate->flags = gate_flags;
                gate->reg = base + gate_offset;
@@ -85,7 +85,7 @@ static struct clk *rockchip_clk_register_branch(const char *name,
        if (div_width > 0) {
                div = kzalloc(sizeof(*div), GFP_KERNEL);
                if (!div)
-                       return ERR_PTR(-ENOMEM);
+                       goto err_div;
 
                div->flags = div_flags;
                div->reg = base + muxdiv_offset;
@@ -105,6 +105,11 @@ static struct clk *rockchip_clk_register_branch(const char *name,
                                     flags);
 
        return clk;
+err_div:
+       kfree(gate);
+err_gate:
+       kfree(mux);
+       return ERR_PTR(-ENOMEM);
 }
 
 struct rockchip_clk_frac {
index a1cdef6b0f9045be6dd3e47b712f02b8e485de50..897c36c1754adbbafa4274e618427b1b7b826e2b 100644 (file)
@@ -92,6 +92,7 @@ static void __init clk_sp810_of_setup(struct device_node *node)
        int num = ARRAY_SIZE(parent_names);
        char name[12];
        struct clk_init_data init;
+       static int instance;
        int i;
        bool deprecated;
 
@@ -118,7 +119,7 @@ static void __init clk_sp810_of_setup(struct device_node *node)
        deprecated = !of_find_property(node, "assigned-clock-parents", NULL);
 
        for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
-               snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+               snprintf(name, sizeof(name), "sp810_%d_%d", instance, i);
 
                sp810->timerclken[i].sp810 = sp810;
                sp810->timerclken[i].channel = i;
@@ -139,5 +140,6 @@ static void __init clk_sp810_of_setup(struct device_node *node)
        }
 
        of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810);
+       instance++;
 }
 CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup);
index 90d64081ddb34ee8ba7a06372a269defdcf07a97..f951f911786e086b2b6dc9d615018eb235347dbe 100644 (file)
@@ -31,9 +31,8 @@
 
 struct private_data {
        struct device *cpu_dev;
-       struct regulator *cpu_reg;
        struct thermal_cooling_device *cdev;
-       unsigned int voltage_tolerance; /* in percentage */
+       const char *reg_name;
 };
 
 static struct freq_attr *cpufreq_dt_attr[] = {
@@ -44,175 +43,128 @@ static struct freq_attr *cpufreq_dt_attr[] = {
 
 static int set_target(struct cpufreq_policy *policy, unsigned int index)
 {
-       struct dev_pm_opp *opp;
-       struct cpufreq_frequency_table *freq_table = policy->freq_table;
-       struct clk *cpu_clk = policy->clk;
        struct private_data *priv = policy->driver_data;
-       struct device *cpu_dev = priv->cpu_dev;
-       struct regulator *cpu_reg = priv->cpu_reg;
-       unsigned long volt = 0, volt_old = 0, tol = 0;
-       unsigned int old_freq, new_freq;
-       long freq_Hz, freq_exact;
-       int ret;
-
-       freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
-       if (freq_Hz <= 0)
-               freq_Hz = freq_table[index].frequency * 1000;
 
-       freq_exact = freq_Hz;
-       new_freq = freq_Hz / 1000;
-       old_freq = clk_get_rate(cpu_clk) / 1000;
+       return dev_pm_opp_set_rate(priv->cpu_dev,
+                                  policy->freq_table[index].frequency * 1000);
+}
 
-       if (!IS_ERR(cpu_reg)) {
-               unsigned long opp_freq;
+/*
+ * An earlier version of opp-v1 bindings used to name the regulator
+ * "cpu0-supply", we still need to handle that for backwards compatibility.
+ */
+static const char *find_supply_name(struct device *dev)
+{
+       struct device_node *np;
+       struct property *pp;
+       int cpu = dev->id;
+       const char *name = NULL;
 
-               rcu_read_lock();
-               opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
-               if (IS_ERR(opp)) {
-                       rcu_read_unlock();
-                       dev_err(cpu_dev, "failed to find OPP for %ld\n",
-                               freq_Hz);
-                       return PTR_ERR(opp);
-               }
-               volt = dev_pm_opp_get_voltage(opp);
-               opp_freq = dev_pm_opp_get_freq(opp);
-               rcu_read_unlock();
-               tol = volt * priv->voltage_tolerance / 100;
-               volt_old = regulator_get_voltage(cpu_reg);
-               dev_dbg(cpu_dev, "Found OPP: %ld kHz, %ld uV\n",
-                       opp_freq / 1000, volt);
-       }
+       np = of_node_get(dev->of_node);
 
-       dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
-               old_freq / 1000, (volt_old > 0) ? volt_old / 1000 : -1,
-               new_freq / 1000, volt ? volt / 1000 : -1);
+       /* This must be valid for sure */
+       if (WARN_ON(!np))
+               return NULL;
 
-       /* scaling up?  scale voltage before frequency */
-       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
-               ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
-               if (ret) {
-                       dev_err(cpu_dev, "failed to scale voltage up: %d\n",
-                               ret);
-                       return ret;
+       /* Try "cpu0" for older DTs */
+       if (!cpu) {
+               pp = of_find_property(np, "cpu0-supply", NULL);
+               if (pp) {
+                       name = "cpu0";
+                       goto node_put;
                }
        }
 
-       ret = clk_set_rate(cpu_clk, freq_exact);
-       if (ret) {
-               dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
-               if (!IS_ERR(cpu_reg) && volt_old > 0)
-                       regulator_set_voltage_tol(cpu_reg, volt_old, tol);
-               return ret;
+       pp = of_find_property(np, "cpu-supply", NULL);
+       if (pp) {
+               name = "cpu";
+               goto node_put;
        }
 
-       /* scaling down?  scale voltage after frequency */
-       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
-               ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
-               if (ret) {
-                       dev_err(cpu_dev, "failed to scale voltage down: %d\n",
-                               ret);
-                       clk_set_rate(cpu_clk, old_freq * 1000);
-               }
-       }
-
-       return ret;
+       dev_dbg(dev, "no regulator for cpu%d\n", cpu);
+node_put:
+       of_node_put(np);
+       return name;
 }
 
-static int allocate_resources(int cpu, struct device **cdev,
-                             struct regulator **creg, struct clk **cclk)
+static int resources_available(void)
 {
        struct device *cpu_dev;
        struct regulator *cpu_reg;
        struct clk *cpu_clk;
        int ret = 0;
-       char *reg_cpu0 = "cpu0", *reg_cpu = "cpu", *reg;
+       const char *name;
 
-       cpu_dev = get_cpu_device(cpu);
+       cpu_dev = get_cpu_device(0);
        if (!cpu_dev) {
-               pr_err("failed to get cpu%d device\n", cpu);
+               pr_err("failed to get cpu0 device\n");
                return -ENODEV;
        }
 
-       /* Try "cpu0" for older DTs */
-       if (!cpu)
-               reg = reg_cpu0;
-       else
-               reg = reg_cpu;
-
-try_again:
-       cpu_reg = regulator_get_optional(cpu_dev, reg);
-       if (IS_ERR(cpu_reg)) {
+       cpu_clk = clk_get(cpu_dev, NULL);
+       ret = PTR_ERR_OR_ZERO(cpu_clk);
+       if (ret) {
                /*
-                * If cpu's regulator supply node is present, but regulator is
-                * not yet registered, we should try defering probe.
+                * If cpu's clk node is present, but clock is not yet
+                * registered, we should try defering probe.
                 */
-               if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) {
-                       dev_dbg(cpu_dev, "cpu%d regulator not ready, retry\n",
-                               cpu);
-                       return -EPROBE_DEFER;
-               }
-
-               /* Try with "cpu-supply" */
-               if (reg == reg_cpu0) {
-                       reg = reg_cpu;
-                       goto try_again;
-               }
+               if (ret == -EPROBE_DEFER)
+                       dev_dbg(cpu_dev, "clock not ready, retry\n");
+               else
+                       dev_err(cpu_dev, "failed to get clock: %d\n", ret);
 
-               dev_dbg(cpu_dev, "no regulator for cpu%d: %ld\n",
-                       cpu, PTR_ERR(cpu_reg));
+               return ret;
        }
 
-       cpu_clk = clk_get(cpu_dev, NULL);
-       if (IS_ERR(cpu_clk)) {
-               /* put regulator */
-               if (!IS_ERR(cpu_reg))
-                       regulator_put(cpu_reg);
+       clk_put(cpu_clk);
 
-               ret = PTR_ERR(cpu_clk);
+       name = find_supply_name(cpu_dev);
+       /* Platform doesn't require regulator */
+       if (!name)
+               return 0;
 
+       cpu_reg = regulator_get_optional(cpu_dev, name);
+       ret = PTR_ERR_OR_ZERO(cpu_reg);
+       if (ret) {
                /*
-                * If cpu's clk node is present, but clock is not yet
-                * registered, we should try defering probe.
+                * If cpu's regulator supply node is present, but regulator is
+                * not yet registered, we should try defering probe.
                 */
                if (ret == -EPROBE_DEFER)
-                       dev_dbg(cpu_dev, "cpu%d clock not ready, retry\n", cpu);
+                       dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n");
                else
-                       dev_err(cpu_dev, "failed to get cpu%d clock: %d\n", cpu,
-                               ret);
-       } else {
-               *cdev = cpu_dev;
-               *creg = cpu_reg;
-               *cclk = cpu_clk;
+                       dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret);
+
+               return ret;
        }
 
-       return ret;
+       regulator_put(cpu_reg);
+       return 0;
 }
 
 static int cpufreq_init(struct cpufreq_policy *policy)
 {
        struct cpufreq_frequency_table *freq_table;
-       struct device_node *np;
        struct private_data *priv;
        struct device *cpu_dev;
-       struct regulator *cpu_reg;
        struct clk *cpu_clk;
        struct dev_pm_opp *suspend_opp;
-       unsigned long min_uV = ~0, max_uV = 0;
        unsigned int transition_latency;
-       bool need_update = false;
+       bool opp_v1 = false;
+       const char *name;
        int ret;
 
-       ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk);
-       if (ret) {
-               pr_err("%s: Failed to allocate resources: %d\n", __func__, ret);
-               return ret;
+       cpu_dev = get_cpu_device(policy->cpu);
+       if (!cpu_dev) {
+               pr_err("failed to get cpu%d device\n", policy->cpu);
+               return -ENODEV;
        }
 
-       np = of_node_get(cpu_dev->of_node);
-       if (!np) {
-               dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu);
-               ret = -ENOENT;
-               goto out_put_reg_clk;
+       cpu_clk = clk_get(cpu_dev, NULL);
+       if (IS_ERR(cpu_clk)) {
+               ret = PTR_ERR(cpu_clk);
+               dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret);
+               return ret;
        }
 
        /* Get OPP-sharing information from "operating-points-v2" bindings */
@@ -223,9 +175,23 @@ static int cpufreq_init(struct cpufreq_policy *policy)
                 * finding shared-OPPs for backward compatibility.
                 */
                if (ret == -ENOENT)
-                       need_update = true;
+                       opp_v1 = true;
                else
-                       goto out_node_put;
+                       goto out_put_clk;
+       }
+
+       /*
+        * OPP layer will be taking care of regulators now, but it needs to know
+        * the name of the regulator first.
+        */
+       name = find_supply_name(cpu_dev);
+       if (name) {
+               ret = dev_pm_opp_set_regulator(cpu_dev, name);
+               if (ret) {
+                       dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
+                               policy->cpu, ret);
+                       goto out_put_clk;
+               }
        }
 
        /*
@@ -246,12 +212,12 @@ static int cpufreq_init(struct cpufreq_policy *policy)
         */
        ret = dev_pm_opp_get_opp_count(cpu_dev);
        if (ret <= 0) {
-               pr_debug("OPP table is not ready, deferring probe\n");
+               dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
                ret = -EPROBE_DEFER;
                goto out_free_opp;
        }
 
-       if (need_update) {
+       if (opp_v1) {
                struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data();
 
                if (!pd || !pd->independent_clocks)
@@ -265,10 +231,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
                if (ret)
                        dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
                                __func__, ret);
-
-               of_property_read_u32(np, "clock-latency", &transition_latency);
-       } else {
-               transition_latency = dev_pm_opp_get_max_clock_latency(cpu_dev);
        }
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -277,62 +239,16 @@ static int cpufreq_init(struct cpufreq_policy *policy)
                goto out_free_opp;
        }
 
-       of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
-
-       if (!transition_latency)
-               transition_latency = CPUFREQ_ETERNAL;
-
-       if (!IS_ERR(cpu_reg)) {
-               unsigned long opp_freq = 0;
-
-               /*
-                * Disable any OPPs where the connected regulator isn't able to
-                * provide the specified voltage and record minimum and maximum
-                * voltage levels.
-                */
-               while (1) {
-                       struct dev_pm_opp *opp;
-                       unsigned long opp_uV, tol_uV;
-
-                       rcu_read_lock();
-                       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq);
-                       if (IS_ERR(opp)) {
-                               rcu_read_unlock();
-                               break;
-                       }
-                       opp_uV = dev_pm_opp_get_voltage(opp);
-                       rcu_read_unlock();
-
-                       tol_uV = opp_uV * priv->voltage_tolerance / 100;
-                       if (regulator_is_supported_voltage(cpu_reg,
-                                                          opp_uV - tol_uV,
-                                                          opp_uV + tol_uV)) {
-                               if (opp_uV < min_uV)
-                                       min_uV = opp_uV;
-                               if (opp_uV > max_uV)
-                                       max_uV = opp_uV;
-                       } else {
-                               dev_pm_opp_disable(cpu_dev, opp_freq);
-                       }
-
-                       opp_freq++;
-               }
-
-               ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
-               if (ret > 0)
-                       transition_latency += ret * 1000;
-       }
+       priv->reg_name = name;
 
        ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
        if (ret) {
-               pr_err("failed to init cpufreq table: %d\n", ret);
+               dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
                goto out_free_priv;
        }
 
        priv->cpu_dev = cpu_dev;
-       priv->cpu_reg = cpu_reg;
        policy->driver_data = priv;
-
        policy->clk = cpu_clk;
 
        rcu_read_lock();
@@ -357,9 +273,11 @@ static int cpufreq_init(struct cpufreq_policy *policy)
                cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
        }
 
-       policy->cpuinfo.transition_latency = transition_latency;
+       transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
+       if (!transition_latency)
+               transition_latency = CPUFREQ_ETERNAL;
 
-       of_node_put(np);
+       policy->cpuinfo.transition_latency = transition_latency;
 
        return 0;
 
@@ -369,12 +287,10 @@ out_free_priv:
        kfree(priv);
 out_free_opp:
        dev_pm_opp_of_cpumask_remove_table(policy->cpus);
-out_node_put:
-       of_node_put(np);
-out_put_reg_clk:
+       if (name)
+               dev_pm_opp_put_regulator(cpu_dev);
+out_put_clk:
        clk_put(cpu_clk);
-       if (!IS_ERR(cpu_reg))
-               regulator_put(cpu_reg);
 
        return ret;
 }
@@ -386,9 +302,10 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
        cpufreq_cooling_unregister(priv->cdev);
        dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
        dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+       if (priv->reg_name)
+               dev_pm_opp_put_regulator(priv->cpu_dev);
+
        clk_put(policy->clk);
-       if (!IS_ERR(priv->cpu_reg))
-               regulator_put(priv->cpu_reg);
        kfree(priv);
 
        return 0;
@@ -407,8 +324,13 @@ static void cpufreq_ready(struct cpufreq_policy *policy)
         * thermal DT code takes care of matching them.
         */
        if (of_find_property(np, "#cooling-cells", NULL)) {
-               priv->cdev = of_cpufreq_cooling_register(np,
-                                                        policy->related_cpus);
+               u32 power_coefficient = 0;
+
+               of_property_read_u32(np, "dynamic-power-coefficient",
+                                    &power_coefficient);
+
+               priv->cdev = of_cpufreq_power_cooling_register(np,
+                               policy->related_cpus, power_coefficient, NULL);
                if (IS_ERR(priv->cdev)) {
                        dev_err(priv->cpu_dev,
                                "running cpufreq without cooling device: %ld\n",
@@ -436,9 +358,6 @@ static struct cpufreq_driver dt_cpufreq_driver = {
 
 static int dt_cpufreq_probe(struct platform_device *pdev)
 {
-       struct device *cpu_dev;
-       struct regulator *cpu_reg;
-       struct clk *cpu_clk;
        int ret;
 
        /*
@@ -448,19 +367,15 @@ static int dt_cpufreq_probe(struct platform_device *pdev)
         *
         * FIXME: Is checking this only for CPU0 sufficient ?
         */
-       ret = allocate_resources(0, &cpu_dev, &cpu_reg, &cpu_clk);
+       ret = resources_available();
        if (ret)
                return ret;
 
-       clk_put(cpu_clk);
-       if (!IS_ERR(cpu_reg))
-               regulator_put(cpu_reg);
-
        dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev);
 
        ret = cpufreq_register_driver(&dt_cpufreq_driver);
        if (ret)
-               dev_err(cpu_dev, "failed register driver: %d\n", ret);
+               dev_err(&pdev->dev, "failed register driver: %d\n", ret);
 
        return ret;
 }
index 25dd5885d1a024d467b2c3f1b012afa33d4a7063..1cfbcb8ba75cff600f57be9217abf1fc3e271241 100644 (file)
@@ -489,6 +489,58 @@ static void cpufreq_interactive_idle_end(void)
        up_read(&pcpu->enable_sem);
 }
 
+static void cpufreq_interactive_get_policy_info(struct cpufreq_policy *policy,
+                                               unsigned int *pmax_freq,
+                                               u64 *phvt, u64 *pfvt)
+{
+       struct cpufreq_interactive_cpuinfo *pcpu;
+       unsigned int max_freq = 0;
+       u64 hvt = ~0ULL, fvt = 0;
+       unsigned int i;
+
+       for_each_cpu(i, policy->cpus) {
+               pcpu = &per_cpu(cpuinfo, i);
+
+               fvt = max(fvt, pcpu->loc_floor_val_time);
+               if (pcpu->target_freq > max_freq) {
+                       max_freq = pcpu->target_freq;
+                       hvt = pcpu->loc_hispeed_val_time;
+               } else if (pcpu->target_freq == max_freq) {
+                       hvt = min(hvt, pcpu->loc_hispeed_val_time);
+               }
+       }
+
+       *pmax_freq = max_freq;
+       *phvt = hvt;
+       *pfvt = fvt;
+}
+
+static void cpufreq_interactive_adjust_cpu(unsigned int cpu,
+                                          struct cpufreq_policy *policy)
+{
+       struct cpufreq_interactive_cpuinfo *pcpu;
+       u64 hvt, fvt;
+       unsigned int max_freq;
+       int i;
+
+       cpufreq_interactive_get_policy_info(policy, &max_freq, &hvt, &fvt);
+
+       for_each_cpu(i, policy->cpus) {
+               pcpu = &per_cpu(cpuinfo, i);
+               pcpu->pol_floor_val_time = fvt;
+       }
+
+       if (max_freq != policy->cur) {
+               __cpufreq_driver_target(policy, max_freq, CPUFREQ_RELATION_H);
+               for_each_cpu(i, policy->cpus) {
+                       pcpu = &per_cpu(cpuinfo, i);
+                       pcpu->pol_hispeed_val_time = hvt;
+               }
+       }
+
+       trace_cpufreq_interactive_setspeed(cpu, max_freq, policy->cur);
+}
+
 static int cpufreq_interactive_speedchange_task(void *data)
 {
        unsigned int cpu;
@@ -517,49 +569,18 @@ static int cpufreq_interactive_speedchange_task(void *data)
                spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
 
                for_each_cpu(cpu, &tmp_mask) {
-                       unsigned int j;
-                       unsigned int max_freq = 0;
-                       struct cpufreq_interactive_cpuinfo *pjcpu;
-                       u64 hvt = ~0ULL, fvt = 0;
-
                        pcpu = &per_cpu(cpuinfo, cpu);
-                       if (!down_read_trylock(&pcpu->enable_sem))
-                               continue;
-                       if (!pcpu->governor_enabled) {
-                               up_read(&pcpu->enable_sem);
-                               continue;
-                       }
-
-                       for_each_cpu(j, pcpu->policy->cpus) {
-                               pjcpu = &per_cpu(cpuinfo, j);
 
-                               fvt = max(fvt, pjcpu->loc_floor_val_time);
-                               if (pjcpu->target_freq > max_freq) {
-                                       max_freq = pjcpu->target_freq;
-                                       hvt = pjcpu->loc_hispeed_val_time;
-                               } else if (pjcpu->target_freq == max_freq) {
-                                       hvt = min(hvt, pjcpu->loc_hispeed_val_time);
-                               }
-                       }
-                       for_each_cpu(j, pcpu->policy->cpus) {
-                               pjcpu = &per_cpu(cpuinfo, j);
-                               pjcpu->pol_floor_val_time = fvt;
-                       }
+                       down_write(&pcpu->policy->rwsem);
 
-                       if (max_freq != pcpu->policy->cur) {
-                               __cpufreq_driver_target(pcpu->policy,
-                                                       max_freq,
-                                                       CPUFREQ_RELATION_H);
-                               for_each_cpu(j, pcpu->policy->cpus) {
-                                       pjcpu = &per_cpu(cpuinfo, j);
-                                       pjcpu->pol_hispeed_val_time = hvt;
-                               }
+                       if (likely(down_read_trylock(&pcpu->enable_sem))) {
+                               if (likely(pcpu->governor_enabled))
+                                       cpufreq_interactive_adjust_cpu(cpu,
+                                                       pcpu->policy);
+                               up_read(&pcpu->enable_sem);
                        }
-                       trace_cpufreq_interactive_setspeed(cpu,
-                                                    pcpu->target_freq,
-                                                    pcpu->policy->cur);
 
-                       up_read(&pcpu->enable_sem);
+                       up_write(&pcpu->policy->rwsem);
                }
        }
 
@@ -579,8 +600,19 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab
 
        for_each_online_cpu(i) {
                pcpu = &per_cpu(cpuinfo, i);
-               if (tunables != pcpu->policy->governor_data)
+
+               if (!down_read_trylock(&pcpu->enable_sem))
+                       continue;
+
+               if (!pcpu->governor_enabled) {
+                       up_read(&pcpu->enable_sem);
+                       continue;
+               }
+
+               if (tunables != pcpu->policy->governor_data) {
+                       up_read(&pcpu->enable_sem);
                        continue;
+               }
 
                spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]);
                if (pcpu->target_freq < tunables->hispeed_freq) {
@@ -591,6 +623,8 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab
                        anyboost = 1;
                }
                spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
+
+               up_read(&pcpu->enable_sem);
        }
 
        spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
index 98fb8821382d8fc145c6bf9227b62236fdabedb1..f53b02a6bc05b935f7ed9d8b9b5ff12d50eacc34 100644 (file)
@@ -667,6 +667,11 @@ static int core_get_max_pstate(void)
                        if (err)
                                goto skip_tar;
 
+                       /* For level 1 and 2, bits[23:16] contain the ratio */
+                       if (tdp_ctrl)
+                               tdp_ratio >>= 16;
+
+                       tdp_ratio &= 0xff; /* ratios are only 8 bits long */
                        if (tdp_ratio - 1 == tar) {
                                max_pstate = tar;
                                pr_debug("max_pstate=TAC %x\n", max_pstate);
index 545069d5fdfba3e7ab07f0ec296404c64ad2a977..e342565e8715e95af6c76a80ca393d8fcfada66a 100644 (file)
@@ -50,7 +50,7 @@ static int arm_enter_idle_state(struct cpuidle_device *dev,
                 * call the CPU ops suspend protocol with idle index as a
                 * parameter.
                 */
-               arm_cpuidle_suspend(idx);
+               ret = arm_cpuidle_suspend(idx);
 
                cpu_pm_exit();
        }
index fb16d812c8f555493f3a2527c0c551bc6de59139..1dffb13e5c2f8134fedb1a84b2cef3daef10fdce 100644 (file)
@@ -1396,9 +1396,9 @@ static int atmel_aes_probe(struct platform_device *pdev)
        }
 
        aes_dd->io_base = devm_ioremap_resource(&pdev->dev, aes_res);
-       if (!aes_dd->io_base) {
+       if (IS_ERR(aes_dd->io_base)) {
                dev_err(dev, "can't ioremap\n");
-               err = -ENOMEM;
+               err = PTR_ERR(aes_dd->io_base);
                goto res_err;
        }
 
index 3178f84d2757c9f3de8ea6114831d43f2eb17507..0dadb6332f0eb7621875a9f35526a33581e50cd8 100644 (file)
@@ -1405,9 +1405,9 @@ static int atmel_sha_probe(struct platform_device *pdev)
        }
 
        sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res);
-       if (!sha_dd->io_base) {
+       if (IS_ERR(sha_dd->io_base)) {
                dev_err(dev, "can't ioremap\n");
-               err = -ENOMEM;
+               err = PTR_ERR(sha_dd->io_base);
                goto res_err;
        }
 
index 2c7a628d0375fd43d80f82084b38eed009a8f032..bf467d7be35cfe2d94fccdbb884716c948017bd6 100644 (file)
@@ -1417,9 +1417,9 @@ static int atmel_tdes_probe(struct platform_device *pdev)
        }
 
        tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res);
-       if (!tdes_dd->io_base) {
+       if (IS_ERR(tdes_dd->io_base)) {
                dev_err(dev, "can't ioremap\n");
-               err = -ENOMEM;
+               err = PTR_ERR(tdes_dd->io_base);
                goto res_err;
        }
 
index d89f20c04266b31ad85bf82ccf5a2169c52ba727..60fc0fa26fd3b19ab557888d9bd6e61c208fe0f6 100644 (file)
@@ -220,6 +220,42 @@ static int ccp_aes_cmac_digest(struct ahash_request *req)
        return ccp_aes_cmac_finup(req);
 }
 
+static int ccp_aes_cmac_export(struct ahash_request *req, void *out)
+{
+       struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req);
+       struct ccp_aes_cmac_exp_ctx state;
+
+       /* Don't let anything leak to 'out' */
+       memset(&state, 0, sizeof(state));
+
+       state.null_msg = rctx->null_msg;
+       memcpy(state.iv, rctx->iv, sizeof(state.iv));
+       state.buf_count = rctx->buf_count;
+       memcpy(state.buf, rctx->buf, sizeof(state.buf));
+
+       /* 'out' may not be aligned so memcpy from local variable */
+       memcpy(out, &state, sizeof(state));
+
+       return 0;
+}
+
+static int ccp_aes_cmac_import(struct ahash_request *req, const void *in)
+{
+       struct ccp_aes_cmac_req_ctx *rctx = ahash_request_ctx(req);
+       struct ccp_aes_cmac_exp_ctx state;
+
+       /* 'in' may not be aligned so memcpy to local variable */
+       memcpy(&state, in, sizeof(state));
+
+       memset(rctx, 0, sizeof(*rctx));
+       rctx->null_msg = state.null_msg;
+       memcpy(rctx->iv, state.iv, sizeof(rctx->iv));
+       rctx->buf_count = state.buf_count;
+       memcpy(rctx->buf, state.buf, sizeof(rctx->buf));
+
+       return 0;
+}
+
 static int ccp_aes_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
                               unsigned int key_len)
 {
@@ -352,10 +388,13 @@ int ccp_register_aes_cmac_algs(struct list_head *head)
        alg->final = ccp_aes_cmac_final;
        alg->finup = ccp_aes_cmac_finup;
        alg->digest = ccp_aes_cmac_digest;
+       alg->export = ccp_aes_cmac_export;
+       alg->import = ccp_aes_cmac_import;
        alg->setkey = ccp_aes_cmac_setkey;
 
        halg = &alg->halg;
        halg->digestsize = AES_BLOCK_SIZE;
+       halg->statesize = sizeof(struct ccp_aes_cmac_exp_ctx);
 
        base = &halg->base;
        snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "cmac(aes)");
index d14b3f28e010897990223fffc8f932fe368a033d..ab9945f2cb7a1383703240025beb0a4dea4abec9 100644 (file)
@@ -207,6 +207,46 @@ static int ccp_sha_digest(struct ahash_request *req)
        return ccp_sha_finup(req);
 }
 
+static int ccp_sha_export(struct ahash_request *req, void *out)
+{
+       struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
+       struct ccp_sha_exp_ctx state;
+
+       /* Don't let anything leak to 'out' */
+       memset(&state, 0, sizeof(state));
+
+       state.type = rctx->type;
+       state.msg_bits = rctx->msg_bits;
+       state.first = rctx->first;
+       memcpy(state.ctx, rctx->ctx, sizeof(state.ctx));
+       state.buf_count = rctx->buf_count;
+       memcpy(state.buf, rctx->buf, sizeof(state.buf));
+
+       /* 'out' may not be aligned so memcpy from local variable */
+       memcpy(out, &state, sizeof(state));
+
+       return 0;
+}
+
+static int ccp_sha_import(struct ahash_request *req, const void *in)
+{
+       struct ccp_sha_req_ctx *rctx = ahash_request_ctx(req);
+       struct ccp_sha_exp_ctx state;
+
+       /* 'in' may not be aligned so memcpy to local variable */
+       memcpy(&state, in, sizeof(state));
+
+       memset(rctx, 0, sizeof(*rctx));
+       rctx->type = state.type;
+       rctx->msg_bits = state.msg_bits;
+       rctx->first = state.first;
+       memcpy(rctx->ctx, state.ctx, sizeof(rctx->ctx));
+       rctx->buf_count = state.buf_count;
+       memcpy(rctx->buf, state.buf, sizeof(rctx->buf));
+
+       return 0;
+}
+
 static int ccp_sha_setkey(struct crypto_ahash *tfm, const u8 *key,
                          unsigned int key_len)
 {
@@ -403,9 +443,12 @@ static int ccp_register_sha_alg(struct list_head *head,
        alg->final = ccp_sha_final;
        alg->finup = ccp_sha_finup;
        alg->digest = ccp_sha_digest;
+       alg->export = ccp_sha_export;
+       alg->import = ccp_sha_import;
 
        halg = &alg->halg;
        halg->digestsize = def->digest_size;
+       halg->statesize = sizeof(struct ccp_sha_exp_ctx);
 
        base = &halg->base;
        snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);
index 76a96f0f44c6d7c659c57cfed3e93928683d9687..a326ec20bfa877c1a2dce78c5f15f3a5ec0731f4 100644 (file)
@@ -129,6 +129,15 @@ struct ccp_aes_cmac_req_ctx {
        struct ccp_cmd cmd;
 };
 
+struct ccp_aes_cmac_exp_ctx {
+       unsigned int null_msg;
+
+       u8 iv[AES_BLOCK_SIZE];
+
+       unsigned int buf_count;
+       u8 buf[AES_BLOCK_SIZE];
+};
+
 /***** SHA related defines *****/
 #define MAX_SHA_CONTEXT_SIZE   SHA256_DIGEST_SIZE
 #define MAX_SHA_BLOCK_SIZE     SHA256_BLOCK_SIZE
@@ -171,6 +180,19 @@ struct ccp_sha_req_ctx {
        struct ccp_cmd cmd;
 };
 
+struct ccp_sha_exp_ctx {
+       enum ccp_sha_type type;
+
+       u64 msg_bits;
+
+       unsigned int first;
+
+       u8 ctx[MAX_SHA_CONTEXT_SIZE];
+
+       unsigned int buf_count;
+       u8 buf[MAX_SHA_BLOCK_SIZE];
+};
+
 /***** Common Context Structure *****/
 struct ccp_ctx {
        int (*complete)(struct crypto_async_request *req, int ret);
index c0656e7f37b5993672002a8a192dc1c9dcf0c4bd..80239ae69527210ef9cabf53267d40907a8df871 100644 (file)
@@ -420,7 +420,7 @@ static int mv_cesa_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
        cesa->regs = devm_ioremap_resource(dev, res);
        if (IS_ERR(cesa->regs))
-               return -ENOMEM;
+               return PTR_ERR(cesa->regs);
 
        ret = mv_cesa_dev_dma_init(cesa);
        if (ret)
index b6f9f42e2985b476ecc63ac16f648535be0cddc2..a04fea4d00637a7fa5bbab8dc701e9ea54e6dd79 100644 (file)
@@ -63,6 +63,14 @@ static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
                ptr->eptr = upper_32_bits(dma_addr);
 }
 
+static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
+                            struct talitos_ptr *src_ptr, bool is_sec1)
+{
+       dst_ptr->ptr = src_ptr->ptr;
+       if (!is_sec1)
+               dst_ptr->eptr = src_ptr->eptr;
+}
+
 static void to_talitos_ptr_len(struct talitos_ptr *ptr, unsigned int len,
                               bool is_sec1)
 {
@@ -1083,21 +1091,20 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
        sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ?: 1,
                              (areq->src == areq->dst) ? DMA_BIDIRECTIONAL
                                                           : DMA_TO_DEVICE);
-
        /* hmac data */
        desc->ptr[1].len = cpu_to_be16(areq->assoclen);
        if (sg_count > 1 &&
            (ret = sg_to_link_tbl_offset(areq->src, sg_count, 0,
                                         areq->assoclen,
                                         &edesc->link_tbl[tbl_off])) > 1) {
-               tbl_off += ret;
-
                to_talitos_ptr(&desc->ptr[1], edesc->dma_link_tbl + tbl_off *
                               sizeof(struct talitos_ptr), 0);
                desc->ptr[1].j_extent = DESC_PTR_LNKTBL_JUMP;
 
                dma_sync_single_for_device(dev, edesc->dma_link_tbl,
                                           edesc->dma_len, DMA_BIDIRECTIONAL);
+
+               tbl_off += ret;
        } else {
                to_talitos_ptr(&desc->ptr[1], sg_dma_address(areq->src), 0);
                desc->ptr[1].j_extent = 0;
@@ -1126,11 +1133,13 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
        if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV)
                sg_link_tbl_len += authsize;
 
-       if (sg_count > 1 &&
-           (ret = sg_to_link_tbl_offset(areq->src, sg_count, areq->assoclen,
-                                        sg_link_tbl_len,
-                                        &edesc->link_tbl[tbl_off])) > 1) {
-               tbl_off += ret;
+       if (sg_count == 1) {
+               to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src) +
+                              areq->assoclen, 0);
+       } else if ((ret = sg_to_link_tbl_offset(areq->src, sg_count,
+                                               areq->assoclen, sg_link_tbl_len,
+                                               &edesc->link_tbl[tbl_off])) >
+                  1) {
                desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
                to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl +
                                              tbl_off *
@@ -1138,8 +1147,10 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
                dma_sync_single_for_device(dev, edesc->dma_link_tbl,
                                           edesc->dma_len,
                                           DMA_BIDIRECTIONAL);
-       } else
-               to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src), 0);
+               tbl_off += ret;
+       } else {
+               copy_talitos_ptr(&desc->ptr[4], &edesc->link_tbl[tbl_off], 0);
+       }
 
        /* cipher out */
        desc->ptr[5].len = cpu_to_be16(cryptlen);
@@ -1151,11 +1162,13 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
 
        edesc->icv_ool = false;
 
-       if (sg_count > 1 &&
-           (sg_count = sg_to_link_tbl_offset(areq->dst, sg_count,
+       if (sg_count == 1) {
+               to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst) +
+                              areq->assoclen, 0);
+       } else if ((sg_count =
+                       sg_to_link_tbl_offset(areq->dst, sg_count,
                                              areq->assoclen, cryptlen,
-                                             &edesc->link_tbl[tbl_off])) >
-           1) {
+                                             &edesc->link_tbl[tbl_off])) > 1) {
                struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off];
 
                to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl +
@@ -1178,8 +1191,9 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
                                           edesc->dma_len, DMA_BIDIRECTIONAL);
 
                edesc->icv_ool = true;
-       } else
-               to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst), 0);
+       } else {
+               copy_talitos_ptr(&desc->ptr[5], &edesc->link_tbl[tbl_off], 0);
+       }
 
        /* iv out */
        map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv,
@@ -2519,21 +2533,11 @@ struct talitos_crypto_alg {
        struct talitos_alg_template algt;
 };
 
-static int talitos_cra_init(struct crypto_tfm *tfm)
+static int talitos_init_common(struct talitos_ctx *ctx,
+                              struct talitos_crypto_alg *talitos_alg)
 {
-       struct crypto_alg *alg = tfm->__crt_alg;
-       struct talitos_crypto_alg *talitos_alg;
-       struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
        struct talitos_private *priv;
 
-       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
-               talitos_alg = container_of(__crypto_ahash_alg(alg),
-                                          struct talitos_crypto_alg,
-                                          algt.alg.hash);
-       else
-               talitos_alg = container_of(alg, struct talitos_crypto_alg,
-                                          algt.alg.crypto);
-
        /* update context with ptr to dev */
        ctx->dev = talitos_alg->dev;
 
@@ -2551,10 +2555,33 @@ static int talitos_cra_init(struct crypto_tfm *tfm)
        return 0;
 }
 
+static int talitos_cra_init(struct crypto_tfm *tfm)
+{
+       struct crypto_alg *alg = tfm->__crt_alg;
+       struct talitos_crypto_alg *talitos_alg;
+       struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
+               talitos_alg = container_of(__crypto_ahash_alg(alg),
+                                          struct talitos_crypto_alg,
+                                          algt.alg.hash);
+       else
+               talitos_alg = container_of(alg, struct talitos_crypto_alg,
+                                          algt.alg.crypto);
+
+       return talitos_init_common(ctx, talitos_alg);
+}
+
 static int talitos_cra_init_aead(struct crypto_aead *tfm)
 {
-       talitos_cra_init(crypto_aead_tfm(tfm));
-       return 0;
+       struct aead_alg *alg = crypto_aead_alg(tfm);
+       struct talitos_crypto_alg *talitos_alg;
+       struct talitos_ctx *ctx = crypto_aead_ctx(tfm);
+
+       talitos_alg = container_of(alg, struct talitos_crypto_alg,
+                                  algt.alg.aead);
+
+       return talitos_init_common(ctx, talitos_alg);
 }
 
 static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
index 4c243c1ffc7f6d32224db88bb4c79d0810d9c87d..790f7cadc1ed8764d8e98745ff5d91819bd80733 100644 (file)
@@ -1440,9 +1440,9 @@ static int ux500_cryp_probe(struct platform_device *pdev)
 
        device_data->phybase = res->start;
        device_data->base = devm_ioremap_resource(dev, res);
-       if (!device_data->base) {
+       if (IS_ERR(device_data->base)) {
                dev_err(dev, "[%s]: ioremap failed!", __func__);
-               ret = -ENOMEM;
+               ret = PTR_ERR(device_data->base);
                goto out;
        }
 
index f47d112041b2173d0f25c0ce9069729000e04456..66b1c3313e2e3ddd0bee660d373334d0329fcb77 100644 (file)
@@ -1675,9 +1675,9 @@ static int ux500_hash_probe(struct platform_device *pdev)
 
        device_data->phybase = res->start;
        device_data->base = devm_ioremap_resource(dev, res);
-       if (!device_data->base) {
+       if (IS_ERR(device_data->base)) {
                dev_err(dev, "%s: ioremap() failed!\n", __func__);
-               ret = -ENOMEM;
+               ret = PTR_ERR(device_data->base);
                goto out;
        }
        spin_lock_init(&device_data->ctx_lock);
index 4f099ea29f83e991349892d91f15c7d0f07d8e38..c66133b5e852ea94a17671dd93ebcdfeaa770931 100644 (file)
@@ -130,26 +130,14 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
 static void dwc_initialize(struct dw_dma_chan *dwc)
 {
        struct dw_dma *dw = to_dw_dma(dwc->chan.device);
-       struct dw_dma_slave *dws = dwc->chan.private;
        u32 cfghi = DWC_CFGH_FIFO_MODE;
        u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
 
        if (dwc->initialized == true)
                return;
 
-       if (dws) {
-               /*
-                * We need controller-specific data to set up slave
-                * transfers.
-                */
-               BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
-
-               cfghi |= DWC_CFGH_DST_PER(dws->dst_id);
-               cfghi |= DWC_CFGH_SRC_PER(dws->src_id);
-       } else {
-               cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
-               cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
-       }
+       cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
+       cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
 
        channel_writel(dwc, CFG_LO, cfglo);
        channel_writel(dwc, CFG_HI, cfghi);
@@ -936,7 +924,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
        struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
        struct dw_dma_slave *dws = param;
 
-       if (!dws || dws->dma_dev != chan->device->dev)
+       if (dws->dma_dev != chan->device->dev)
                return false;
 
        /* We have to copy data since dws can be temporary storage */
@@ -1160,6 +1148,14 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
         * doesn't mean what you think it means), and status writeback.
         */
 
+       /*
+        * We need controller-specific data to set up slave transfers.
+        */
+       if (chan->private && !dw_dma_filter(chan, chan->private)) {
+               dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
+               return -EINVAL;
+       }
+
        /* Enable controller here if needed */
        if (!dw->in_use)
                dw_dma_on(dw);
@@ -1221,6 +1217,14 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        spin_lock_irqsave(&dwc->lock, flags);
        list_splice_init(&dwc->free_list, &list);
        dwc->descs_allocated = 0;
+
+       /* Clear custom channel configuration */
+       dwc->src_id = 0;
+       dwc->dst_id = 0;
+
+       dwc->src_master = 0;
+       dwc->dst_master = 0;
+
        dwc->initialized = false;
 
        /* Disable interrupts */
index 823ad728aecff9b0e2b9810a6aad297bb1bb7d54..efc02b98e6bafe6bc802a530c2e2d508f12dd86d 100644 (file)
@@ -135,7 +135,7 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc)
        sr = hsu_chan_readl(hsuc, HSU_CH_SR);
        spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
 
-       return sr;
+       return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
 }
 
 irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
index f06579c6d548d0b11b83204d0f04494d001db2d3..26da2865b02558b48d19e7faac39481ecd622911 100644 (file)
@@ -41,6 +41,9 @@
 #define HSU_CH_SR_DESCTO(x)    BIT(8 + (x))
 #define HSU_CH_SR_DESCTO_ANY   (BIT(11) | BIT(10) | BIT(9) | BIT(8))
 #define HSU_CH_SR_CHE          BIT(15)
+#define HSU_CH_SR_DESCE(x)     BIT(16 + (x))
+#define HSU_CH_SR_DESCE_ANY    (BIT(19) | BIT(18) | BIT(17) | BIT(16))
+#define HSU_CH_SR_CDESC_ANY    (BIT(31) | BIT(30))
 
 /* Bits in HSU_CH_CR */
 #define HSU_CH_CR_CHA          BIT(0)
index a59061e4221ad1528bcdb919a0b651b025e4d91f..55f5d33f6dc70c5f3a1f2b89d045da4194287fce 100644 (file)
@@ -122,6 +122,7 @@ struct pxad_chan {
 struct pxad_device {
        struct dma_device               slave;
        int                             nr_chans;
+       int                             nr_requestors;
        void __iomem                    *base;
        struct pxad_phy                 *phys;
        spinlock_t                      phy_lock;       /* Phy association */
@@ -473,7 +474,7 @@ static void pxad_free_phy(struct pxad_chan *chan)
                return;
 
        /* clear the channel mapping in DRCMR */
-       if (chan->drcmr <= DRCMR_CHLNUM) {
+       if (chan->drcmr <= pdev->nr_requestors) {
                reg = pxad_drcmr(chan->drcmr);
                writel_relaxed(0, chan->phy->base + reg);
        }
@@ -509,6 +510,7 @@ static bool is_running_chan_misaligned(struct pxad_chan *chan)
 
 static void phy_enable(struct pxad_phy *phy, bool misaligned)
 {
+       struct pxad_device *pdev;
        u32 reg, dalgn;
 
        if (!phy->vchan)
@@ -518,7 +520,8 @@ static void phy_enable(struct pxad_phy *phy, bool misaligned)
                "%s(); phy=%p(%d) misaligned=%d\n", __func__,
                phy, phy->idx, misaligned);
 
-       if (phy->vchan->drcmr <= DRCMR_CHLNUM) {
+       pdev = to_pxad_dev(phy->vchan->vc.chan.device);
+       if (phy->vchan->drcmr <= pdev->nr_requestors) {
                reg = pxad_drcmr(phy->vchan->drcmr);
                writel_relaxed(DRCMR_MAPVLD | phy->idx, phy->base + reg);
        }
@@ -914,6 +917,7 @@ static void pxad_get_config(struct pxad_chan *chan,
 {
        u32 maxburst = 0, dev_addr = 0;
        enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+       struct pxad_device *pdev = to_pxad_dev(chan->vc.chan.device);
 
        *dcmd = 0;
        if (dir == DMA_DEV_TO_MEM) {
@@ -922,7 +926,7 @@ static void pxad_get_config(struct pxad_chan *chan,
                dev_addr = chan->cfg.src_addr;
                *dev_src = dev_addr;
                *dcmd |= PXA_DCMD_INCTRGADDR;
-               if (chan->drcmr <= DRCMR_CHLNUM)
+               if (chan->drcmr <= pdev->nr_requestors)
                        *dcmd |= PXA_DCMD_FLOWSRC;
        }
        if (dir == DMA_MEM_TO_DEV) {
@@ -931,7 +935,7 @@ static void pxad_get_config(struct pxad_chan *chan,
                dev_addr = chan->cfg.dst_addr;
                *dev_dst = dev_addr;
                *dcmd |= PXA_DCMD_INCSRCADDR;
-               if (chan->drcmr <= DRCMR_CHLNUM)
+               if (chan->drcmr <= pdev->nr_requestors)
                        *dcmd |= PXA_DCMD_FLOWTRG;
        }
        if (dir == DMA_MEM_TO_MEM)
@@ -1341,13 +1345,15 @@ static struct dma_chan *pxad_dma_xlate(struct of_phandle_args *dma_spec,
 
 static int pxad_init_dmadev(struct platform_device *op,
                            struct pxad_device *pdev,
-                           unsigned int nr_phy_chans)
+                           unsigned int nr_phy_chans,
+                           unsigned int nr_requestors)
 {
        int ret;
        unsigned int i;
        struct pxad_chan *c;
 
        pdev->nr_chans = nr_phy_chans;
+       pdev->nr_requestors = nr_requestors;
        INIT_LIST_HEAD(&pdev->slave.channels);
        pdev->slave.device_alloc_chan_resources = pxad_alloc_chan_resources;
        pdev->slave.device_free_chan_resources = pxad_free_chan_resources;
@@ -1382,7 +1388,7 @@ static int pxad_probe(struct platform_device *op)
        const struct of_device_id *of_id;
        struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
        struct resource *iores;
-       int ret, dma_channels = 0;
+       int ret, dma_channels = 0, nb_requestors = 0;
        const enum dma_slave_buswidth widths =
                DMA_SLAVE_BUSWIDTH_1_BYTE   | DMA_SLAVE_BUSWIDTH_2_BYTES |
                DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1399,13 +1405,23 @@ static int pxad_probe(struct platform_device *op)
                return PTR_ERR(pdev->base);
 
        of_id = of_match_device(pxad_dt_ids, &op->dev);
-       if (of_id)
+       if (of_id) {
                of_property_read_u32(op->dev.of_node, "#dma-channels",
                                     &dma_channels);
-       else if (pdata && pdata->dma_channels)
+               ret = of_property_read_u32(op->dev.of_node, "#dma-requests",
+                                          &nb_requestors);
+               if (ret) {
+                       dev_warn(pdev->slave.dev,
+                                "#dma-requests set to default 32 as missing in OF: %d",
+                                ret);
+                       nb_requestors = 32;
+               };
+       } else if (pdata && pdata->dma_channels) {
                dma_channels = pdata->dma_channels;
-       else
+               nb_requestors = pdata->nb_requestors;
+       } else {
                dma_channels = 32;      /* default 32 channel */
+       }
 
        dma_cap_set(DMA_SLAVE, pdev->slave.cap_mask);
        dma_cap_set(DMA_MEMCPY, pdev->slave.cap_mask);
@@ -1422,7 +1438,7 @@ static int pxad_probe(struct platform_device *op)
        pdev->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
 
        pdev->slave.dev = &op->dev;
-       ret = pxad_init_dmadev(op, pdev, dma_channels);
+       ret = pxad_init_dmadev(op, pdev, dma_channels, nb_requestors);
        if (ret) {
                dev_err(pdev->slave.dev, "unable to register\n");
                return ret;
@@ -1441,7 +1457,8 @@ static int pxad_probe(struct platform_device *op)
 
        platform_set_drvdata(op, pdev);
        pxad_init_debugfs(pdev);
-       dev_info(pdev->slave.dev, "initialized %d channels\n", dma_channels);
+       dev_info(pdev->slave.dev, "initialized %d channels on %d requestors\n",
+                dma_channels, nb_requestors);
        return 0;
 }
 
index 9eee13ef83a560fd0c54153c61bc01a77cd3eb7f..d87a47547ba59933d719d39cf1fe1460df2eeb55 100644 (file)
@@ -1452,7 +1452,7 @@ static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
        u64 chan_off;
        u64 dram_base           = get_dram_base(pvt, range);
        u64 hole_off            = f10_dhar_offset(pvt);
-       u64 dct_sel_base_off    = (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
+       u64 dct_sel_base_off    = (u64)(pvt->dct_sel_hi & 0xFFFFFC00) << 16;
 
        if (hi_rng) {
                /*
index 01087a38da226d08bd7e08da5a183885fbf420b1..792bdae2b91dfcf28a8a7fca199212d4990aa8af 100644 (file)
@@ -1866,7 +1866,7 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val,
 
        i7_dev = get_i7core_dev(mce->socketid);
        if (!i7_dev)
-               return NOTIFY_BAD;
+               return NOTIFY_DONE;
 
        mci = i7_dev->mci;
        pvt = mci->pvt_info;
index 429309c62699ff9ea536a90b839dbb99b7305ecc..37649221f81cace9767458769aa5b05f8a5fa8a5 100644 (file)
@@ -1117,8 +1117,8 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
                         n_tads, gb, (mb*1000)/1024,
                         ((u64)tmp_mb) << 20L,
-                        (u32)TAD_SOCK(reg),
-                        (u32)TAD_CH(reg),
+                        (u32)(1 << TAD_SOCK(reg)),
+                        (u32)TAD_CH(reg) + 1,
                         (u32)TAD_TGT0(reg),
                         (u32)TAD_TGT1(reg),
                         (u32)TAD_TGT2(reg),
@@ -1396,7 +1396,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        }
 
        ch_way = TAD_CH(reg) + 1;
-       sck_way = TAD_SOCK(reg) + 1;
+       sck_way = TAD_SOCK(reg);
 
        if (ch_way == 3)
                idx = addr >> 6;
@@ -1435,7 +1435,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                switch(ch_way) {
                case 2:
                case 4:
-                       sck_xch = 1 << sck_way * (ch_way >> 1);
+                       sck_xch = (1 << sck_way) * (ch_way >> 1);
                        break;
                default:
                        sprintf(msg, "Invalid mirror set. Can't decode addr");
@@ -1453,7 +1453,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                 n_tads,
                 addr,
                 limit,
-                (u32)TAD_SOCK(reg),
+                sck_way,
                 ch_way,
                 offset,
                 idx,
@@ -1468,18 +1468,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                        offset, addr);
                return -EINVAL;
        }
-       addr -= offset;
-       /* Store the low bits [0:6] of the addr */
-       ch_addr = addr & 0x7f;
-       /* Remove socket wayness and remove 6 bits */
-       addr >>= 6;
-       addr = div_u64(addr, sck_xch);
-#if 0
-       /* Divide by channel way */
-       addr = addr / ch_way;
-#endif
-       /* Recover the last 6 bits */
-       ch_addr |= addr << 6;
+
+       ch_addr = addr - offset;
+       ch_addr >>= (6 + shiftup);
+       ch_addr /= sck_xch;
+       ch_addr <<= (6 + shiftup);
+       ch_addr |= addr & ((1 << (6 + shiftup)) - 1);
 
        /*
         * Step 3) Decode rank
@@ -2260,7 +2254,7 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
 
        mci = get_mci_for_node_id(mce->socketid);
        if (!mci)
-               return NOTIFY_BAD;
+               return NOTIFY_DONE;
        pvt = mci->pvt_info;
 
        /*
index 9f9ea334399c19044908f2ebe241e79166123fa5..b6cb30d207be16f064a093813b70f32f6f344f75 100644 (file)
@@ -803,7 +803,7 @@ static int max77843_muic_probe(struct platform_device *pdev)
        /* Clear IRQ bits before request IRQs */
        ret = regmap_bulk_read(max77843->regmap_muic,
                        MAX77843_MUIC_REG_INT1, info->status,
-                       MAX77843_MUIC_IRQ_NUM);
+                       MAX77843_MUIC_STATUS_NUM);
        if (ret) {
                dev_err(&pdev->dev, "Failed to Clear IRQ bits\n");
                goto err_muic_irq;
index 027ca212179f7f81276733d0bda6b97a636c6770..3b52677f459ae24b2dd2dcd75b0c4fe95beeb64c 100644 (file)
@@ -180,6 +180,7 @@ static int generic_ops_register(void)
 {
        generic_ops.get_variable = efi.get_variable;
        generic_ops.set_variable = efi.set_variable;
+       generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
        generic_ops.get_next_variable = efi.get_next_variable;
        generic_ops.query_variable_store = efi_query_variable_store;
 
index 3c0467d3688cff14df877fea66d61c3fbb3279bd..c4098748e1fe8d5096a7161c2b08e54f80ae1d71 100644 (file)
@@ -8,7 +8,7 @@ cflags-$(CONFIG_X86_32)         := -march=i386
 cflags-$(CONFIG_X86_64)                := -mcmodel=small
 cflags-$(CONFIG_X86)           += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
                                   -fPIC -fno-strict-aliasing -mno-red-zone \
-                                  -mno-mmx -mno-sse -DDISABLE_BRANCH_PROFILING
+                                  -mno-mmx -mno-sse
 
 cflags-$(CONFIG_ARM64)         := $(subst -pg,,$(KBUILD_CFLAGS))
 cflags-$(CONFIG_ARM)           := $(subst -pg,,$(KBUILD_CFLAGS)) \
@@ -16,7 +16,7 @@ cflags-$(CONFIG_ARM)          := $(subst -pg,,$(KBUILD_CFLAGS)) \
 
 cflags-$(CONFIG_EFI_ARMSTUB)   += -I$(srctree)/scripts/dtc/libfdt
 
-KBUILD_CFLAGS                  := $(cflags-y) \
+KBUILD_CFLAGS                  := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
                                   $(call cc-option,-ffreestanding) \
                                   $(call cc-option,-fno-stack-protector)
 
@@ -34,7 +34,8 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
 lib-$(CONFIG_EFI_ARMSTUB)      += arm-stub.o fdt.o string.o \
                                   $(patsubst %.c,lib-%.o,$(arm-deps))
 
-lib-$(CONFIG_ARM64)            += arm64-stub.o
+lib-$(CONFIG_ARM)              += arm32-stub.o
+lib-$(CONFIG_ARM64)            += arm64-stub.o random.o
 CFLAGS_arm64-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
 #
index 950c87f5d279335210088e4154eda135b24304d5..d5aa1d16154f5cb100e865a1bfbb8e0e49fb542c 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "efistub.h"
 
+bool __nokaslr;
+
 static int efi_secureboot_enabled(efi_system_table_t *sys_table_arg)
 {
        static efi_guid_t const var_guid = EFI_GLOBAL_VARIABLE_GUID;
@@ -207,14 +209,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
                pr_efi_err(sys_table, "Failed to find DRAM base\n");
                goto fail;
        }
-       status = handle_kernel_image(sys_table, image_addr, &image_size,
-                                    &reserve_addr,
-                                    &reserve_size,
-                                    dram_base, image);
-       if (status != EFI_SUCCESS) {
-               pr_efi_err(sys_table, "Failed to relocate kernel\n");
-               goto fail;
-       }
 
        /*
         * Get the command line from EFI, using the LOADED_IMAGE
@@ -224,7 +218,28 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
        cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
        if (!cmdline_ptr) {
                pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
-               goto fail_free_image;
+               goto fail;
+       }
+
+       /* check whether 'nokaslr' was passed on the command line */
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+               static const u8 default_cmdline[] = CONFIG_CMDLINE;
+               const u8 *str, *cmdline = cmdline_ptr;
+
+               if (IS_ENABLED(CONFIG_CMDLINE_FORCE))
+                       cmdline = default_cmdline;
+               str = strstr(cmdline, "nokaslr");
+               if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
+                       __nokaslr = true;
+       }
+
+       status = handle_kernel_image(sys_table, image_addr, &image_size,
+                                    &reserve_addr,
+                                    &reserve_size,
+                                    dram_base, image);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err(sys_table, "Failed to relocate kernel\n");
+               goto fail_free_cmdline;
        }
 
        status = efi_parse_options(cmdline_ptr);
@@ -244,7 +259,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 
                if (status != EFI_SUCCESS) {
                        pr_efi_err(sys_table, "Failed to load device tree!\n");
-                       goto fail_free_cmdline;
+                       goto fail_free_image;
                }
        }
 
@@ -286,12 +301,11 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
        efi_free(sys_table, initrd_size, initrd_addr);
        efi_free(sys_table, fdt_size, fdt_addr);
 
-fail_free_cmdline:
-       efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
-
 fail_free_image:
        efi_free(sys_table, image_size, *image_addr);
        efi_free(sys_table, reserve_size, reserve_addr);
+fail_free_cmdline:
+       efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
 fail:
        return EFI_ERROR;
 }
index 78dfbd34b6bffd2fa36312da89dc6ca43f036c3c..e0e6b74fef8f7becdef4c0481919ead298023250 100644 (file)
 #include <asm/efi.h>
 #include <asm/sections.h>
 
+#include "efistub.h"
+
+extern bool __nokaslr;
+
 efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
                                        unsigned long *image_addr,
                                        unsigned long *image_size,
@@ -23,26 +27,52 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
 {
        efi_status_t status;
        unsigned long kernel_size, kernel_memsize = 0;
-       unsigned long nr_pages;
        void *old_image_addr = (void *)*image_addr;
        unsigned long preferred_offset;
+       u64 phys_seed = 0;
+
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+               if (!__nokaslr) {
+                       status = efi_get_random_bytes(sys_table_arg,
+                                                     sizeof(phys_seed),
+                                                     (u8 *)&phys_seed);
+                       if (status == EFI_NOT_FOUND) {
+                               pr_efi(sys_table_arg, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
+                       } else if (status != EFI_SUCCESS) {
+                               pr_efi_err(sys_table_arg, "efi_get_random_bytes() failed\n");
+                               return status;
+                       }
+               } else {
+                       pr_efi(sys_table_arg, "KASLR disabled on kernel command line\n");
+               }
+       }
 
        /*
         * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond
         * a 2 MB aligned base, which itself may be lower than dram_base, as
         * long as the resulting offset equals or exceeds it.
         */
-       preferred_offset = round_down(dram_base, SZ_2M) + TEXT_OFFSET;
+       preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET;
        if (preferred_offset < dram_base)
-               preferred_offset += SZ_2M;
+               preferred_offset += MIN_KIMG_ALIGN;
 
-       /* Relocate the image, if required. */
        kernel_size = _edata - _text;
-       if (*image_addr != preferred_offset) {
-               kernel_memsize = kernel_size + (_end - _edata);
+       kernel_memsize = kernel_size + (_end - _edata);
+
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
+               /*
+                * If KASLR is enabled, and we have some randomness available,
+                * locate the kernel at a randomized offset in physical memory.
+                */
+               *reserve_size = kernel_memsize + TEXT_OFFSET;
+               status = efi_random_alloc(sys_table_arg, *reserve_size,
+                                         MIN_KIMG_ALIGN, reserve_addr,
+                                         phys_seed);
 
+               *image_addr = *reserve_addr + TEXT_OFFSET;
+       } else {
                /*
-                * First, try a straight allocation at the preferred offset.
+                * Else, try a straight allocation at the preferred offset.
                 * This will work around the issue where, if dram_base == 0x0,
                 * efi_low_alloc() refuses to allocate at 0x0 (to prevent the
                 * address of the allocation to be mistaken for a FAIL return
@@ -52,27 +82,31 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
                 * Mustang), we can still place the kernel at the address
                 * 'dram_base + TEXT_OFFSET'.
                 */
+               if (*image_addr == preferred_offset)
+                       return EFI_SUCCESS;
+
                *image_addr = *reserve_addr = preferred_offset;
-               nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) /
-                          EFI_PAGE_SIZE;
+               *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN);
+
                status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                       EFI_LOADER_DATA, nr_pages,
+                                       EFI_LOADER_DATA,
+                                       *reserve_size / EFI_PAGE_SIZE,
                                        (efi_physical_addr_t *)reserve_addr);
-               if (status != EFI_SUCCESS) {
-                       kernel_memsize += TEXT_OFFSET;
-                       status = efi_low_alloc(sys_table_arg, kernel_memsize,
-                                              SZ_2M, reserve_addr);
+       }
 
-                       if (status != EFI_SUCCESS) {
-                               pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
-                               return status;
-                       }
-                       *image_addr = *reserve_addr + TEXT_OFFSET;
+       if (status != EFI_SUCCESS) {
+               *reserve_size = kernel_memsize + TEXT_OFFSET;
+               status = efi_low_alloc(sys_table_arg, *reserve_size,
+                                      MIN_KIMG_ALIGN, reserve_addr);
+
+               if (status != EFI_SUCCESS) {
+                       pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
+                       *reserve_size = 0;
+                       return status;
                }
-               memcpy((void *)*image_addr, old_image_addr, kernel_size);
-               *reserve_size = kernel_memsize;
+               *image_addr = *reserve_addr + TEXT_OFFSET;
        }
-
+       memcpy((void *)*image_addr, old_image_addr, kernel_size);
 
        return EFI_SUCCESS;
 }
index f07d4a67fa76b3a3cb542e31a24a093c6f7aff97..29ed2f9b218ca9892bfcc72da2d91ba4750f4c97 100644 (file)
@@ -649,6 +649,10 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
        return dst;
 }
 
+#ifndef MAX_CMDLINE_ADDRESS
+#define MAX_CMDLINE_ADDRESS    ULONG_MAX
+#endif
+
 /*
  * Convert the unicode UEFI command line to ASCII to pass to kernel.
  * Size of memory allocated return in *cmd_line_len.
@@ -684,7 +688,8 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
 
        options_bytes++;        /* NUL termination */
 
-       status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
+       status = efi_high_alloc(sys_table_arg, options_bytes, 0,
+                               &cmdline_addr, MAX_CMDLINE_ADDRESS);
        if (status != EFI_SUCCESS)
                return NULL;
 
index 6b6548fda0895ecb0ca7e9a60699d7100e335566..5ed3d3f3816637cd10d007f381797320f0567305 100644 (file)
@@ -43,4 +43,11 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                     unsigned long desc_size, efi_memory_desc_t *runtime_map,
                     int *count);
 
+efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table,
+                                 unsigned long size, u8 *out);
+
+efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,
+                             unsigned long size, unsigned long align,
+                             unsigned long *addr, unsigned long random_seed);
+
 #endif
index b62e2f5dcab3b2d95074b534de803915145dc20c..b1c22cf18f7d39f531bca06d99ac44ff1d6a9e32 100644 (file)
@@ -147,6 +147,20 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
        if (status)
                goto fdt_set_fail;
 
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+               efi_status_t efi_status;
+
+               efi_status = efi_get_random_bytes(sys_table, sizeof(fdt_val64),
+                                                 (u8 *)&fdt_val64);
+               if (efi_status == EFI_SUCCESS) {
+                       status = fdt_setprop(fdt, node, "kaslr-seed",
+                                            &fdt_val64, sizeof(fdt_val64));
+                       if (status)
+                               goto fdt_set_fail;
+               } else if (efi_status != EFI_NOT_FOUND) {
+                       return efi_status;
+               }
+       }
        return EFI_SUCCESS;
 
 fdt_set_fail:
diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c
new file mode 100644 (file)
index 0000000..53f6d3f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+struct efi_rng_protocol {
+       efi_status_t (*get_info)(struct efi_rng_protocol *,
+                                unsigned long *, efi_guid_t *);
+       efi_status_t (*get_rng)(struct efi_rng_protocol *,
+                               efi_guid_t *, unsigned long, u8 *out);
+};
+
+efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg,
+                                 unsigned long size, u8 *out)
+{
+       efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
+       efi_status_t status;
+       struct efi_rng_protocol *rng;
+
+       status = efi_call_early(locate_protocol, &rng_proto, NULL,
+                               (void **)&rng);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       return rng->get_rng(rng, NULL, size, out);
+}
+
+/*
+ * Return the number of slots covered by this entry, i.e., the number of
+ * addresses it covers that are suitably aligned and supply enough room
+ * for the allocation.
+ */
+static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
+                                        unsigned long size,
+                                        unsigned long align)
+{
+       u64 start, end;
+
+       if (md->type != EFI_CONVENTIONAL_MEMORY)
+               return 0;
+
+       start = round_up(md->phys_addr, align);
+       end = round_down(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - size,
+                        align);
+
+       if (start > end)
+               return 0;
+
+       return (end - start + 1) / align;
+}
+
+/*
+ * The UEFI memory descriptors have a virtual address field that is only used
+ * when installing the virtual mapping using SetVirtualAddressMap(). Since it
+ * is unused here, we can reuse it to keep track of each descriptor's slot
+ * count.
+ */
+#define MD_NUM_SLOTS(md)       ((md)->virt_addr)
+
+efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,
+                             unsigned long size,
+                             unsigned long align,
+                             unsigned long *addr,
+                             unsigned long random_seed)
+{
+       unsigned long map_size, desc_size, total_slots = 0, target_slot;
+       efi_status_t status;
+       efi_memory_desc_t *memory_map;
+       int map_offset;
+
+       status = efi_get_memory_map(sys_table_arg, &memory_map, &map_size,
+                                   &desc_size, NULL, NULL);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       if (align < EFI_ALLOC_ALIGN)
+               align = EFI_ALLOC_ALIGN;
+
+       /* count the suitable slots in each memory map entry */
+       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+               efi_memory_desc_t *md = (void *)memory_map + map_offset;
+               unsigned long slots;
+
+               slots = get_entry_num_slots(md, size, align);
+               MD_NUM_SLOTS(md) = slots;
+               total_slots += slots;
+       }
+
+       /* find a random number between 0 and total_slots */
+       target_slot = (total_slots * (u16)random_seed) >> 16;
+
+       /*
+        * target_slot is now a value in the range [0, total_slots), and so
+        * it corresponds with exactly one of the suitable slots we recorded
+        * when iterating over the memory map the first time around.
+        *
+        * So iterate over the memory map again, subtracting the number of
+        * slots of each entry at each iteration, until we have found the entry
+        * that covers our chosen slot. Use the residual value of target_slot
+        * to calculate the randomly chosen address, and allocate it directly
+        * using EFI_ALLOCATE_ADDRESS.
+        */
+       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+               efi_memory_desc_t *md = (void *)memory_map + map_offset;
+               efi_physical_addr_t target;
+               unsigned long pages;
+
+               if (target_slot >= MD_NUM_SLOTS(md)) {
+                       target_slot -= MD_NUM_SLOTS(md);
+                       continue;
+               }
+
+               target = round_up(md->phys_addr, align) + target_slot * align;
+               pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+
+               status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                                       EFI_LOADER_DATA, pages, &target);
+               if (status == EFI_SUCCESS)
+                       *addr = target;
+               break;
+       }
+
+       efi_call_early(free_pool, memory_map);
+
+       return status;
+}
index 7f2ea21c730dd76a86f3ab5a1e253878878960a7..6f182fd91a6d0dbf713f7b56c4449dda8b795b77 100644 (file)
@@ -202,29 +202,44 @@ static const struct variable_validate variable_validate[] = {
        { NULL_GUID, "", NULL },
 };
 
+/*
+ * Check if @var_name matches the pattern given in @match_name.
+ *
+ * @var_name: an array of @len non-NUL characters.
+ * @match_name: a NUL-terminated pattern string, optionally ending in "*". A
+ *              final "*" character matches any trailing characters @var_name,
+ *              including the case when there are none left in @var_name.
+ * @match: on output, the number of non-wildcard characters in @match_name
+ *         that @var_name matches, regardless of the return value.
+ * @return: whether @var_name fully matches @match_name.
+ */
 static bool
 variable_matches(const char *var_name, size_t len, const char *match_name,
                 int *match)
 {
        for (*match = 0; ; (*match)++) {
                char c = match_name[*match];
-               char u = var_name[*match];
 
-               /* Wildcard in the matching name means we've matched */
-               if (c == '*')
+               switch (c) {
+               case '*':
+                       /* Wildcard in @match_name means we've matched. */
                        return true;
 
-               /* Case sensitive match */
-               if (!c && *match == len)
-                       return true;
+               case '\0':
+                       /* @match_name has ended. Has @var_name too? */
+                       return (*match == len);
 
-               if (c != u)
+               default:
+                       /*
+                        * We've reached a non-wildcard char in @match_name.
+                        * Continue only if there's an identical character in
+                        * @var_name.
+                        */
+                       if (*match < len && c == var_name[*match])
+                               continue;
                        return false;
-
-               if (!c)
-                       return true;
+               }
        }
-       return true;
 }
 
 bool
index bb1099c549dfbe643428b99c0ac33489028a9558..053fc2f465dfe663df9c75205e9806fa51c6d497 100644 (file)
@@ -1673,6 +1673,7 @@ struct amdgpu_uvd {
        struct amdgpu_bo        *vcpu_bo;
        void                    *cpu_addr;
        uint64_t                gpu_addr;
+       unsigned                fw_version;
        atomic_t                handles[AMDGPU_MAX_UVD_HANDLES];
        struct drm_file         *filp[AMDGPU_MAX_UVD_HANDLES];
        struct delayed_work     idle_work;
index e23843f4d877be7813a1574db0f855847f9aa591..4488e82f87b01475a43a789280c6f809452530df 100644 (file)
@@ -303,7 +303,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        fw_info.feature = adev->vce.fb_version;
                        break;
                case AMDGPU_INFO_FW_UVD:
-                       fw_info.ver = 0;
+                       fw_info.ver = adev->uvd.fw_version;
                        fw_info.feature = 0;
                        break;
                case AMDGPU_INFO_FW_GMC:
index 064ebb3470748619e0b43ff7bfe2671a58c50bbd..89df7871653d1773cc8739eb2b700671a4e6d110 100644 (file)
@@ -52,7 +52,7 @@ struct amdgpu_hpd;
 
 #define AMDGPU_MAX_HPD_PINS 6
 #define AMDGPU_MAX_CRTCS 6
-#define AMDGPU_MAX_AFMT_BLOCKS 7
+#define AMDGPU_MAX_AFMT_BLOCKS 9
 
 enum amdgpu_rmx_type {
        RMX_OFF,
@@ -308,8 +308,8 @@ struct amdgpu_mode_info {
        struct atom_context *atom_context;
        struct card_info *atom_card_info;
        bool mode_config_initialized;
-       struct amdgpu_crtc *crtcs[6];
-       struct amdgpu_afmt *afmt[7];
+       struct amdgpu_crtc *crtcs[AMDGPU_MAX_CRTCS];
+       struct amdgpu_afmt *afmt[AMDGPU_MAX_AFMT_BLOCKS];
        /* DVI-I properties */
        struct drm_property *coherent_mode_property;
        /* DAC enable load detect */
index b8fbbd7699e4586e13e57905b0cef818f6e43e6b..73628c7599e748a3bb2ebe72d25133927e97f315 100644 (file)
@@ -540,6 +540,7 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
        if (!metadata_size) {
                if (bo->metadata_size) {
                        kfree(bo->metadata);
+                       bo->metadata = NULL;
                        bo->metadata_size = 0;
                }
                return 0;
index 53f987aeeacff5a4b48663850c7a413d64a9ba76..3b35ad83867ccd15af7e1a15eb57576db4e03577 100644 (file)
@@ -156,6 +156,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
        DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n",
                version_major, version_minor, family_id);
 
+       adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) |
+                               (family_id << 8));
+
        bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)
                 +  AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE;
        r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true,
@@ -273,6 +276,8 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)
        memcpy(adev->uvd.cpu_addr, (adev->uvd.fw->data) + offset,
                (adev->uvd.fw->size) - offset);
 
+       cancel_delayed_work_sync(&adev->uvd.idle_work);
+
        size = amdgpu_bo_size(adev->uvd.vcpu_bo);
        size -= le32_to_cpu(hdr->ucode_size_bytes);
        ptr = adev->uvd.cpu_addr;
index a745eeeb5d8200f6b92e259c655b10b658c4cad5..bb0da76051a18f2bd9941617d0f0635ccdce990e 100644 (file)
@@ -220,6 +220,7 @@ int amdgpu_vce_suspend(struct amdgpu_device *adev)
        if (i == AMDGPU_MAX_VCE_HANDLES)
                return 0;
 
+       cancel_delayed_work_sync(&adev->vce.idle_work);
        /* TODO: suspending running encoding sessions isn't supported */
        return -EINVAL;
 }
index 1e0bba29e16796f97c8eee38fc9d3100c405f6bc..1cd6de575305aa3f657fa1a7f5a70232b272d739 100644 (file)
@@ -298,6 +298,10 @@ bool amdgpu_atombios_encoder_mode_fixup(struct drm_encoder *encoder,
            && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
                adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
 
+       /* vertical FP must be at least 1 */
+       if (mode->crtc_vsync_start == mode->crtc_vdisplay)
+               adjusted_mode->crtc_vsync_start++;
+
        /* get the native mode for scaling */
        if (amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT))
                amdgpu_panel_mode_fixup(encoder, adjusted_mode);
index aa491540ba85bebbcf70c1d4d1be4b088026b9c9..94630076460912123f946339c1cafe843df49413 100644 (file)
@@ -3628,7 +3628,7 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
                                        unsigned vm_id, uint64_t pd_addr)
 {
        int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
-       uint32_t seq = ring->fence_drv.sync_seq;
+       uint32_t seq = ring->fence_drv.sync_seq[ring->idx];
        uint64_t addr = ring->fence_drv.gpu_addr;
 
        amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
index 272110cc18c2f2f83a6d6b1c1aa3ba8bec9d0df2..ea87033bfaf6eb1a8da77a73c3ac9b1766afcade 100644 (file)
@@ -898,14 +898,6 @@ static int gmc_v7_0_early_init(void *handle)
        gmc_v7_0_set_gart_funcs(adev);
        gmc_v7_0_set_irq_funcs(adev);
 
-       if (adev->flags & AMD_IS_APU) {
-               adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
-       } else {
-               u32 tmp = RREG32(mmMC_SEQ_MISC0);
-               tmp &= MC_SEQ_MISC0__MT__MASK;
-               adev->mc.vram_type = gmc_v7_0_convert_vram_type(tmp);
-       }
-
        return 0;
 }
 
@@ -926,6 +918,14 @@ static int gmc_v7_0_sw_init(void *handle)
        if (r)
                return r;
 
+       if (adev->flags & AMD_IS_APU) {
+               adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
+       } else {
+               u32 tmp = RREG32(mmMC_SEQ_MISC0);
+               tmp &= MC_SEQ_MISC0__MT__MASK;
+               adev->mc.vram_type = gmc_v7_0_convert_vram_type(tmp);
+       }
+
        r = amdgpu_irq_add_id(adev, 146, &adev->mc.vm_fault);
        if (r)
                return r;
index ba4ad00ba8b4cc38f146de95396d43b52d3609c7..08423089fb84ba7462fc59e979447f46f9a9440e 100644 (file)
@@ -852,14 +852,6 @@ static int gmc_v8_0_early_init(void *handle)
        gmc_v8_0_set_gart_funcs(adev);
        gmc_v8_0_set_irq_funcs(adev);
 
-       if (adev->flags & AMD_IS_APU) {
-               adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
-       } else {
-               u32 tmp = RREG32(mmMC_SEQ_MISC0);
-               tmp &= MC_SEQ_MISC0__MT__MASK;
-               adev->mc.vram_type = gmc_v8_0_convert_vram_type(tmp);
-       }
-
        return 0;
 }
 
@@ -870,6 +862,8 @@ static int gmc_v8_0_late_init(void *handle)
        return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
 }
 
+#define mmMC_SEQ_MISC0_FIJI 0xA71
+
 static int gmc_v8_0_sw_init(void *handle)
 {
        int r;
@@ -880,6 +874,19 @@ static int gmc_v8_0_sw_init(void *handle)
        if (r)
                return r;
 
+       if (adev->flags & AMD_IS_APU) {
+               adev->mc.vram_type = AMDGPU_VRAM_TYPE_UNKNOWN;
+       } else {
+               u32 tmp;
+
+               if (adev->asic_type == CHIP_FIJI)
+                       tmp = RREG32(mmMC_SEQ_MISC0_FIJI);
+               else
+                       tmp = RREG32(mmMC_SEQ_MISC0);
+               tmp &= MC_SEQ_MISC0__MT__MASK;
+               adev->mc.vram_type = gmc_v8_0_convert_vram_type(tmp);
+       }
+
        r = amdgpu_irq_add_id(adev, 146, &adev->mc.vm_fault);
        if (r)
                return r;
index 2cf50180cc51bd496289feb892a2a56b6d81abe0..b1c7a9b3631bd3141e273bd7b6bacddb28970620 100644 (file)
@@ -32,8 +32,8 @@
 #include "oss/oss_2_4_d.h"
 #include "oss/oss_2_4_sh_mask.h"
 
-#include "gmc/gmc_8_1_d.h"
-#include "gmc/gmc_8_1_sh_mask.h"
+#include "gmc/gmc_7_1_d.h"
+#include "gmc/gmc_7_1_sh_mask.h"
 
 #include "gca/gfx_8_0_d.h"
 #include "gca/gfx_8_0_enum.h"
index c34c393e9aea0c2dfe3442c28a72f2206fbcd7fb..d5e19b5fbbfb00d1fbbcd1066da0ac4f12424ec3 100644 (file)
@@ -513,7 +513,7 @@ static int dbgdev_wave_control_set_registers(
                                union SQ_CMD_BITS *in_reg_sq_cmd,
                                union GRBM_GFX_INDEX_BITS *in_reg_gfx_index)
 {
-       int status;
+       int status = 0;
        union SQ_CMD_BITS reg_sq_cmd;
        union GRBM_GFX_INDEX_BITS reg_gfx_index;
        struct HsaDbgWaveMsgAMDGen2 *pMsg;
index 9535c5b60387281a8a95929c09201dd086fff9cc..7e5a97204051b0f9e283132ec2086f1ee10fee54 100644 (file)
@@ -178,7 +178,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 {
        struct drm_dp_aux_msg msg;
        unsigned int retry;
-       int err;
+       int err = 0;
 
        memset(&msg, 0, sizeof(msg));
        msg.address = offset;
@@ -186,6 +186,8 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
        msg.buffer = buffer;
        msg.size = size;
 
+       mutex_lock(&aux->hw_mutex);
+
        /*
         * The specification doesn't give any recommendation on how often to
         * retry native transactions. We used to retry 7 times like for
@@ -194,25 +196,24 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
         */
        for (retry = 0; retry < 32; retry++) {
 
-               mutex_lock(&aux->hw_mutex);
                err = aux->transfer(aux, &msg);
-               mutex_unlock(&aux->hw_mutex);
                if (err < 0) {
                        if (err == -EBUSY)
                                continue;
 
-                       return err;
+                       goto unlock;
                }
 
 
                switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) {
                case DP_AUX_NATIVE_REPLY_ACK:
                        if (err < size)
-                               return -EPROTO;
-                       return err;
+                               err = -EPROTO;
+                       goto unlock;
 
                case DP_AUX_NATIVE_REPLY_NACK:
-                       return -EIO;
+                       err = -EIO;
+                       goto unlock;
 
                case DP_AUX_NATIVE_REPLY_DEFER:
                        usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100);
@@ -221,7 +222,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
        }
 
        DRM_DEBUG_KMS("too many retries, giving up\n");
-       return -EIO;
+       err = -EIO;
+
+unlock:
+       mutex_unlock(&aux->hw_mutex);
+       return err;
 }
 
 /**
@@ -543,9 +548,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
        int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz));
 
        for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) {
-               mutex_lock(&aux->hw_mutex);
                ret = aux->transfer(aux, msg);
-               mutex_unlock(&aux->hw_mutex);
                if (ret < 0) {
                        if (ret == -EBUSY)
                                continue;
@@ -684,6 +687,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 
        memset(&msg, 0, sizeof(msg));
 
+       mutex_lock(&aux->hw_mutex);
+
        for (i = 0; i < num; i++) {
                msg.address = msgs[i].addr;
                drm_dp_i2c_msg_set_request(&msg, &msgs[i]);
@@ -738,6 +743,8 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
        msg.size = 0;
        (void)drm_dp_i2c_do_msg(aux, &msg);
 
+       mutex_unlock(&aux->hw_mutex);
+
        return err;
 }
 
index 39d7e2e15c11e4603d8c889cc48bc507729b495d..d268bf18a662c960335445c5d4bd2da7c5bc885f 100644 (file)
@@ -1665,13 +1665,19 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
        struct drm_dp_mst_branch *mstb;
        int len, ret, port_num;
 
+       port = drm_dp_get_validated_port_ref(mgr, port);
+       if (!port)
+               return -EINVAL;
+
        port_num = port->port_num;
        mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
        if (!mstb) {
                mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num);
 
-               if (!mstb)
+               if (!mstb) {
+                       drm_dp_put_port(port);
                        return -EINVAL;
+               }
        }
 
        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
@@ -1697,6 +1703,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
        kfree(txmsg);
 fail_put:
        drm_dp_put_mst_branch_device(mstb);
+       drm_dp_put_port(port);
        return ret;
 }
 
@@ -1779,6 +1786,11 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
                req_payload.start_slot = cur_slots;
                if (mgr->proposed_vcpis[i]) {
                        port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi);
+                       port = drm_dp_get_validated_port_ref(mgr, port);
+                       if (!port) {
+                               mutex_unlock(&mgr->payload_lock);
+                               return -EINVAL;
+                       }
                        req_payload.num_slots = mgr->proposed_vcpis[i]->num_slots;
                } else {
                        port = NULL;
@@ -1804,6 +1816,9 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
                        mgr->payloads[i].payload_state = req_payload.payload_state;
                }
                cur_slots += req_payload.num_slots;
+
+               if (port)
+                       drm_dp_put_port(port);
        }
 
        for (i = 0; i < mgr->max_payloads; i++) {
@@ -2109,6 +2124,8 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr)
 
        if (mgr->mst_primary) {
                int sret;
+               u8 guid[16];
+
                sret = drm_dp_dpcd_read(mgr->aux, DP_DPCD_REV, mgr->dpcd, DP_RECEIVER_CAP_SIZE);
                if (sret != DP_RECEIVER_CAP_SIZE) {
                        DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n");
@@ -2123,6 +2140,16 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr)
                        ret = -1;
                        goto out_unlock;
                }
+
+               /* Some hubs forget their guids after they resume */
+               sret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
+               if (sret != 16) {
+                       DRM_DEBUG_KMS("dpcd read failed - undocked during suspend?\n");
+                       ret = -1;
+                       goto out_unlock;
+               }
+               drm_dp_check_mstb_guid(mgr->mst_primary, guid);
+
                ret = 0;
        } else
                ret = -1;
index bc7b8faba84d8359afe9b13cc245c87f5d9c9ea6..7e461dca564c80effaeb46a99f533b3fd5d6cf9a 100644 (file)
@@ -2838,7 +2838,14 @@ enum skl_disp_power_wells {
 #define GEN6_RP_STATE_CAP      (MCHBAR_MIRROR_BASE_SNB + 0x5998)
 #define BXT_RP_STATE_CAP        0x138170
 
-#define INTERVAL_1_28_US(us)   (((us) * 100) >> 7)
+/*
+ * Make these a multiple of magic 25 to avoid SNB (eg. Dell XPS
+ * 8300) freezing up around GPU hangs. Looks as if even
+ * scheduling/timer interrupts start misbehaving if the RPS
+ * EI/thresholds are "bad", leading to a very sluggish or even
+ * frozen machine.
+ */
+#define INTERVAL_1_28_US(us)   roundup(((us) * 100) >> 7, 25)
 #define INTERVAL_1_33_US(us)   (((us) * 3)   >> 2)
 #define INTERVAL_0_833_US(us)  (((us) * 6) / 5)
 #define GT_INTERVAL_FROM_US(dev_priv, us) (IS_GEN9(dev_priv) ? \
index 9e530a73935460ddc35d357721f667f28d0d4e09..fc28c512ece3cddee666c23ec77acf57ba224f85 100644 (file)
@@ -180,7 +180,8 @@ struct stepping_info {
 static const struct stepping_info skl_stepping_info[] = {
                {'A', '0'}, {'B', '0'}, {'C', '0'},
                {'D', '0'}, {'E', '0'}, {'F', '0'},
-               {'G', '0'}, {'H', '0'}, {'I', '0'}
+               {'G', '0'}, {'H', '0'}, {'I', '0'},
+               {'J', '0'}, {'K', '0'}
 };
 
 static struct stepping_info bxt_stepping_info[] = {
index c5d518dc055db584fcef95926818312d90090af3..63be0cd16c00e1d9b668ecd40804905ad128a770 100644 (file)
@@ -464,9 +464,17 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
        } else if (IS_BROADWELL(dev)) {
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
-               ddi_translations_edp = bdw_ddi_translations_edp;
+
+               if (dev_priv->edp_low_vswing) {
+                       ddi_translations_edp = bdw_ddi_translations_edp;
+                       n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+               } else {
+                       ddi_translations_edp = bdw_ddi_translations_dp;
+                       n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
+               }
+
                ddi_translations_hdmi = bdw_ddi_translations_hdmi;
-               n_edp_entries = ARRAY_SIZE(bdw_ddi_translations_edp);
+
                n_dp_entries = ARRAY_SIZE(bdw_ddi_translations_dp);
                n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
                hdmi_default_entry = 7;
@@ -3188,12 +3196,6 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
        intel_ddi_clock_get(encoder, pipe_config);
 }
 
-static void intel_ddi_destroy(struct drm_encoder *encoder)
-{
-       /* HDMI has nothing special to destroy, so we can go with this. */
-       intel_dp_encoder_destroy(encoder);
-}
-
 static bool intel_ddi_compute_config(struct intel_encoder *encoder,
                                     struct intel_crtc_state *pipe_config)
 {
@@ -3212,7 +3214,8 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder,
 }
 
 static const struct drm_encoder_funcs intel_ddi_funcs = {
-       .destroy = intel_ddi_destroy,
+       .reset = intel_dp_encoder_reset,
+       .destroy = intel_dp_encoder_destroy,
 };
 
 static struct intel_connector *
@@ -3284,6 +3287,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_encoder->post_disable = intel_ddi_post_disable;
        intel_encoder->get_hw_state = intel_ddi_get_hw_state;
        intel_encoder->get_config = intel_ddi_get_config;
+       intel_encoder->suspend = intel_dp_encoder_suspend;
 
        intel_dig_port->port = port;
        intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
index ad79840e79a66d9ea738dbeb6c59a7b6f3f131e2..f408eac04856338c578925af2e7f660edf60c34e 100644 (file)
@@ -4447,7 +4447,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
                      intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX);
 
        return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
-               &state->scaler_state.scaler_id, DRM_ROTATE_0,
+               &state->scaler_state.scaler_id, BIT(DRM_ROTATE_0),
                state->pipe_src_w, state->pipe_src_h,
                adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
 }
index a35aca2ddc590f1054857a18c28da1fabd296f8f..883da2d3be0c887644231c75f558accc11203872 100644 (file)
@@ -5035,7 +5035,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
        kfree(intel_dig_port);
 }
 
-static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
+void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
 
@@ -5077,7 +5077,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
        edp_panel_vdd_schedule_off(intel_dp);
 }
 
-static void intel_dp_encoder_reset(struct drm_encoder *encoder)
+void intel_dp_encoder_reset(struct drm_encoder *encoder)
 {
        struct intel_dp *intel_dp;
 
index 6c11aa38644212de0027ea7677575a4e0e7f52ba..776c3f4ae43ea6343d987594da43f94c7851e052 100644 (file)
@@ -477,6 +477,8 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_device *dev = connector->dev;
 
+       intel_connector->unregister(intel_connector);
+
        /* need to nuke the connector */
        drm_modeset_lock_all(dev);
        if (connector->state->crtc) {
@@ -490,11 +492,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
 
                WARN(ret, "Disabling mst crtc failed with %i\n", ret);
        }
-       drm_modeset_unlock_all(dev);
 
-       intel_connector->unregister(intel_connector);
-
-       drm_modeset_lock_all(dev);
        intel_connector_remove_from_fbdev(intel_connector);
        drm_connector_cleanup(connector);
        drm_modeset_unlock_all(dev);
index 0d00f07b7163c90c10d8e994b037b7b24b508d34..f34a219ec5c405dde2c1d13cb5441e2e31473b30 100644 (file)
@@ -1204,6 +1204,8 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
+void intel_dp_encoder_reset(struct drm_encoder *encoder);
+void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
 void intel_dp_encoder_destroy(struct drm_encoder *encoder);
 int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 bool intel_dp_compute_config(struct intel_encoder *encoder,
index a92f31f1f05959f916b79f0211a75f2467f194be..5763037586ee099f132577b8a4baea80af4b1351 100644 (file)
@@ -1388,8 +1388,16 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
                                hdmi_to_dig_port(intel_hdmi));
        }
 
-       if (!live_status)
-               DRM_DEBUG_KMS("Live status not up!");
+       if (!live_status) {
+               DRM_DEBUG_KMS("HDMI live status down\n");
+               /*
+                * Live status register is not reliable on all intel platforms.
+                * So consider live_status only for certain platforms, for
+                * others, read EDID to determine presence of sink.
+                */
+               if (INTEL_INFO(dev_priv)->gen < 7 || IS_IVYBRIDGE(dev_priv))
+                       live_status = true;
+       }
 
        intel_hdmi_unset_edid(connector);
 
index d69547a65dbb95599c400e864b95c779863ef995..7058f75c7b4291c26522491110679327326d0258 100644 (file)
@@ -776,11 +776,11 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes)
                if (unlikely(total_bytes > remain_usable)) {
                        /*
                         * The base request will fit but the reserved space
-                        * falls off the end. So only need to to wait for the
-                        * reserved size after flushing out the remainder.
+                        * falls off the end. So don't need an immediate wrap
+                        * and only need to effectively wait for the reserved
+                        * size space from the start of ringbuffer.
                         */
                        wait_bytes = remain_actual + ringbuf->reserved_size;
-                       need_wrap = true;
                } else if (total_bytes > ringbuf->space) {
                        /* No wrapping required, just waiting. */
                        wait_bytes = total_bytes;
index f6b2a814e629117a14067b0cbe58dddffcff4b91..9d48443bca2e7542f8ce51f5b2ca1f4dbc4244a3 100644 (file)
@@ -1922,6 +1922,17 @@ i915_dispatch_execbuffer(struct drm_i915_gem_request *req,
        return 0;
 }
 
+static void cleanup_phys_status_page(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = to_i915(ring->dev);
+
+       if (!dev_priv->status_page_dmah)
+               return;
+
+       drm_pci_free(ring->dev, dev_priv->status_page_dmah);
+       ring->status_page.page_addr = NULL;
+}
+
 static void cleanup_status_page(struct intel_engine_cs *ring)
 {
        struct drm_i915_gem_object *obj;
@@ -1938,9 +1949,9 @@ static void cleanup_status_page(struct intel_engine_cs *ring)
 
 static int init_status_page(struct intel_engine_cs *ring)
 {
-       struct drm_i915_gem_object *obj;
+       struct drm_i915_gem_object *obj = ring->status_page.obj;
 
-       if ((obj = ring->status_page.obj) == NULL) {
+       if (obj == NULL) {
                unsigned flags;
                int ret;
 
@@ -2134,7 +2145,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
                if (ret)
                        goto error;
        } else {
-               BUG_ON(ring->id != RCS);
+               WARN_ON(ring->id != RCS);
                ret = init_phys_status_page(ring);
                if (ret)
                        goto error;
@@ -2179,7 +2190,12 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
        if (ring->cleanup)
                ring->cleanup(ring);
 
-       cleanup_status_page(ring);
+       if (I915_NEED_GFX_HWS(ring->dev)) {
+               cleanup_status_page(ring);
+       } else {
+               WARN_ON(ring->id != RCS);
+               cleanup_phys_status_page(ring);
+       }
 
        i915_cmd_parser_fini_ring(ring);
        i915_gem_batch_pool_fini(&ring->batch_pool);
@@ -2341,11 +2357,11 @@ static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes)
                if (unlikely(total_bytes > remain_usable)) {
                        /*
                         * The base request will fit but the reserved space
-                        * falls off the end. So only need to to wait for the
-                        * reserved size after flushing out the remainder.
+                        * falls off the end. So don't need an immediate wrap
+                        * and only need to effectively wait for the reserved
+                        * size space from the start of ringbuffer.
                         */
                        wait_bytes = remain_actual + ringbuf->reserved_size;
-                       need_wrap = true;
                } else if (total_bytes > ringbuf->space) {
                        /* No wrapping required, just waiting. */
                        wait_bytes = total_bytes;
index 43cba129a0c000efd32bbf84ea59992d1d913905..cc91ae832ffb4fa734786dd2144513f31de491d4 100644 (file)
@@ -1132,7 +1132,11 @@ static void intel_uncore_fw_domains_init(struct drm_device *dev)
        } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                dev_priv->uncore.funcs.force_wake_get =
                        fw_domains_get_with_thread_status;
-               dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+               if (IS_HASWELL(dev))
+                       dev_priv->uncore.funcs.force_wake_put =
+                               fw_domains_put_with_fifo;
+               else
+                       dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
                fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
                               FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
        } else if (IS_IVYBRIDGE(dev)) {
index 3216e157a8a0d17c62e6c7f75e5df8b9b0d99b9d..89da47234016b8bb4c6a0906e2f32cfee9a1b04f 100644 (file)
@@ -131,7 +131,7 @@ nvkm_ramht_del(struct nvkm_ramht **pramht)
        struct nvkm_ramht *ramht = *pramht;
        if (ramht) {
                nvkm_gpuobj_del(&ramht->gpuobj);
-               kfree(*pramht);
+               vfree(*pramht);
                *pramht = NULL;
        }
 }
@@ -143,8 +143,8 @@ nvkm_ramht_new(struct nvkm_device *device, u32 size, u32 align,
        struct nvkm_ramht *ramht;
        int ret, i;
 
-       if (!(ramht = *pramht = kzalloc(sizeof(*ramht) + (size >> 3) *
-                                       sizeof(*ramht->data), GFP_KERNEL)))
+       if (!(ramht = *pramht = vzalloc(sizeof(*ramht) +
+                                       (size >> 3) * sizeof(*ramht->data))))
                return -ENOMEM;
 
        ramht->device = device;
index 9f5dfc85147a50df62f30fdb84453c18a622380e..36655a74c538a133f62fb7f879a1a72ae3775fc0 100644 (file)
@@ -1717,6 +1717,8 @@ gf100_gr_init(struct gf100_gr *gr)
 
        gf100_gr_mmio(gr, gr->func->mmio);
 
+       nvkm_mask(device, TPC_UNIT(0, 0, 0x05c), 0x00000001, 0x00000001);
+
        memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr));
        for (i = 0, gpc = -1; i < gr->tpc_total; i++) {
                do {
index 3c612d4f4e3a06ba9ec3b478e060b5705843593a..f92c46ec9a963c89597a5c21ef3da7385f859c2e 100644 (file)
@@ -375,10 +375,15 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
 
        qxl_bo_kunmap(user_bo);
 
+       qcrtc->cur_x += qcrtc->hot_spot_x - hot_x;
+       qcrtc->cur_y += qcrtc->hot_spot_y - hot_y;
+       qcrtc->hot_spot_x = hot_x;
+       qcrtc->hot_spot_y = hot_y;
+
        cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
        cmd->type = QXL_CURSOR_SET;
-       cmd->u.set.position.x = qcrtc->cur_x;
-       cmd->u.set.position.y = qcrtc->cur_y;
+       cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
+       cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
 
        cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0);
 
@@ -441,8 +446,8 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
 
        cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
        cmd->type = QXL_CURSOR_MOVE;
-       cmd->u.position.x = qcrtc->cur_x;
-       cmd->u.position.y = qcrtc->cur_y;
+       cmd->u.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
+       cmd->u.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
        qxl_release_unmap(qdev, release, &cmd->release_info);
 
        qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
index 01a86948eb8cd6007a1db70785b714df9bc9cbb1..3ab90179e9ab9075db3d29d8b3ea55084f0b077c 100644 (file)
@@ -135,6 +135,8 @@ struct qxl_crtc {
        int index;
        int cur_x;
        int cur_y;
+       int hot_spot_x;
+       int hot_spot_y;
 };
 
 struct qxl_output {
index 01b20e14a247b1404c94354c778bbc1fbd8859f9..9de6503b10d8507898ac0488b7e51cf399ae067a 100644 (file)
@@ -310,6 +310,10 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
            && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
                adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
 
+       /* vertical FP must be at least 1 */
+       if (mode->crtc_vsync_start == mode->crtc_vdisplay)
+               adjusted_mode->crtc_vsync_start++;
+
        /* get the native mode for scaling */
        if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
                radeon_panel_mode_fixup(encoder, adjusted_mode);
@@ -892,8 +896,6 @@ atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_m
                        else
                                args.v1.ucLaneNum = 4;
 
-                       if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
-                               args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
@@ -910,6 +912,10 @@ atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_m
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
                        else
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
+
+                       if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
+                               args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+
                        break;
                case 2:
                case 3:
index 2ad462896896b017402688352428082b6925df7b..32491355a1d415833a5517148478af82e493aa0d 100644 (file)
@@ -2608,10 +2608,152 @@ static void evergreen_agp_enable(struct radeon_device *rdev)
        WREG32(VM_CONTEXT1_CNTL, 0);
 }
 
+static const unsigned ni_dig_offsets[] =
+{
+       NI_DIG0_REGISTER_OFFSET,
+       NI_DIG1_REGISTER_OFFSET,
+       NI_DIG2_REGISTER_OFFSET,
+       NI_DIG3_REGISTER_OFFSET,
+       NI_DIG4_REGISTER_OFFSET,
+       NI_DIG5_REGISTER_OFFSET
+};
+
+static const unsigned ni_tx_offsets[] =
+{
+       NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1,
+       NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1,
+       NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1,
+       NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1,
+       NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1,
+       NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1
+};
+
+static const unsigned evergreen_dp_offsets[] =
+{
+       EVERGREEN_DP0_REGISTER_OFFSET,
+       EVERGREEN_DP1_REGISTER_OFFSET,
+       EVERGREEN_DP2_REGISTER_OFFSET,
+       EVERGREEN_DP3_REGISTER_OFFSET,
+       EVERGREEN_DP4_REGISTER_OFFSET,
+       EVERGREEN_DP5_REGISTER_OFFSET
+};
+
+
+/*
+ * Assumption is that EVERGREEN_CRTC_MASTER_EN enable for requested crtc
+ * We go from crtc to connector and it is not relible  since it
+ * should be an opposite direction .If crtc is enable then
+ * find the dig_fe which selects this crtc and insure that it enable.
+ * if such dig_fe is found then find dig_be which selects found dig_be and
+ * insure that it enable and in DP_SST mode.
+ * if UNIPHY_PLL_CONTROL1.enable then we should disconnect timing
+ * from dp symbols clocks .
+ */
+static bool evergreen_is_dp_sst_stream_enabled(struct radeon_device *rdev,
+                                              unsigned crtc_id, unsigned *ret_dig_fe)
+{
+       unsigned i;
+       unsigned dig_fe;
+       unsigned dig_be;
+       unsigned dig_en_be;
+       unsigned uniphy_pll;
+       unsigned digs_fe_selected;
+       unsigned dig_be_mode;
+       unsigned dig_fe_mask;
+       bool is_enabled = false;
+       bool found_crtc = false;
+
+       /* loop through all running dig_fe to find selected crtc */
+       for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) {
+               dig_fe = RREG32(NI_DIG_FE_CNTL + ni_dig_offsets[i]);
+               if (dig_fe & NI_DIG_FE_CNTL_SYMCLK_FE_ON &&
+                   crtc_id == NI_DIG_FE_CNTL_SOURCE_SELECT(dig_fe)) {
+                       /* found running pipe */
+                       found_crtc = true;
+                       dig_fe_mask = 1 << i;
+                       dig_fe = i;
+                       break;
+               }
+       }
+
+       if (found_crtc) {
+               /* loop through all running dig_be to find selected dig_fe */
+               for (i = 0; i < ARRAY_SIZE(ni_dig_offsets); i++) {
+                       dig_be = RREG32(NI_DIG_BE_CNTL + ni_dig_offsets[i]);
+                       /* if dig_fe_selected by dig_be? */
+                       digs_fe_selected = NI_DIG_BE_CNTL_FE_SOURCE_SELECT(dig_be);
+                       dig_be_mode = NI_DIG_FE_CNTL_MODE(dig_be);
+                       if (dig_fe_mask &  digs_fe_selected &&
+                           /* if dig_be in sst mode? */
+                           dig_be_mode == NI_DIG_BE_DPSST) {
+                               dig_en_be = RREG32(NI_DIG_BE_EN_CNTL +
+                                                  ni_dig_offsets[i]);
+                               uniphy_pll = RREG32(NI_DCIO_UNIPHY0_PLL_CONTROL1 +
+                                                   ni_tx_offsets[i]);
+                               /* dig_be enable and tx is running */
+                               if (dig_en_be & NI_DIG_BE_EN_CNTL_ENABLE &&
+                                   dig_en_be & NI_DIG_BE_EN_CNTL_SYMBCLK_ON &&
+                                   uniphy_pll & NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE) {
+                                       is_enabled = true;
+                                       *ret_dig_fe = dig_fe;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return is_enabled;
+}
+
+/*
+ * Blank dig when in dp sst mode
+ * Dig ignores crtc timing
+ */
+static void evergreen_blank_dp_output(struct radeon_device *rdev,
+                                     unsigned dig_fe)
+{
+       unsigned stream_ctrl;
+       unsigned fifo_ctrl;
+       unsigned counter = 0;
+
+       if (dig_fe >= ARRAY_SIZE(evergreen_dp_offsets)) {
+               DRM_ERROR("invalid dig_fe %d\n", dig_fe);
+               return;
+       }
+
+       stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+                            evergreen_dp_offsets[dig_fe]);
+       if (!(stream_ctrl & EVERGREEN_DP_VID_STREAM_CNTL_ENABLE)) {
+               DRM_ERROR("dig %d , should be enable\n", dig_fe);
+               return;
+       }
+
+       stream_ctrl &=~EVERGREEN_DP_VID_STREAM_CNTL_ENABLE;
+       WREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+              evergreen_dp_offsets[dig_fe], stream_ctrl);
+
+       stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+                            evergreen_dp_offsets[dig_fe]);
+       while (counter < 32 && stream_ctrl & EVERGREEN_DP_VID_STREAM_STATUS) {
+               msleep(1);
+               counter++;
+               stream_ctrl = RREG32(EVERGREEN_DP_VID_STREAM_CNTL +
+                                    evergreen_dp_offsets[dig_fe]);
+       }
+       if (counter >= 32 )
+               DRM_ERROR("counter exceeds %d\n", counter);
+
+       fifo_ctrl = RREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe]);
+       fifo_ctrl |= EVERGREEN_DP_STEER_FIFO_RESET;
+       WREG32(EVERGREEN_DP_STEER_FIFO + evergreen_dp_offsets[dig_fe], fifo_ctrl);
+
+}
+
 void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
        u32 crtc_enabled, tmp, frame_count, blackout;
        int i, j;
+       unsigned dig_fe;
 
        if (!ASIC_IS_NODCE(rdev)) {
                save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
@@ -2651,7 +2793,17 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
                                        break;
                                udelay(1);
                        }
-
+                       /*we should disable dig if it drives dp sst*/
+                       /*but we are in radeon_device_init and the topology is unknown*/
+                       /*and it is available after radeon_modeset_init*/
+                       /*the following method radeon_atom_encoder_dpms_dig*/
+                       /*does the job if we initialize it properly*/
+                       /*for now we do it this manually*/
+                       /**/
+                       if (ASIC_IS_DCE5(rdev) &&
+                           evergreen_is_dp_sst_stream_enabled(rdev, i ,&dig_fe))
+                               evergreen_blank_dp_output(rdev, dig_fe);
+                       /*we could remove 6 lines below*/
                        /* XXX this is a hack to avoid strange behavior with EFI on certain systems */
                        WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
                        tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
index aa939dfed3a36586fc814f7077ef24332ab2b684..b436badf9efa356e00b80adee5cda4f191c5b537 100644 (file)
 
 /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
 #define EVERGREEN_HDMI_BASE                            0x7030
+/*DIG block*/
+#define NI_DIG0_REGISTER_OFFSET                 (0x7000  - 0x7000)
+#define NI_DIG1_REGISTER_OFFSET                 (0x7C00  - 0x7000)
+#define NI_DIG2_REGISTER_OFFSET                 (0x10800 - 0x7000)
+#define NI_DIG3_REGISTER_OFFSET                 (0x11400 - 0x7000)
+#define NI_DIG4_REGISTER_OFFSET                 (0x12000 - 0x7000)
+#define NI_DIG5_REGISTER_OFFSET                 (0x12C00 - 0x7000)
+
+
+#define NI_DIG_FE_CNTL                               0x7000
+#       define NI_DIG_FE_CNTL_SOURCE_SELECT(x)        ((x) & 0x3)
+#       define NI_DIG_FE_CNTL_SYMCLK_FE_ON            (1<<24)
+
+
+#define NI_DIG_BE_CNTL                    0x7140
+#       define NI_DIG_BE_CNTL_FE_SOURCE_SELECT(x)     (((x) >> 8 ) & 0x3F)
+#       define NI_DIG_FE_CNTL_MODE(x)                 (((x) >> 16) & 0x7 )
+
+#define NI_DIG_BE_EN_CNTL                              0x7144
+#       define NI_DIG_BE_EN_CNTL_ENABLE               (1 << 0)
+#       define NI_DIG_BE_EN_CNTL_SYMBCLK_ON           (1 << 8)
+#       define NI_DIG_BE_DPSST 0
 
 /* Display Port block */
+#define EVERGREEN_DP0_REGISTER_OFFSET                 (0x730C  - 0x730C)
+#define EVERGREEN_DP1_REGISTER_OFFSET                 (0x7F0C  - 0x730C)
+#define EVERGREEN_DP2_REGISTER_OFFSET                 (0x10B0C - 0x730C)
+#define EVERGREEN_DP3_REGISTER_OFFSET                 (0x1170C - 0x730C)
+#define EVERGREEN_DP4_REGISTER_OFFSET                 (0x1230C - 0x730C)
+#define EVERGREEN_DP5_REGISTER_OFFSET                 (0x12F0C - 0x730C)
+
+
+#define EVERGREEN_DP_VID_STREAM_CNTL                    0x730C
+#       define EVERGREEN_DP_VID_STREAM_CNTL_ENABLE     (1 << 0)
+#       define EVERGREEN_DP_VID_STREAM_STATUS          (1 <<16)
+#define EVERGREEN_DP_STEER_FIFO                         0x7310
+#       define EVERGREEN_DP_STEER_FIFO_RESET           (1 << 0)
 #define EVERGREEN_DP_SEC_CNTL                           0x7280
 #       define EVERGREEN_DP_SEC_STREAM_ENABLE           (1 << 0)
 #       define EVERGREEN_DP_SEC_ASP_ENABLE              (1 << 4)
 #       define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x)      (((x) & 0xf) << 24)
 #       define EVERGREEN_DP_SEC_SS_EN                   (1 << 28)
 
+/*DCIO_UNIPHY block*/
+#define NI_DCIO_UNIPHY0_UNIPHY_TX_CONTROL1            (0x6600  -0x6600)
+#define NI_DCIO_UNIPHY1_UNIPHY_TX_CONTROL1            (0x6640  -0x6600)
+#define NI_DCIO_UNIPHY2_UNIPHY_TX_CONTROL1            (0x6680 - 0x6600)
+#define NI_DCIO_UNIPHY3_UNIPHY_TX_CONTROL1            (0x66C0 - 0x6600)
+#define NI_DCIO_UNIPHY4_UNIPHY_TX_CONTROL1            (0x6700 - 0x6600)
+#define NI_DCIO_UNIPHY5_UNIPHY_TX_CONTROL1            (0x6740 - 0x6600)
+
+#define NI_DCIO_UNIPHY0_PLL_CONTROL1                   0x6618
+#       define NI_DCIO_UNIPHY0_PLL_CONTROL1_ENABLE     (1 << 0)
+
 #endif
index 340f3f549f295314788fbf9b3052880b8095a7f1..9cfc1c3e19657c10432029b95431902e47db2879 100644 (file)
@@ -1996,10 +1996,12 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                   rdev->mode_info.dither_property,
                                                   RADEON_FMT_DITHER_DISABLE);
 
-                       if (radeon_audio != 0)
+                       if (radeon_audio != 0) {
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                               radeon_connector->audio = RADEON_AUDIO_AUTO;
+                       }
                        if (ASIC_IS_DCE5(rdev))
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.output_csc_property,
@@ -2124,6 +2126,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                               radeon_connector->audio = RADEON_AUDIO_AUTO;
                        }
                        if (connector_type == DRM_MODE_CONNECTOR_DVII) {
                                radeon_connector->dac_load_detect = true;
@@ -2179,6 +2182,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                               radeon_connector->audio = RADEON_AUDIO_AUTO;
                        }
                        if (ASIC_IS_DCE5(rdev))
                                drm_object_attach_property(&radeon_connector->base.base,
@@ -2231,6 +2235,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                drm_object_attach_property(&radeon_connector->base.base,
                                                           rdev->mode_info.audio_property,
                                                           RADEON_AUDIO_AUTO);
+                               radeon_connector->audio = RADEON_AUDIO_AUTO;
                        }
                        if (ASIC_IS_DCE5(rdev))
                                drm_object_attach_property(&radeon_connector->base.base,
index e06ac546a90ff185a31f64b4ce6e9fd76d071adc..f342aad79cc6d2debc95269ac2552750647d28d2 100644 (file)
@@ -235,6 +235,8 @@ static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
 {
        struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo);
 
+       if (radeon_ttm_tt_has_userptr(bo->ttm))
+               return -EPERM;
        return drm_vma_node_verify_access(&rbo->gem_base.vma_node, filp);
 }
 
index a82b891ae1febb4a4523fbde3dea3de398c8a40c..caa73de584a53dd8ca9f26cdb6ca97d4f17c6b41 100644 (file)
@@ -2926,9 +2926,12 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = {
        /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
        { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0x2015, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6811, 0x148c, 0x2015, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6810, 0x1682, 0x9275, 0, 120000 },
        { 0, 0, 0, 0 },
 };
 
@@ -3008,6 +3011,10 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                }
                ++p;
        }
+       /* limit mclk on all R7 370 parts for stability */
+       if (rdev->pdev->device == 0x6811 &&
+           rdev->pdev->revision == 0x81)
+               max_mclk = 120000;
 
        if (rps->vce_active) {
                rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
index 62c7b1dafaa4ba6f4c573fd6d631b86b3b83ce45..73e41a8613da338d0151a27efff9c73390645930 100644 (file)
@@ -539,7 +539,7 @@ static int udlfb_create(struct drm_fb_helper *helper,
 out_destroy_fbi:
        drm_fb_helper_release_fbi(helper);
 out_gfree:
-       drm_gem_object_unreference(&ufbdev->ufb.obj->base);
+       drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
 out:
        return ret;
 }
index 2a0a784ab6eec37c34143f250fae9851f5d3ea94..d7528e0d844244bfc1de19ed2f84cd42a3aea836 100644 (file)
@@ -52,7 +52,7 @@ udl_gem_create(struct drm_file *file,
                return ret;
        }
 
-       drm_gem_object_unreference(&obj->base);
+       drm_gem_object_unreference_unlocked(&obj->base);
        *handle_p = handle;
        return 0;
 }
index a0e28f3a278deea575ad50a9342ff4a224e9d6cc..0585fd2031ddcd94f914296bea08e8101ea251d4 100644 (file)
@@ -1068,7 +1068,6 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
                        goto err_register;
                }
 
-               pdev->dev.of_node = of_node;
                pdev->dev.parent = dev;
 
                ret = platform_device_add_data(pdev, &reg->pdata,
@@ -1079,6 +1078,12 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
                        platform_device_put(pdev);
                        goto err_register;
                }
+
+               /*
+                * Set of_node only after calling platform_device_add. Otherwise
+                * the platform:imx-ipuv3-crtc modalias won't be used.
+                */
+               pdev->dev.of_node = of_node;
        }
 
        return 0;
index c6f7a694f67a189daaae4be80645fb8773bfd2d5..ec791e169f8f7c205e1428bc3887ddd2dece043c 100644 (file)
@@ -1897,6 +1897,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
@@ -2615,9 +2616,10 @@ int hid_add_device(struct hid_device *hdev)
        /*
         * Scan generic devices for group information
         */
-       if (hid_ignore_special_drivers ||
-           (!hdev->group &&
-            !hid_match_id(hdev, hid_have_special_driver))) {
+       if (hid_ignore_special_drivers) {
+               hdev->group = HID_GROUP_GENERIC;
+       } else if (!hdev->group &&
+                  !hid_match_id(hdev, hid_have_special_driver)) {
                ret = hid_scan_report(hdev);
                if (ret)
                        hid_warn(hdev, "bad device descriptor (%d)\n", ret);
index 8b78a7f1f779faa586abd156a0f9ce7082616bc5..909ab0176ef2313a382309c7319c9920a6995cf1 100644 (file)
 #define USB_DEVICE_ID_CORSAIR_K90      0x1b02
 
 #define USB_VENDOR_ID_CREATIVELABS     0x041e
+#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51     0x322c
 #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
 
 #define USB_VENDOR_ID_CVTOUCH          0x1ff7
index 591d4ad7708ffe045a4b8faf71ec4a2fd3ff0c48..7ecd96bdf83439afccac5047a58432b8c4b0cc5c 100644 (file)
@@ -396,6 +396,11 @@ static void mt_feature_mapping(struct hid_device *hdev,
                        td->is_buttonpad = true;
 
                break;
+       case 0xff0000c5:
+               /* Retrieve the Win8 blob once to enable some devices */
+               if (usage->usage_index == 0)
+                       mt_get_feature(hdev, field->report);
+               break;
        }
 }
 
index 10bd8e6e4c9c814cbceb863bbff4a87f3d3a283a..0b80633bae91ecb180a7b0d4d245a8dec6313e0d 100644 (file)
@@ -282,17 +282,21 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
        u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
        u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
        u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
+       u16 size;
+       int args_len;
+       int index = 0;
+
+       i2c_hid_dbg(ihid, "%s\n", __func__);
+
+       if (data_len > ihid->bufsize)
+               return -EINVAL;
 
-       /* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
-       u16 size =      2                       /* size */ +
+       size =          2                       /* size */ +
                        (reportID ? 1 : 0)      /* reportID */ +
                        data_len                /* buf */;
-       int args_len =  (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
+       args_len =      (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
                        2                       /* dataRegister */ +
                        size                    /* args */;
-       int index = 0;
-
-       i2c_hid_dbg(ihid, "%s\n", __func__);
 
        if (!use_data && maxOutputLength == 0)
                return -ENOSYS;
index 5dd426fee8cc3c1403307c44445e96a9c93e13e9..0df32fe0e3459a0db81661a9241bdd3f12d801d2 100644 (file)
@@ -951,14 +951,6 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
        return ret;
 }
 
-static void usbhid_restart_queues(struct usbhid_device *usbhid)
-{
-       if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
-               usbhid_restart_out_queue(usbhid);
-       if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-               usbhid_restart_ctrl_queue(usbhid);
-}
-
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
@@ -1404,6 +1396,37 @@ static void hid_cease_io(struct usbhid_device *usbhid)
        usb_kill_urb(usbhid->urbout);
 }
 
+static void hid_restart_io(struct hid_device *hid)
+{
+       struct usbhid_device *usbhid = hid->driver_data;
+       int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl);
+       int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl);
+
+       spin_lock_irq(&usbhid->lock);
+       clear_bit(HID_SUSPENDED, &usbhid->iofl);
+       usbhid_mark_busy(usbhid);
+
+       if (clear_halt || reset_pending)
+               schedule_work(&usbhid->reset_work);
+       usbhid->retry_delay = 0;
+       spin_unlock_irq(&usbhid->lock);
+
+       if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl))
+               return;
+
+       if (!clear_halt) {
+               if (hid_start_in(hid) < 0)
+                       hid_io_error(hid);
+       }
+
+       spin_lock_irq(&usbhid->lock);
+       if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+               usbhid_restart_out_queue(usbhid);
+       if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+               usbhid_restart_ctrl_queue(usbhid);
+       spin_unlock_irq(&usbhid->lock);
+}
+
 /* Treat USB reset pretty much the same as suspend/resume */
 static int hid_pre_reset(struct usb_interface *intf)
 {
@@ -1453,14 +1476,14 @@ static int hid_post_reset(struct usb_interface *intf)
                return 1;
        }
 
+       /* No need to do another reset or clear a halted endpoint */
        spin_lock_irq(&usbhid->lock);
        clear_bit(HID_RESET_PENDING, &usbhid->iofl);
+       clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
        spin_unlock_irq(&usbhid->lock);
        hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-       status = hid_start_in(hid);
-       if (status < 0)
-               hid_io_error(hid);
-       usbhid_restart_queues(usbhid);
+
+       hid_restart_io(hid);
 
        return 0;
 }
@@ -1483,25 +1506,9 @@ void usbhid_put_power(struct hid_device *hid)
 #ifdef CONFIG_PM
 static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
 {
-       struct usbhid_device *usbhid = hid->driver_data;
-       int status;
-
-       spin_lock_irq(&usbhid->lock);
-       clear_bit(HID_SUSPENDED, &usbhid->iofl);
-       usbhid_mark_busy(usbhid);
-
-       if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
-                       test_bit(HID_RESET_PENDING, &usbhid->iofl))
-               schedule_work(&usbhid->reset_work);
-       usbhid->retry_delay = 0;
-
-       usbhid_restart_queues(usbhid);
-       spin_unlock_irq(&usbhid->lock);
-
-       status = hid_start_in(hid);
-       if (status < 0)
-               hid_io_error(hid);
+       int status = 0;
 
+       hid_restart_io(hid);
        if (driver_suspended && hid->driver && hid->driver->resume)
                status = hid->driver->resume(hid);
        return status;
@@ -1570,12 +1577,8 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 static int hid_resume(struct usb_interface *intf)
 {
        struct hid_device *hid = usb_get_intfdata (intf);
-       struct usbhid_device *usbhid = hid->driver_data;
        int status;
 
-       if (!test_bit(HID_STARTED, &usbhid->iofl))
-               return 0;
-
        status = hid_resume_common(hid, true);
        dev_dbg(&intf->dev, "resume status %d\n", status);
        return 0;
@@ -1584,10 +1587,8 @@ static int hid_resume(struct usb_interface *intf)
 static int hid_reset_resume(struct usb_interface *intf)
 {
        struct hid_device *hid = usb_get_intfdata(intf);
-       struct usbhid_device *usbhid = hid->driver_data;
        int status;
 
-       clear_bit(HID_SUSPENDED, &usbhid->iofl);
        status = hid_post_reset(intf);
        if (status >= 0 && hid->driver && hid->driver->reset_resume) {
                int ret = hid->driver->reset_resume(hid);
index 7dd0953cd70f222f037c72b7c217b76eff8d2942..dc8e6adf95a4357ffaf9121a2da8ddc9d2700223 100644 (file)
@@ -70,6 +70,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
+       { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
index 01a4f05c16421b63a09737ad3eb4a4fb249259ae..5c02d7bbc7f20f3dc89081005f8606a3a2506523 100644 (file)
@@ -2492,6 +2492,17 @@ void wacom_setup_device_quirks(struct wacom *wacom)
                }
        }
 
+       /*
+        * Hack for the Bamboo One:
+        * the device presents a PAD/Touch interface as most Bamboos and even
+        * sends ghosts PAD data on it. However, later, we must disable this
+        * ghost interface, and we can not detect it unless we set it here
+        * to WACOM_DEVICETYPE_PAD or WACOM_DEVICETYPE_TOUCH.
+        */
+       if (features->type == BAMBOO_PEN &&
+           features->pktlen == WACOM_PKGLEN_BBTOUCH3)
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+
        /*
         * Raw Wacom-mode pen and touch events both come from interface
         * 0, whose HID descriptor has an application usage of 0xFF0D
@@ -3438,6 +3449,10 @@ static const struct wacom_features wacom_features_0x33E =
        { "Wacom Intuos PT M 2", 21600, 13500, 2047, 63,
          INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
          .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x343 =
+       { "Wacom DTK1651", 34616, 19559, 1023, 0,
+         DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
+         WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
 
 static const struct wacom_features wacom_features_HID_ANY_ID =
        { "Wacom HID", .type = HID_GENERIC };
@@ -3603,6 +3618,7 @@ const struct hid_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x33C) },
        { USB_DEVICE_WACOM(0x33D) },
        { USB_DEVICE_WACOM(0x33E) },
+       { USB_DEVICE_WACOM(0x343) },
        { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x4004) },
        { USB_DEVICE_WACOM(0x5000) },
index 36544c4f653c6d2f1c7c3ca1333186d68f2f6269..303d0c9df907a722e6d366b07a7f4c8d8a7c728b 100644 (file)
@@ -85,6 +85,9 @@ static struct max1111_data *the_max1111;
 
 int max1111_read_channel(int channel)
 {
+       if (!the_max1111 || !the_max1111->spi)
+               return -ENODEV;
+
        return max1111_read(&the_max1111->spi->dev, channel);
 }
 EXPORT_SYMBOL(max1111_read_channel);
@@ -258,6 +261,9 @@ static int max1111_remove(struct spi_device *spi)
 {
        struct max1111_data *data = spi_get_drvdata(spi);
 
+#ifdef CONFIG_SHARPSL_PM
+       the_max1111 = NULL;
+#endif
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&spi->dev.kobj, &max1110_attr_group);
        sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group);
index 83e9f591a54b356150a7e2090e9a14473b6f96a0..e7a348807f0cb2ce91fd48e2d133f034830763be 100644 (file)
@@ -1,6 +1,7 @@
 config STM
        tristate "System Trace Module devices"
        select CONFIGFS_FS
+       select SRCU
        help
          A System Trace Module (STM) is a device exporting data in System
          Trace Protocol (STP) format as defined by MIPI STP standards.
index 714bdc837769fdc74fdf9208c18d0568ecc653ae..b167ab25310a3b53797a8604d0adf360d91fb3e9 100644 (file)
@@ -116,8 +116,8 @@ struct cpm_i2c {
        cbd_t __iomem *rbase;
        u_char *txbuf[CPM_MAXBD];
        u_char *rxbuf[CPM_MAXBD];
-       u32 txdma[CPM_MAXBD];
-       u32 rxdma[CPM_MAXBD];
+       dma_addr_t txdma[CPM_MAXBD];
+       dma_addr_t rxdma[CPM_MAXBD];
 };
 
 static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
index b29c7500461a72c051b29dc2822f28afbf248b35..f54ece8fce781865336caca2e43abb301a69b62c 100644 (file)
@@ -671,7 +671,9 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
                return -EIO;
        }
 
-       clk_prepare_enable(i2c->clk);
+       ret = clk_enable(i2c->clk);
+       if (ret)
+               return ret;
 
        for (i = 0; i < num; i++, msgs++) {
                stop = (i == num - 1);
@@ -695,7 +697,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
        }
 
  out:
-       clk_disable_unprepare(i2c->clk);
+       clk_disable(i2c->clk);
        return ret;
 }
 
@@ -747,7 +749,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       clk_prepare_enable(i2c->clk);
+       ret = clk_prepare_enable(i2c->clk);
+       if (ret)
+               return ret;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
@@ -799,6 +803,10 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, i2c);
 
+       clk_disable(i2c->clk);
+
+       return 0;
+
  err_clk:
        clk_disable_unprepare(i2c->clk);
        return ret;
@@ -810,6 +818,8 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&i2c->adap);
 
+       clk_unprepare(i2c->clk);
+
        return 0;
 }
 
@@ -821,6 +831,8 @@ static int exynos5_i2c_suspend_noirq(struct device *dev)
 
        i2c->suspended = 1;
 
+       clk_unprepare(i2c->clk);
+
        return 0;
 }
 
@@ -830,7 +842,9 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
        struct exynos5_i2c *i2c = platform_get_drvdata(pdev);
        int ret = 0;
 
-       clk_prepare_enable(i2c->clk);
+       ret = clk_prepare_enable(i2c->clk);
+       if (ret)
+               return ret;
 
        ret = exynos5_hsi2c_clock_setup(i2c);
        if (ret) {
@@ -839,7 +853,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
        }
 
        exynos5_i2c_init(i2c);
-       clk_disable_unprepare(i2c->clk);
+       clk_disable(i2c->clk);
        i2c->suspended = 0;
 
        return 0;
index cd4510a6337548d26344b8ccc5cb427ab13dd4ef..146eed70bdf46e0caf005531d18bb5c46db175aa 100644 (file)
@@ -65,7 +65,7 @@
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
-#define INTEL_IDLE_VERSION "0.4"
+#define INTEL_IDLE_VERSION "0.4.1"
 #define PREFIX "intel_idle: "
 
 static struct cpuidle_driver intel_idle_driver = {
@@ -994,36 +994,92 @@ static void intel_idle_cpuidle_devices_uninit(void)
 }
 
 /*
- * intel_idle_state_table_update()
- *
- * Update the default state_table for this CPU-id
+ * ivt_idle_state_table_update(void)
  *
- * Currently used to access tuned IVT multi-socket targets
+ * Tune IVT multi-socket targets
  * Assumption: num_sockets == (max_package_num + 1)
  */
-void intel_idle_state_table_update(void)
+static void ivt_idle_state_table_update(void)
 {
        /* IVT uses a different table for 1-2, 3-4, and > 4 sockets */
-       if (boot_cpu_data.x86_model == 0x3e) { /* IVT */
-               int cpu, package_num, num_sockets = 1;
-
-               for_each_online_cpu(cpu) {
-                       package_num = topology_physical_package_id(cpu);
-                       if (package_num + 1 > num_sockets) {
-                               num_sockets = package_num + 1;
-
-                               if (num_sockets > 4) {
-                                       cpuidle_state_table = ivt_cstates_8s;
-                                       return;
-                               }
+       int cpu, package_num, num_sockets = 1;
+
+       for_each_online_cpu(cpu) {
+               package_num = topology_physical_package_id(cpu);
+               if (package_num + 1 > num_sockets) {
+                       num_sockets = package_num + 1;
+
+                       if (num_sockets > 4) {
+                               cpuidle_state_table = ivt_cstates_8s;
+                               return;
                        }
                }
+       }
+
+       if (num_sockets > 2)
+               cpuidle_state_table = ivt_cstates_4s;
+
+       /* else, 1 and 2 socket systems use default ivt_cstates */
+}
+/*
+ * sklh_idle_state_table_update(void)
+ *
+ * On SKL-H (model 0x5e) disable C8 and C9 if:
+ * C10 is enabled and SGX disabled
+ */
+static void sklh_idle_state_table_update(void)
+{
+       unsigned long long msr;
+       unsigned int eax, ebx, ecx, edx;
+
+
+       /* if PC10 disabled via cmdline intel_idle.max_cstate=7 or shallower */
+       if (max_cstate <= 7)
+               return;
+
+       /* if PC10 not present in CPUID.MWAIT.EDX */
+       if ((mwait_substates & (0xF << 28)) == 0)
+               return;
+
+       rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr);
+
+       /* PC10 is not enabled in PKG C-state limit */
+       if ((msr & 0xF) != 8)
+               return;
+
+       ecx = 0;
+       cpuid(7, &eax, &ebx, &ecx, &edx);
+
+       /* if SGX is present */
+       if (ebx & (1 << 2)) {
 
-               if (num_sockets > 2)
-                       cpuidle_state_table = ivt_cstates_4s;
-               /* else, 1 and 2 socket systems use default ivt_cstates */
+               rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
+
+               /* if SGX is enabled */
+               if (msr & (1 << 18))
+                       return;
+       }
+
+       skl_cstates[5].disabled = 1;    /* C8-SKL */
+       skl_cstates[6].disabled = 1;    /* C9-SKL */
+}
+/*
+ * intel_idle_state_table_update()
+ *
+ * Update the default state_table for this CPU-id
+ */
+
+static void intel_idle_state_table_update(void)
+{
+       switch (boot_cpu_data.x86_model) {
+
+       case 0x3e: /* IVT */
+               ivt_idle_state_table_update();
+               break;
+       case 0x5e: /* SKL-H */
+               sklh_idle_state_table_update();
+               break;
        }
-       return;
 }
 
 /*
@@ -1063,6 +1119,14 @@ static int __init intel_idle_cpuidle_driver_init(void)
                if (num_substates == 0)
                        continue;
 
+               /* if state marked as disabled, skip it */
+               if (cpuidle_state_table[cstate].disabled != 0) {
+                       pr_debug(PREFIX "state %s is disabled",
+                               cpuidle_state_table[cstate].name);
+                       continue;
+               }
+
+
                if (((mwait_cstate + 1) > 2) &&
                        !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
                        mark_tsc_unstable("TSC halts in idle"
index 2d33f1e821db0098a0d774e6c5d0fd44ba596675..291c61a41c9a8cae12198c207a2f12afd5d5532c 100644 (file)
@@ -547,7 +547,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
 {
        int ret;
        int axis = chan->scan_index;
-       unsigned int raw_val;
+       __le16 raw_val;
 
        mutex_lock(&data->mutex);
        ret = bmc150_accel_set_power_state(data, true);
@@ -557,14 +557,14 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
        }
 
        ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
-                              &raw_val, 2);
+                              &raw_val, sizeof(raw_val));
        if (ret < 0) {
                dev_err(data->dev, "Error reading axis %d\n", axis);
                bmc150_accel_set_power_state(data, false);
                mutex_unlock(&data->mutex);
                return ret;
        }
-       *val = sign_extend32(raw_val >> chan->scan_type.shift,
+       *val = sign_extend32(le16_to_cpu(raw_val) >> chan->scan_type.shift,
                             chan->scan_type.realbits - 1);
        ret = bmc150_accel_set_power_state(data, false);
        mutex_unlock(&data->mutex);
@@ -988,6 +988,7 @@ static const struct iio_event_spec bmc150_accel_event = {
                .realbits = (bits),                                     \
                .storagebits = 16,                                      \
                .shift = 16 - (bits),                                   \
+               .endianness = IIO_LE,                                   \
        },                                                              \
        .event_spec = &bmc150_accel_event,                              \
        .num_event_specs = 1                                            \
index 02ff789852a05b411d20aaa7b89e92039305e6cd..acb3b303d8002cec1473f6bc2c6f2f61d496ce8d 100644 (file)
@@ -452,7 +452,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
 static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 {
        int ret;
-       unsigned int raw_val;
+       __le16 raw_val;
 
        mutex_lock(&data->mutex);
        ret = bmg160_set_power_state(data, true);
@@ -462,7 +462,7 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
        }
 
        ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val,
-                              2);
+                              sizeof(raw_val));
        if (ret < 0) {
                dev_err(data->dev, "Error reading axis %d\n", axis);
                bmg160_set_power_state(data, false);
@@ -470,7 +470,7 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
                return ret;
        }
 
-       *val = sign_extend32(raw_val, 15);
+       *val = sign_extend32(le16_to_cpu(raw_val), 15);
        ret = bmg160_set_power_state(data, false);
        mutex_unlock(&data->mutex);
        if (ret < 0)
@@ -733,6 +733,7 @@ static const struct iio_event_spec bmg160_event = {
                .sign = 's',                                            \
                .realbits = 16,                                 \
                .storagebits = 16,                                      \
+               .endianness = IIO_LE,                                   \
        },                                                              \
        .event_spec = &bmg160_event,                                    \
        .num_event_specs = 1                                            \
@@ -780,7 +781,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
                        mutex_unlock(&data->mutex);
                        goto err;
                }
-               data->buffer[i++] = ret;
+               data->buffer[i++] = val;
        }
        mutex_unlock(&data->mutex);
 
index b13936dacc78377fec8254380ee92c0f95d50b25..f2a7f72f7aa68ec18873b6cc62e8d430a04f2ec6 100644 (file)
@@ -462,6 +462,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
        int rc;
        int irq;
 
+       init_waitqueue_head(&data->data_ready_queue);
+       clear_bit(0, &data->flags);
        if (client->irq)
                irq = client->irq;
        else
@@ -477,8 +479,6 @@ static int ak8975_setup_irq(struct ak8975_data *data)
                return rc;
        }
 
-       init_waitqueue_head(&data->data_ready_queue);
-       clear_bit(0, &data->flags);
        data->eoc_irq = irq;
 
        return rc;
@@ -732,7 +732,7 @@ static int ak8975_probe(struct i2c_client *client,
        int eoc_gpio;
        int err;
        const char *name = NULL;
-       enum asahi_compass_chipset chipset;
+       enum asahi_compass_chipset chipset = AK_MAX_TYPE;
 
        /* Grab and set up the supplied GPIO. */
        if (client->dev.platform_data)
index 06a4d9c3558196ec54d1d04200e62b14753c4c62..9daca46819222bedb73e166eda7d1607af6277c8 100644 (file)
@@ -44,6 +44,7 @@ static inline int st_magn_allocate_ring(struct iio_dev *indio_dev)
 static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev)
 {
 }
+#define ST_MAGN_TRIGGER_SET_STATE NULL
 #endif /* CONFIG_IIO_BUFFER */
 
 #endif /* ST_MAGN_H */
index 6b4e8a008bc0418f3ad54728b73e03e6e8d6e1fa..564adf3116e875ba3a599959b1c37db77333e8a1 100644 (file)
@@ -48,6 +48,7 @@
 
 #include <asm/uaccess.h>
 
+#include <rdma/ib.h>
 #include <rdma/ib_cm.h>
 #include <rdma/ib_user_cm.h>
 #include <rdma/ib_marshall.h>
@@ -1103,6 +1104,9 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf,
        struct ib_ucm_cmd_hdr hdr;
        ssize_t result;
 
+       if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
+               return -EACCES;
+
        if (len < sizeof(hdr))
                return -EINVAL;
 
index 8b5a934e1133d80b42e12d1790b3672d73e4a779..886f61ea6cc7d2f58e8d8c739c511ccd7dc78df7 100644 (file)
@@ -1574,6 +1574,9 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf,
        struct rdma_ucm_cmd_hdr hdr;
        ssize_t ret;
 
+       if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
+               return -EACCES;
+
        if (len < sizeof(hdr))
                return -EINVAL;
 
index e3ef28861be63dd453d0fd1b55ec21f939919624..24f3ca2c4ad761bf639eb2933c30387c25377c21 100644 (file)
@@ -48,6 +48,8 @@
 
 #include <asm/uaccess.h>
 
+#include <rdma/ib.h>
+
 #include "uverbs.h"
 
 MODULE_AUTHOR("Roland Dreier");
@@ -682,6 +684,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
        int srcu_key;
        ssize_t ret;
 
+       if (WARN_ON_ONCE(!ib_safe_file_access(filp)))
+               return -EACCES;
+
        if (count < sizeof hdr)
                return -EINVAL;
 
index de9cd6901752fc1e3da38d64f62bfce7cb853501..bc147582bed9ed8a9cef92b8d0000562d4c49684 100644 (file)
@@ -162,7 +162,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
        cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, T4_BAR2_QTYPE_INGRESS,
                                      &cq->bar2_qid,
                                      user ? &cq->bar2_pa : NULL);
-       if (user && !cq->bar2_va) {
+       if (user && !cq->bar2_pa) {
                pr_warn(MOD "%s: cqid %u not in BAR2 range.\n",
                        pci_name(rdev->lldi.pdev), cq->cqid);
                ret = -EINVAL;
index aa515afee7248823428cb2b725bf10c70f4fd82a..53aa7515f542a512eb9d8dcee37b7559d8e60de9 100644 (file)
@@ -185,6 +185,10 @@ void __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid,
 
        if (pbar2_pa)
                *pbar2_pa = (rdev->bar2_pa + bar2_qoffset) & PAGE_MASK;
+
+       if (is_t4(rdev->lldi.adapter_type))
+               return NULL;
+
        return rdev->bar2_kva + bar2_qoffset;
 }
 
@@ -270,7 +274,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        /*
         * User mode must have bar2 access.
         */
-       if (user && (!wq->sq.bar2_va || !wq->rq.bar2_va)) {
+       if (user && (!wq->sq.bar2_pa || !wq->rq.bar2_pa)) {
                pr_warn(MOD "%s: sqid %u or rqid %u not in BAR2 range.\n",
                        pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid);
                goto free_dma;
index c4e0915283904e034ffdb05be18420c9eac7fba8..721d63f5b461092a9ca41210696111f1a67ef410 100644 (file)
@@ -273,7 +273,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
                     sizeof(struct mlx5_wqe_ctrl_seg)) /
                     sizeof(struct mlx5_wqe_data_seg);
        props->max_sge = min(max_rq_sg, max_sq_sg);
-       props->max_sge_rd = props->max_sge;
+       props->max_sge_rd          = MLX5_MAX_SGE_RD;
        props->max_cq              = 1 << MLX5_CAP_GEN(mdev, log_max_cq);
        props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_cq_sz)) - 1;
        props->max_mr              = 1 << MLX5_CAP_GEN(mdev, log_max_mkey);
index e449e394963f00d42cd11ecafbca6081f9011bcd..24f4a782e0f431282bb8f79fc496a0b998a7a55a 100644 (file)
@@ -45,6 +45,8 @@
 #include <linux/export.h>
 #include <linux/uio.h>
 
+#include <rdma/ib.h>
+
 #include "qib.h"
 #include "qib_common.h"
 #include "qib_user_sdma.h"
@@ -2067,6 +2069,9 @@ static ssize_t qib_write(struct file *fp, const char __user *data,
        ssize_t ret = 0;
        void *dest;
 
+       if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
+               return -EACCES;
+
        if (count < sizeof(cmd.type)) {
                ret = -EINVAL;
                goto bail;
index f357ca67a41cd859b2ff5e704621f72813b91fa8..87799de90a1debb6990f0bcb083a4f52c86a097c 100644 (file)
@@ -456,7 +456,10 @@ out_locked:
        return status;
 }
 
-static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
+/*
+ * Caller must hold 'priv->lock'
+ */
+static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_sa_multicast *multicast;
@@ -466,6 +469,10 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
        ib_sa_comp_mask comp_mask;
        int ret = 0;
 
+       if (!priv->broadcast ||
+           !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
+               return -EINVAL;
+
        ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw);
 
        rec.mgid     = mcast->mcmember.mgid;
@@ -525,20 +532,23 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
                        rec.join_state = 4;
 #endif
        }
+       spin_unlock_irq(&priv->lock);
 
        multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
                                         &rec, comp_mask, GFP_KERNEL,
                                         ipoib_mcast_join_complete, mcast);
+       spin_lock_irq(&priv->lock);
        if (IS_ERR(multicast)) {
                ret = PTR_ERR(multicast);
                ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret);
-               spin_lock_irq(&priv->lock);
                /* Requeue this join task with a backoff delay */
                __ipoib_mcast_schedule_join_thread(priv, mcast, 1);
                clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
                spin_unlock_irq(&priv->lock);
                complete(&mcast->done);
+               spin_lock_irq(&priv->lock);
        }
+       return 0;
 }
 
 void ipoib_mcast_join_task(struct work_struct *work)
@@ -620,9 +630,10 @@ void ipoib_mcast_join_task(struct work_struct *work)
                                /* Found the next unjoined group */
                                init_completion(&mcast->done);
                                set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
-                               spin_unlock_irq(&priv->lock);
-                               ipoib_mcast_join(dev, mcast);
-                               spin_lock_irq(&priv->lock);
+                               if (ipoib_mcast_join(dev, mcast)) {
+                                       spin_unlock_irq(&priv->lock);
+                                       return;
+                               }
                        } else if (!delay_until ||
                                 time_before(mcast->delay_until, delay_until))
                                delay_until = mcast->delay_until;
@@ -641,10 +652,9 @@ out:
        if (mcast) {
                init_completion(&mcast->done);
                set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+               ipoib_mcast_join(dev, mcast);
        }
        spin_unlock_irq(&priv->lock);
-       if (mcast)
-               ipoib_mcast_join(dev, mcast);
 }
 
 int ipoib_mcast_start_thread(struct net_device *dev)
index 8a51c3b5d657e5a49ae50c4e5f104a7298d732f2..b0edb66a291bc3996deb8f5697a838498ad27f14 100644 (file)
@@ -66,6 +66,7 @@ isert_rdma_accept(struct isert_conn *isert_conn);
 struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np);
 
 static void isert_release_work(struct work_struct *work);
+static void isert_wait4flush(struct isert_conn *isert_conn);
 
 static inline bool
 isert_prot_cmd(struct isert_conn *conn, struct se_cmd *cmd)
@@ -815,12 +816,31 @@ isert_put_conn(struct isert_conn *isert_conn)
        kref_put(&isert_conn->kref, isert_release_kref);
 }
 
+static void
+isert_handle_unbound_conn(struct isert_conn *isert_conn)
+{
+       struct isert_np *isert_np = isert_conn->cm_id->context;
+
+       mutex_lock(&isert_np->mutex);
+       if (!list_empty(&isert_conn->node)) {
+               /*
+                * This means iscsi doesn't know this connection
+                * so schedule a cleanup ourselves
+                */
+               list_del_init(&isert_conn->node);
+               isert_put_conn(isert_conn);
+               complete(&isert_conn->wait);
+               queue_work(isert_release_wq, &isert_conn->release_work);
+       }
+       mutex_unlock(&isert_np->mutex);
+}
+
 /**
  * isert_conn_terminate() - Initiate connection termination
  * @isert_conn: isert connection struct
  *
  * Notes:
- * In case the connection state is FULL_FEATURE, move state
+ * In case the connection state is BOUND, move state
  * to TEMINATING and start teardown sequence (rdma_disconnect).
  * In case the connection state is UP, complete flush as well.
  *
@@ -832,23 +852,19 @@ isert_conn_terminate(struct isert_conn *isert_conn)
 {
        int err;
 
-       switch (isert_conn->state) {
-       case ISER_CONN_TERMINATING:
-               break;
-       case ISER_CONN_UP:
-       case ISER_CONN_FULL_FEATURE: /* FALLTHRU */
-               isert_info("Terminating conn %p state %d\n",
-                          isert_conn, isert_conn->state);
-               isert_conn->state = ISER_CONN_TERMINATING;
-               err = rdma_disconnect(isert_conn->cm_id);
-               if (err)
-                       isert_warn("Failed rdma_disconnect isert_conn %p\n",
-                                  isert_conn);
-               break;
-       default:
-               isert_warn("conn %p teminating in state %d\n",
-                          isert_conn, isert_conn->state);
-       }
+       if (isert_conn->state >= ISER_CONN_TERMINATING)
+               return;
+
+       isert_info("Terminating conn %p state %d\n",
+                  isert_conn, isert_conn->state);
+       isert_conn->state = ISER_CONN_TERMINATING;
+       err = rdma_disconnect(isert_conn->cm_id);
+       if (err)
+               isert_warn("Failed rdma_disconnect isert_conn %p\n",
+                          isert_conn);
+
+       isert_info("conn %p completing wait\n", isert_conn);
+       complete(&isert_conn->wait);
 }
 
 static int
@@ -882,35 +898,27 @@ static int
 isert_disconnected_handler(struct rdma_cm_id *cma_id,
                           enum rdma_cm_event_type event)
 {
-       struct isert_np *isert_np = cma_id->context;
-       struct isert_conn *isert_conn;
-       bool terminating = false;
-
-       if (isert_np->cm_id == cma_id)
-               return isert_np_cma_handler(cma_id->context, event);
-
-       isert_conn = cma_id->qp->qp_context;
+       struct isert_conn *isert_conn = cma_id->qp->qp_context;
 
        mutex_lock(&isert_conn->mutex);
-       terminating = (isert_conn->state == ISER_CONN_TERMINATING);
-       isert_conn_terminate(isert_conn);
-       mutex_unlock(&isert_conn->mutex);
-
-       isert_info("conn %p completing wait\n", isert_conn);
-       complete(&isert_conn->wait);
-
-       if (terminating)
-               goto out;
-
-       mutex_lock(&isert_np->mutex);
-       if (!list_empty(&isert_conn->node)) {
-               list_del_init(&isert_conn->node);
-               isert_put_conn(isert_conn);
-               queue_work(isert_release_wq, &isert_conn->release_work);
+       switch (isert_conn->state) {
+       case ISER_CONN_TERMINATING:
+               break;
+       case ISER_CONN_UP:
+               isert_conn_terminate(isert_conn);
+               isert_wait4flush(isert_conn);
+               isert_handle_unbound_conn(isert_conn);
+               break;
+       case ISER_CONN_BOUND:
+       case ISER_CONN_FULL_FEATURE: /* FALLTHRU */
+               iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+               break;
+       default:
+               isert_warn("conn %p teminating in state %d\n",
+                          isert_conn, isert_conn->state);
        }
-       mutex_unlock(&isert_np->mutex);
+       mutex_unlock(&isert_conn->mutex);
 
-out:
        return 0;
 }
 
@@ -929,12 +937,16 @@ isert_connect_error(struct rdma_cm_id *cma_id)
 static int
 isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 {
+       struct isert_np *isert_np = cma_id->context;
        int ret = 0;
 
        isert_info("%s (%d): status %d id %p np %p\n",
                   rdma_event_msg(event->event), event->event,
                   event->status, cma_id, cma_id->context);
 
+       if (isert_np->cm_id == cma_id)
+               return isert_np_cma_handler(cma_id->context, event->event);
+
        switch (event->event) {
        case RDMA_CM_EVENT_CONNECT_REQUEST:
                ret = isert_connect_request(cma_id, event);
@@ -980,13 +992,10 @@ isert_post_recvm(struct isert_conn *isert_conn, u32 count)
        rx_wr--;
        rx_wr->next = NULL; /* mark end of work requests list */
 
-       isert_conn->post_recv_buf_count += count;
        ret = ib_post_recv(isert_conn->qp, isert_conn->rx_wr,
                           &rx_wr_failed);
-       if (ret) {
+       if (ret)
                isert_err("ib_post_recv() failed with ret: %d\n", ret);
-               isert_conn->post_recv_buf_count -= count;
-       }
 
        return ret;
 }
@@ -1002,12 +1011,9 @@ isert_post_recv(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc)
        rx_wr.num_sge = 1;
        rx_wr.next = NULL;
 
-       isert_conn->post_recv_buf_count++;
        ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_failed);
-       if (ret) {
+       if (ret)
                isert_err("ib_post_recv() failed with ret: %d\n", ret);
-               isert_conn->post_recv_buf_count--;
-       }
 
        return ret;
 }
@@ -1120,12 +1126,9 @@ isert_rdma_post_recvl(struct isert_conn *isert_conn)
        rx_wr.sg_list = &sge;
        rx_wr.num_sge = 1;
 
-       isert_conn->post_recv_buf_count++;
        ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_fail);
-       if (ret) {
+       if (ret)
                isert_err("ib_post_recv() failed: %d\n", ret);
-               isert_conn->post_recv_buf_count--;
-       }
 
        return ret;
 }
@@ -1620,7 +1623,6 @@ isert_rcv_completion(struct iser_rx_desc *desc,
        ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen,
                                      DMA_FROM_DEVICE);
 
-       isert_conn->post_recv_buf_count--;
 }
 
 static int
@@ -2035,7 +2037,8 @@ is_isert_tx_desc(struct isert_conn *isert_conn, void *wr_id)
        void *start = isert_conn->rx_descs;
        int len = ISERT_QP_MAX_RECV_DTOS * sizeof(*isert_conn->rx_descs);
 
-       if (wr_id >= start && wr_id < start + len)
+       if ((wr_id >= start && wr_id < start + len) ||
+           (wr_id == isert_conn->login_req_buf))
                return false;
 
        return true;
@@ -2059,10 +2062,6 @@ isert_cq_comp_err(struct isert_conn *isert_conn, struct ib_wc *wc)
                        isert_unmap_tx_desc(desc, ib_dev);
                else
                        isert_completion_put(desc, isert_cmd, ib_dev, true);
-       } else {
-               isert_conn->post_recv_buf_count--;
-               if (!isert_conn->post_recv_buf_count)
-                       iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
        }
 }
 
@@ -3193,6 +3192,7 @@ accept_wait:
 
        conn->context = isert_conn;
        isert_conn->conn = conn;
+       isert_conn->state = ISER_CONN_BOUND;
 
        isert_set_conn_info(np, conn, isert_conn);
 
index 3d7fbc47c3434c32308136b7faec65590b74d439..1874d21daee07cd3e76b8a3d06af37a04650db3f 100644 (file)
@@ -50,6 +50,7 @@ enum iser_ib_op_code {
 enum iser_conn_state {
        ISER_CONN_INIT,
        ISER_CONN_UP,
+       ISER_CONN_BOUND,
        ISER_CONN_FULL_FEATURE,
        ISER_CONN_TERMINATING,
        ISER_CONN_DOWN,
@@ -144,7 +145,6 @@ struct isert_device;
 
 struct isert_conn {
        enum iser_conn_state    state;
-       int                     post_recv_buf_count;
        u32                     responder_resources;
        u32                     initiator_depth;
        bool                    pi_support;
index 2e2fe818ca9f1acc42d74c8f4d0e0cfbaf810172..eaabf31258462e06d961e35a4e3e7f7294c48a9e 100644 (file)
@@ -1737,47 +1737,6 @@ send_sense:
        return -1;
 }
 
-/**
- * srpt_rx_mgmt_fn_tag() - Process a task management function by tag.
- * @ch: RDMA channel of the task management request.
- * @fn: Task management function to perform.
- * @req_tag: Tag of the SRP task management request.
- * @mgmt_ioctx: I/O context of the task management request.
- *
- * Returns zero if the target core will process the task management
- * request asynchronously.
- *
- * Note: It is assumed that the initiator serializes tag-based task management
- * requests.
- */
-static int srpt_rx_mgmt_fn_tag(struct srpt_send_ioctx *ioctx, u64 tag)
-{
-       struct srpt_device *sdev;
-       struct srpt_rdma_ch *ch;
-       struct srpt_send_ioctx *target;
-       int ret, i;
-
-       ret = -EINVAL;
-       ch = ioctx->ch;
-       BUG_ON(!ch);
-       BUG_ON(!ch->sport);
-       sdev = ch->sport->sdev;
-       BUG_ON(!sdev);
-       spin_lock_irq(&sdev->spinlock);
-       for (i = 0; i < ch->rq_size; ++i) {
-               target = ch->ioctx_ring[i];
-               if (target->cmd.se_lun == ioctx->cmd.se_lun &&
-                   target->cmd.tag == tag &&
-                   srpt_get_cmd_state(target) != SRPT_STATE_DONE) {
-                       ret = 0;
-                       /* now let the target core abort &target->cmd; */
-                       break;
-               }
-       }
-       spin_unlock_irq(&sdev->spinlock);
-       return ret;
-}
-
 static int srp_tmr_to_tcm(int fn)
 {
        switch (fn) {
@@ -1812,7 +1771,6 @@ static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch,
        struct se_cmd *cmd;
        struct se_session *sess = ch->sess;
        uint64_t unpacked_lun;
-       uint32_t tag = 0;
        int tcm_tmr;
        int rc;
 
@@ -1828,25 +1786,10 @@ static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch,
        srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT);
        send_ioctx->cmd.tag = srp_tsk->tag;
        tcm_tmr = srp_tmr_to_tcm(srp_tsk->tsk_mgmt_func);
-       if (tcm_tmr < 0) {
-               send_ioctx->cmd.se_tmr_req->response =
-                       TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
-               goto fail;
-       }
        unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_tsk->lun,
                                       sizeof(srp_tsk->lun));
-
-       if (srp_tsk->tsk_mgmt_func == SRP_TSK_ABORT_TASK) {
-               rc = srpt_rx_mgmt_fn_tag(send_ioctx, srp_tsk->task_tag);
-               if (rc < 0) {
-                       send_ioctx->cmd.se_tmr_req->response =
-                                       TMR_TASK_DOES_NOT_EXIST;
-                       goto fail;
-               }
-               tag = srp_tsk->task_tag;
-       }
        rc = target_submit_tmr(&send_ioctx->cmd, sess, NULL, unpacked_lun,
-                               srp_tsk, tcm_tmr, GFP_KERNEL, tag,
+                               srp_tsk, tcm_tmr, GFP_KERNEL, srp_tsk->task_tag,
                                TARGET_SCF_ACK_KREF);
        if (rc != 0) {
                send_ioctx->cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
index cfd58e87da2620061f2d93e01244c9d052319991..1c5914cae8533326e17b878b406bedca130912d6 100644 (file)
@@ -817,26 +817,49 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
 
        ar2->udev = udev;
 
+       /* Sanity check, first interface must have an endpoint */
+       if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
+               dev_err(&interface->dev,
+                       "%s(): interface 0 must have an endpoint\n", __func__);
+               r = -ENODEV;
+               goto fail1;
+       }
        ar2->intf[0] = interface;
        ar2->ep[0] = &alt->endpoint[0].desc;
 
+       /* Sanity check, the device must have two interfaces */
        ar2->intf[1] = usb_ifnum_to_if(udev, 1);
+       if ((udev->actconfig->desc.bNumInterfaces < 2) || !ar2->intf[1]) {
+               dev_err(&interface->dev, "%s(): need 2 interfaces, found %d\n",
+                       __func__, udev->actconfig->desc.bNumInterfaces);
+               r = -ENODEV;
+               goto fail1;
+       }
+
        r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
        if (r)
                goto fail1;
+
+       /* Sanity check, second interface must have an endpoint */
        alt = ar2->intf[1]->cur_altsetting;
+       if (alt->desc.bNumEndpoints < 1 || !alt->endpoint) {
+               dev_err(&interface->dev,
+                       "%s(): interface 1 must have an endpoint\n", __func__);
+               r = -ENODEV;
+               goto fail2;
+       }
        ar2->ep[1] = &alt->endpoint[0].desc;
 
        r = ati_remote2_urb_init(ar2);
        if (r)
-               goto fail2;
+               goto fail3;
 
        ar2->channel_mask = channel_mask;
        ar2->mode_mask = mode_mask;
 
        r = ati_remote2_setup(ar2, ar2->channel_mask);
        if (r)
-               goto fail2;
+               goto fail3;
 
        usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
        strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
@@ -845,11 +868,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
 
        r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
        if (r)
-               goto fail2;
+               goto fail3;
 
        r = ati_remote2_input_init(ar2);
        if (r)
-               goto fail3;
+               goto fail4;
 
        usb_set_intfdata(interface, ar2);
 
@@ -857,10 +880,11 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
 
        return 0;
 
- fail3:
+ fail4:
        sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
- fail2:
+ fail3:
        ati_remote2_urb_cleanup(ar2);
+ fail2:
        usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
  fail1:
        kfree(ar2);
index ac1fa5f4458052a97d5e8793123ce6b54623a9fa..9c0ea36913b4a98293911f62a2d649dc08a855cd 100644 (file)
@@ -1663,6 +1663,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
 
        pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
                                         union_desc->bMasterInterface0);
+       if (!pcu->ctrl_intf)
+               return -EINVAL;
 
        alt = pcu->ctrl_intf->cur_altsetting;
        pcu->ep_ctrl = &alt->endpoint[0].desc;
@@ -1670,6 +1672,8 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
 
        pcu->data_intf = usb_ifnum_to_if(pcu->udev,
                                         union_desc->bSlaveInterface0);
+       if (!pcu->data_intf)
+               return -EINVAL;
 
        alt = pcu->data_intf->cur_altsetting;
        if (alt->desc.bNumEndpoints != 2) {
index 3f02e0e03d128afaee7439e509f00d22f23e9e59..67aab86048ad73faa1f1af16c1ae1663cf4500f1 100644 (file)
@@ -353,7 +353,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
        if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
                kpd_delay = 15625;
 
-       if (kpd_delay > 62500 || kpd_delay == 0) {
+       /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+       if (kpd_delay > USEC_PER_SEC * 2 || kpd_delay < USEC_PER_SEC / 64) {
                dev_err(&pdev->dev, "invalid power key trigger delay\n");
                return -EINVAL;
        }
@@ -385,8 +386,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
        pwr->name = "pmic8xxx_pwrkey";
        pwr->phys = "pmic8xxx_pwrkey/input0";
 
-       delay = (kpd_delay << 10) / USEC_PER_SEC;
-       delay = 1 + ilog2(delay);
+       delay = (kpd_delay << 6) / USEC_PER_SEC;
+       delay = ilog2(delay);
 
        err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
        if (err < 0) {
index 63b539d3dabae13ce7d1cb12fe19322f655043fd..84909a12ff36c231e7bcfc545bc2ce180c6cd26f 100644 (file)
@@ -307,6 +307,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
        int error = -ENOMEM;
 
        interface = intf->cur_altsetting;
+       if (interface->desc.bNumEndpoints < 1)
+               return -EINVAL;
+
        endpoint = &interface->endpoint[0].desc;
        if (!usb_endpoint_is_int_in(endpoint))
                return -EIO;
index 6025eb430c0a5010c908961ccf8897943fd3c945..a41d8328c0643ccd9f2c88885f47be262983df30 100644 (file)
@@ -862,8 +862,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
        if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
                return;
 
-       /* Bug in FW 8.1, buttons are reported only when ExtBit is 1 */
-       if (SYN_ID_FULL(priv->identity) == 0x801 &&
+       /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */
+       if ((SYN_ID_FULL(priv->identity) == 0x801 ||
+            SYN_ID_FULL(priv->identity) == 0x802) &&
            !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
                return;
 
index 3a7f3a4a439635064a4e8ca78e1e7860b9072a47..7c18249d6c8e820e3fe86ffa66196164dbef2d3f 100644 (file)
@@ -858,6 +858,14 @@ static int gtco_probe(struct usb_interface *usbinterface,
                goto err_free_buf;
        }
 
+       /* Sanity check that a device has an endpoint */
+       if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) {
+               dev_err(&usbinterface->dev,
+                       "Invalid number of endpoints\n");
+               error = -EINVAL;
+               goto err_free_urb;
+       }
+
        /*
         * The endpoint is always altsetting 0, we know this since we know
         * this device only has one interrupt endpoint
@@ -879,7 +887,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
         * HID report descriptor
         */
        if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
-                                    HID_DEVICE_TYPE, &hid_desc) != 0){
+                                    HID_DEVICE_TYPE, &hid_desc) != 0) {
                dev_err(&usbinterface->dev,
                        "Can't retrieve exta USB descriptor to get hid report descriptor length\n");
                error = -EIO;
index 9bbadaaf6bc3723f044a9c44e8619773d242ec8f..7b3845aa5983ad57892a0022990f3353bcca82b6 100644 (file)
@@ -370,8 +370,8 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
                        point.coord_x = point.coord_y = 0;
                }
 
-               point.state = payload[9 * i + 5] & 0x03;
-               point.id = (payload[9 * i + 5] & 0xfc) >> 2;
+               point.state = payload[9 * i + 5] & 0x0f;
+               point.id = (payload[9 * i + 5] & 0xf0) >> 4;
 
                /* determine touch major, minor and orientation */
                point.area_major = max(payload[9 * i + 6],
index fc836f523afafb7ad643e07edbb1053a8466023e..b9319b76a8a193e9da184290e0282a94d5d2ae14 100644 (file)
@@ -91,6 +91,7 @@ struct iommu_dev_data {
        struct list_head dev_data_list;   /* For global dev_data_list */
        struct protection_domain *domain; /* Domain the device is bound to */
        u16 devid;                        /* PCI Device ID */
+       u16 alias;                        /* Alias Device ID */
        bool iommu_v2;                    /* Device can make use of IOMMUv2 */
        bool passthrough;                 /* Device is identity mapped */
        struct {
@@ -125,6 +126,13 @@ static struct protection_domain *to_pdomain(struct iommu_domain *dom)
        return container_of(dom, struct protection_domain, domain);
 }
 
+static inline u16 get_device_id(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       return PCI_DEVID(pdev->bus->number, pdev->devfn);
+}
+
 static struct iommu_dev_data *alloc_dev_data(u16 devid)
 {
        struct iommu_dev_data *dev_data;
@@ -162,6 +170,68 @@ out_unlock:
        return dev_data;
 }
 
+static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
+{
+       *(u16 *)data = alias;
+       return 0;
+}
+
+static u16 get_alias(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       u16 devid, ivrs_alias, pci_alias;
+
+       devid = get_device_id(dev);
+       ivrs_alias = amd_iommu_alias_table[devid];
+       pci_for_each_dma_alias(pdev, __last_alias, &pci_alias);
+
+       if (ivrs_alias == pci_alias)
+               return ivrs_alias;
+
+       /*
+        * DMA alias showdown
+        *
+        * The IVRS is fairly reliable in telling us about aliases, but it
+        * can't know about every screwy device.  If we don't have an IVRS
+        * reported alias, use the PCI reported alias.  In that case we may
+        * still need to initialize the rlookup and dev_table entries if the
+        * alias is to a non-existent device.
+        */
+       if (ivrs_alias == devid) {
+               if (!amd_iommu_rlookup_table[pci_alias]) {
+                       amd_iommu_rlookup_table[pci_alias] =
+                               amd_iommu_rlookup_table[devid];
+                       memcpy(amd_iommu_dev_table[pci_alias].data,
+                              amd_iommu_dev_table[devid].data,
+                              sizeof(amd_iommu_dev_table[pci_alias].data));
+               }
+
+               return pci_alias;
+       }
+
+       pr_info("AMD-Vi: Using IVRS reported alias %02x:%02x.%d "
+               "for device %s[%04x:%04x], kernel reported alias "
+               "%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias),
+               PCI_FUNC(ivrs_alias), dev_name(dev), pdev->vendor, pdev->device,
+               PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias),
+               PCI_FUNC(pci_alias));
+
+       /*
+        * If we don't have a PCI DMA alias and the IVRS alias is on the same
+        * bus, then the IVRS table may know about a quirk that we don't.
+        */
+       if (pci_alias == devid &&
+           PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) {
+               pdev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
+               pdev->dma_alias_devfn = ivrs_alias & 0xff;
+               pr_info("AMD-Vi: Added PCI DMA alias %02x.%d for %s\n",
+                       PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias),
+                       dev_name(dev));
+       }
+
+       return ivrs_alias;
+}
+
 static struct iommu_dev_data *find_dev_data(u16 devid)
 {
        struct iommu_dev_data *dev_data;
@@ -174,13 +244,6 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
        return dev_data;
 }
 
-static inline u16 get_device_id(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-
-       return PCI_DEVID(pdev->bus->number, pdev->devfn);
-}
-
 static struct iommu_dev_data *get_dev_data(struct device *dev)
 {
        return dev->archdata.iommu;
@@ -308,6 +371,8 @@ static int iommu_init_device(struct device *dev)
        if (!dev_data)
                return -ENOMEM;
 
+       dev_data->alias = get_alias(dev);
+
        if (pci_iommuv2_capable(pdev)) {
                struct amd_iommu *iommu;
 
@@ -328,7 +393,7 @@ static void iommu_ignore_device(struct device *dev)
        u16 devid, alias;
 
        devid = get_device_id(dev);
-       alias = amd_iommu_alias_table[devid];
+       alias = get_alias(dev);
 
        memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
        memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));
@@ -1017,7 +1082,7 @@ static int device_flush_dte(struct iommu_dev_data *dev_data)
        int ret;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
-       alias = amd_iommu_alias_table[dev_data->devid];
+       alias = dev_data->alias;
 
        ret = iommu_flush_dte(iommu, dev_data->devid);
        if (!ret && alias != dev_data->devid)
@@ -1891,7 +1956,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
        bool ats;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
-       alias = amd_iommu_alias_table[dev_data->devid];
+       alias = dev_data->alias;
        ats   = dev_data->ats.enabled;
 
        /* Update data structures */
@@ -1925,7 +1990,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
                return;
 
        iommu = amd_iommu_rlookup_table[dev_data->devid];
-       alias = amd_iommu_alias_table[dev_data->devid];
+       alias = dev_data->alias;
 
        /* decrease reference counters */
        dev_data->domain->dev_iommu[iommu->index] -= 1;
index 72d6182666cbd24ba785fc59572c655b6f0c2c8f..58f2fe687a24ddd29ac6d786862eefc33098d795 100644 (file)
@@ -403,7 +403,7 @@ static int __finalise_sg(struct device *dev, struct scatterlist *sg, int nents,
                unsigned int s_length = sg_dma_len(s);
                unsigned int s_dma_len = s->length;
 
-               s->offset = s_offset;
+               s->offset += s_offset;
                s->length = s_length;
                sg_dma_address(s) = dma_addr + s_offset;
                dma_addr += s_dma_len;
@@ -422,7 +422,7 @@ static void __invalidate_sg(struct scatterlist *sg, int nents)
 
        for_each_sg(sg, s, nents, i) {
                if (sg_dma_address(s) != DMA_ERROR_CODE)
-                       s->offset = sg_dma_address(s);
+                       s->offset += sg_dma_address(s);
                if (sg_dma_len(s))
                        s->length = sg_dma_len(s);
                sg_dma_address(s) = DMA_ERROR_CODE;
index 0e3b0092ec92c9d4d1dcb06e713edcf99c4a9293..515bb8b8095230488f49f139c6a68c6e9381d857 100644 (file)
@@ -848,7 +848,8 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev)
        if (!group->default_domain) {
                group->default_domain = __iommu_domain_alloc(dev->bus,
                                                             IOMMU_DOMAIN_DMA);
-               group->domain = group->default_domain;
+               if (!group->domain)
+                       group->domain = group->default_domain;
        }
 
        ret = iommu_group_add_device(group, dev);
index efe50845939d91fee149acb085912697031dd9a0..17304705f2cf9443b99690565ece5b537e3e61c4 100644 (file)
@@ -183,7 +183,7 @@ static void __iomem * __init icoll_init_iobase(struct device_node *np)
        void __iomem *icoll_base;
 
        icoll_base = of_io_request_and_map(np, 0, np->name);
-       if (!icoll_base)
+       if (IS_ERR(icoll_base))
                panic("%s: unable to map resource", np->full_name);
        return icoll_base;
 }
index 4ef178078e5bd7ddf388e215eddc1bde3151b0fb..1254e98f6b577f4ac0347ff6ec262d7fd820dc80 100644 (file)
@@ -154,9 +154,9 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
 
        gc = irq_get_domain_generic_chip(domain, 0);
        gc->reg_base = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (!gc->reg_base) {
+       if (IS_ERR(gc->reg_base)) {
                pr_err("unable to map resource\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(gc->reg_base);
                goto fail_irqd_remove;
        }
 
index 7913fdcfc8496bdd7c719a8c3334f6136c74eced..d8b0ab6f3753c7ffc1e4655c1da26056f5746430 100644 (file)
@@ -458,6 +458,18 @@ config DM_VERITY
 
          If unsure, say N.
 
+config DM_VERITY_FEC
+       bool "Verity forward error correction support"
+       depends on DM_VERITY
+       select REED_SOLOMON
+       select REED_SOLOMON_DEC8
+       ---help---
+         Add forward error correction support to dm-verity. This option
+         makes it possible to use pre-generated error correction data to
+         recover from corrupted blocks.
+
+         If unsure, say N.
+
 config DM_SWITCH
        tristate "Switch target support (EXPERIMENTAL)"
        depends on BLK_DEV_DM
index f34979cd141aed02d867f11f3f03c9403d327005..62a65764e8e0f093cede342f0eb4b7d0aec2eb4e 100644 (file)
@@ -16,6 +16,7 @@ dm-cache-mq-y   += dm-cache-policy-mq.o
 dm-cache-smq-y   += dm-cache-policy-smq.o
 dm-cache-cleaner-y += dm-cache-policy-cleaner.o
 dm-era-y       += dm-era-target.o
+dm-verity-y    += dm-verity-target.o
 md-mod-y       += md.o bitmap.o
 raid456-y      += raid5.o raid5-cache.o
 
@@ -63,3 +64,7 @@ obj-$(CONFIG_DM_LOG_WRITES)   += dm-log-writes.o
 ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs                    += dm-uevent.o
 endif
+
+ifeq ($(CONFIG_DM_VERITY_FEC),y)
+dm-verity-objs                 += dm-verity-fec.o
+endif
index 8d0ead98eb6edc2c25eafad5f8b4ab0a49e91e2d..a296425a7270df87e1fc9cdd403668dd5bb82deb 100644 (file)
@@ -1015,8 +1015,12 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
         */
        atomic_set(&dc->count, 1);
 
-       if (bch_cached_dev_writeback_start(dc))
+       /* Block writeback thread, but spawn it */
+       down_write(&dc->writeback_lock);
+       if (bch_cached_dev_writeback_start(dc)) {
+               up_write(&dc->writeback_lock);
                return -ENOMEM;
+       }
 
        if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
                bch_sectors_dirty_init(dc);
@@ -1028,6 +1032,9 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
        bch_cached_dev_run(dc);
        bcache_device_link(&dc->disk, c, "bdev");
 
+       /* Allow the writeback thread to proceed */
+       up_write(&dc->writeback_lock);
+
        pr_info("Caching %s as %s on set %pU",
                bdevname(dc->bdev, buf), dc->disk.disk->disk_name,
                dc->disk.c->sb.set_uuid);
@@ -1366,6 +1373,9 @@ static void cache_set_flush(struct closure *cl)
        struct btree *b;
        unsigned i;
 
+       if (!c)
+               closure_return(cl);
+
        bch_cache_accounting_destroy(&c->accounting);
 
        kobject_put(&c->internal);
@@ -1828,11 +1838,12 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
        return 0;
 }
 
-static void register_cache(struct cache_sb *sb, struct page *sb_page,
+static int register_cache(struct cache_sb *sb, struct page *sb_page,
                                struct block_device *bdev, struct cache *ca)
 {
        char name[BDEVNAME_SIZE];
-       const char *err = "cannot allocate memory";
+       const char *err = NULL;
+       int ret = 0;
 
        memcpy(&ca->sb, sb, sizeof(struct cache_sb));
        ca->bdev = bdev;
@@ -1847,27 +1858,35 @@ static void register_cache(struct cache_sb *sb, struct page *sb_page,
        if (blk_queue_discard(bdev_get_queue(ca->bdev)))
                ca->discard = CACHE_DISCARD(&ca->sb);
 
-       if (cache_alloc(sb, ca) != 0)
+       ret = cache_alloc(sb, ca);
+       if (ret != 0)
                goto err;
 
-       err = "error creating kobject";
-       if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache"))
-               goto err;
+       if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) {
+               err = "error calling kobject_add";
+               ret = -ENOMEM;
+               goto out;
+       }
 
        mutex_lock(&bch_register_lock);
        err = register_cache_set(ca);
        mutex_unlock(&bch_register_lock);
 
-       if (err)
-               goto err;
+       if (err) {
+               ret = -ENODEV;
+               goto out;
+       }
 
        pr_info("registered cache device %s", bdevname(bdev, name));
+
 out:
        kobject_put(&ca->kobj);
-       return;
+
 err:
-       pr_notice("error opening %s: %s", bdevname(bdev, name), err);
-       goto out;
+       if (err)
+               pr_notice("error opening %s: %s", bdevname(bdev, name), err);
+
+       return ret;
 }
 
 /* Global interfaces/init */
@@ -1965,7 +1984,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
                if (!ca)
                        goto err_close;
 
-               register_cache(sb, sb_page, bdev, ca);
+               if (register_cache(sb, sb_page, bdev, ca) != 0)
+                       goto err_close;
        }
 out:
        if (sb_page)
index f6543f3a970f8daf44f3523e0209fd85a3c13f0b..3970cda10080988887bfa07329241d94afd1b883 100644 (file)
@@ -867,18 +867,55 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
        return 0;
 }
 
-#define WRITE_LOCK(cmd) \
-       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
-               return -EINVAL; \
-       down_write(&cmd->root_lock)
+static bool cmd_write_lock(struct dm_cache_metadata *cmd)
+{
+       down_write(&cmd->root_lock);
+       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) {
+               up_write(&cmd->root_lock);
+               return false;
+       }
+       return true;
+}
+
+#define WRITE_LOCK(cmd)                                \
+       do {                                    \
+               if (!cmd_write_lock((cmd)))     \
+                       return -EINVAL;         \
+       } while(0)
 
-#define WRITE_LOCK_VOID(cmd) \
-       if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
-               return; \
-       down_write(&cmd->root_lock)
+#define WRITE_LOCK_VOID(cmd)                   \
+       do {                                    \
+               if (!cmd_write_lock((cmd)))     \
+                       return;                 \
+       } while(0)
 
 #define WRITE_UNLOCK(cmd) \
-       up_write(&cmd->root_lock)
+       up_write(&(cmd)->root_lock)
+
+static bool cmd_read_lock(struct dm_cache_metadata *cmd)
+{
+       down_read(&cmd->root_lock);
+       if (cmd->fail_io) {
+               up_read(&cmd->root_lock);
+               return false;
+       }
+       return true;
+}
+
+#define READ_LOCK(cmd)                         \
+       do {                                    \
+               if (!cmd_read_lock((cmd)))      \
+                       return -EINVAL;         \
+       } while(0)
+
+#define READ_LOCK_VOID(cmd)                    \
+       do {                                    \
+               if (!cmd_read_lock((cmd)))      \
+                       return;                 \
+       } while(0)
+
+#define READ_UNLOCK(cmd) \
+       up_read(&(cmd)->root_lock)
 
 int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
 {
@@ -1015,22 +1052,20 @@ int dm_cache_load_discards(struct dm_cache_metadata *cmd,
 {
        int r;
 
-       down_read(&cmd->root_lock);
+       READ_LOCK(cmd);
        r = __load_discards(cmd, fn, context);
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 
        return r;
 }
 
-dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd)
+int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result)
 {
-       dm_cblock_t r;
-
-       down_read(&cmd->root_lock);
-       r = cmd->cache_blocks;
-       up_read(&cmd->root_lock);
+       READ_LOCK(cmd);
+       *result = cmd->cache_blocks;
+       READ_UNLOCK(cmd);
 
-       return r;
+       return 0;
 }
 
 static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock)
@@ -1188,9 +1223,9 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd,
 {
        int r;
 
-       down_read(&cmd->root_lock);
+       READ_LOCK(cmd);
        r = __load_mappings(cmd, policy, fn, context);
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 
        return r;
 }
@@ -1215,18 +1250,18 @@ static int __dump_mappings(struct dm_cache_metadata *cmd)
 
 void dm_cache_dump(struct dm_cache_metadata *cmd)
 {
-       down_read(&cmd->root_lock);
+       READ_LOCK_VOID(cmd);
        __dump_mappings(cmd);
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 }
 
 int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd)
 {
        int r;
 
-       down_read(&cmd->root_lock);
+       READ_LOCK(cmd);
        r = cmd->changed;
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 
        return r;
 }
@@ -1276,9 +1311,9 @@ int dm_cache_set_dirty(struct dm_cache_metadata *cmd,
 void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd,
                                 struct dm_cache_statistics *stats)
 {
-       down_read(&cmd->root_lock);
+       READ_LOCK_VOID(cmd);
        *stats = cmd->stats;
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 }
 
 void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
@@ -1312,9 +1347,9 @@ int dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd,
 {
        int r = -EINVAL;
 
-       down_read(&cmd->root_lock);
+       READ_LOCK(cmd);
        r = dm_sm_get_nr_free(cmd->metadata_sm, result);
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 
        return r;
 }
@@ -1324,9 +1359,9 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
 {
        int r = -EINVAL;
 
-       down_read(&cmd->root_lock);
+       READ_LOCK(cmd);
        r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
-       up_read(&cmd->root_lock);
+       READ_UNLOCK(cmd);
 
        return r;
 }
@@ -1417,7 +1452,13 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
 
 int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result)
 {
-       return blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
+       int r;
+
+       READ_LOCK(cmd);
+       r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
+       READ_UNLOCK(cmd);
+
+       return r;
 }
 
 void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd)
@@ -1440,10 +1481,7 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
        struct dm_block *sblock;
        struct cache_disk_superblock *disk_super;
 
-       /*
-        * We ignore fail_io for this function.
-        */
-       down_write(&cmd->root_lock);
+       WRITE_LOCK(cmd);
        set_bit(NEEDS_CHECK, &cmd->flags);
 
        r = superblock_lock(cmd, &sblock);
@@ -1458,19 +1496,17 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
        dm_bm_unlock(sblock);
 
 out:
-       up_write(&cmd->root_lock);
+       WRITE_UNLOCK(cmd);
        return r;
 }
 
-bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd)
+int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result)
 {
-       bool needs_check;
+       READ_LOCK(cmd);
+       *result = !!test_bit(NEEDS_CHECK, &cmd->flags);
+       READ_UNLOCK(cmd);
 
-       down_read(&cmd->root_lock);
-       needs_check = !!test_bit(NEEDS_CHECK, &cmd->flags);
-       up_read(&cmd->root_lock);
-
-       return needs_check;
+       return 0;
 }
 
 int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
index 2ffee21f318dfef70c967570b9677da0193d6e12..8528744195e53aeecbbe52688b8ae40d2200c339 100644 (file)
@@ -66,7 +66,7 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd);
  * origin blocks to map to.
  */
 int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size);
-dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd);
+int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result);
 
 int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
                                   sector_t discard_block_size,
@@ -137,7 +137,7 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
  */
 int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result);
 
-bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd);
+int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result);
 int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd);
 void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd);
 void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd);
index 2fd4c82961441e08b2b20d8db98bfb2bad86e05e..bb9b92ebbf8e5b850e8c3d0243053e9fdb7e1ad2 100644 (file)
@@ -118,14 +118,12 @@ static void iot_io_end(struct io_tracker *iot, sector_t len)
  */
 struct dm_hook_info {
        bio_end_io_t *bi_end_io;
-       void *bi_private;
 };
 
 static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
                        bio_end_io_t *bi_end_io, void *bi_private)
 {
        h->bi_end_io = bio->bi_end_io;
-       h->bi_private = bio->bi_private;
 
        bio->bi_end_io = bi_end_io;
        bio->bi_private = bi_private;
@@ -134,7 +132,6 @@ static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
 static void dm_unhook_bio(struct dm_hook_info *h, struct bio *bio)
 {
        bio->bi_end_io = h->bi_end_io;
-       bio->bi_private = h->bi_private;
 }
 
 /*----------------------------------------------------------------*/
@@ -987,9 +984,14 @@ static void notify_mode_switch(struct cache *cache, enum cache_metadata_mode mod
 
 static void set_cache_mode(struct cache *cache, enum cache_metadata_mode new_mode)
 {
-       bool needs_check = dm_cache_metadata_needs_check(cache->cmd);
+       bool needs_check;
        enum cache_metadata_mode old_mode = get_cache_mode(cache);
 
+       if (dm_cache_metadata_needs_check(cache->cmd, &needs_check)) {
+               DMERR("unable to read needs_check flag, setting failure mode");
+               new_mode = CM_FAIL;
+       }
+
        if (new_mode == CM_WRITE && needs_check) {
                DMERR("%s: unable to switch cache to write mode until repaired.",
                      cache_device_name(cache));
@@ -3513,6 +3515,7 @@ static void cache_status(struct dm_target *ti, status_type_t type,
        char buf[BDEVNAME_SIZE];
        struct cache *cache = ti->private;
        dm_cblock_t residency;
+       bool needs_check;
 
        switch (type) {
        case STATUSTYPE_INFO:
@@ -3586,7 +3589,9 @@ static void cache_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("rw ");
 
-               if (dm_cache_metadata_needs_check(cache->cmd))
+               r = dm_cache_metadata_needs_check(cache->cmd, &needs_check);
+
+               if (r || needs_check)
                        DMEMIT("needs_check ");
                else
                        DMEMIT("- ");
index 61f184ad081c2f0820e22740fcf0b615b813e547..e4d1bafe78c1ab63e411eedd26c3c81d17713e66 100644 (file)
@@ -207,7 +207,6 @@ struct dm_snap_pending_exception {
         */
        struct bio *full_bio;
        bio_end_io_t *full_bio_end_io;
-       void *full_bio_private;
 };
 
 /*
@@ -1106,6 +1105,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        int i;
        int r = -EINVAL;
        char *origin_path, *cow_path;
+       dev_t origin_dev, cow_dev;
        unsigned args_used, num_flush_bios = 1;
        fmode_t origin_mode = FMODE_READ;
 
@@ -1136,11 +1136,19 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                ti->error = "Cannot get origin device";
                goto bad_origin;
        }
+       origin_dev = s->origin->bdev->bd_dev;
 
        cow_path = argv[0];
        argv++;
        argc--;
 
+       cow_dev = dm_get_dev_t(cow_path);
+       if (cow_dev && cow_dev == origin_dev) {
+               ti->error = "COW device cannot be the same as origin device";
+               r = -EINVAL;
+               goto bad_cow;
+       }
+
        r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow);
        if (r) {
                ti->error = "Cannot get COW device";
@@ -1486,10 +1494,8 @@ out:
        snapshot_bios = bio_list_get(&pe->snapshot_bios);
        origin_bios = bio_list_get(&pe->origin_bios);
        full_bio = pe->full_bio;
-       if (full_bio) {
+       if (full_bio)
                full_bio->bi_end_io = pe->full_bio_end_io;
-               full_bio->bi_private = pe->full_bio_private;
-       }
        increment_pending_exceptions_done_count();
 
        up_write(&s->lock);
@@ -1595,7 +1601,6 @@ static void start_full_bio(struct dm_snap_pending_exception *pe,
 
        pe->full_bio = bio;
        pe->full_bio_end_io = bio->bi_end_io;
-       pe->full_bio_private = bio->bi_private;
 
        callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
                                                   copy_callback, pe);
index 061152a437300bbfacfbbc6e475c3935df7cecb6..cb5d0daf53bb65ba0c47c330ce533590840adb46 100644 (file)
@@ -364,6 +364,26 @@ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
        return 0;
 }
 
+/*
+ * Convert the path to a device
+ */
+dev_t dm_get_dev_t(const char *path)
+{
+       dev_t uninitialized_var(dev);
+       struct block_device *bdev;
+
+       bdev = lookup_bdev(path);
+       if (IS_ERR(bdev))
+               dev = name_to_dev_t(path);
+       else {
+               dev = bdev->bd_dev;
+               bdput(bdev);
+       }
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(dm_get_dev_t);
+
 /*
  * Add a device to the list, or just increment the usage count if
  * it's already present.
@@ -372,23 +392,15 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
                  struct dm_dev **result)
 {
        int r;
-       dev_t uninitialized_var(dev);
+       dev_t dev;
        struct dm_dev_internal *dd;
        struct dm_table *t = ti->table;
-       struct block_device *bdev;
 
        BUG_ON(!t);
 
-       /* convert the path to a device */
-       bdev = lookup_bdev(path);
-       if (IS_ERR(bdev)) {
-               dev = name_to_dev_t(path);
-               if (!dev)
-                       return -ENODEV;
-       } else {
-               dev = bdev->bd_dev;
-               bdput(bdev);
-       }
+       dev = dm_get_dev_t(path);
+       if (!dev)
+               return -ENODEV;
 
        dd = find_device(&t->devices, dev);
        if (!dd) {
index c219a053c7f66d1ebae80a19b005af38914dbe8c..911ada64336407fe15f8b5d6fc2df026cf1649cc 100644 (file)
@@ -1943,5 +1943,8 @@ bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
 
 void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd)
 {
-       dm_tm_issue_prefetches(pmd->tm);
+       down_read(&pmd->root_lock);
+       if (!pmd->fail_io)
+               dm_tm_issue_prefetches(pmd->tm);
+       up_read(&pmd->root_lock);
 }
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
new file mode 100644 (file)
index 0000000..ad10d6d
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Sami Tolvanen <samitolvanen@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include "dm-verity-fec.h"
+#include <linux/math64.h>
+#include <linux/sysfs.h>
+
+#define DM_MSG_PREFIX  "verity-fec"
+
+/*
+ * If error correction has been configured, returns true.
+ */
+bool verity_fec_is_enabled(struct dm_verity *v)
+{
+       return v->fec && v->fec->dev;
+}
+
+/*
+ * Return a pointer to dm_verity_fec_io after dm_verity_io and its variable
+ * length fields.
+ */
+static inline struct dm_verity_fec_io *fec_io(struct dm_verity_io *io)
+{
+       return (struct dm_verity_fec_io *) verity_io_digest_end(io->v, io);
+}
+
+/*
+ * Return an interleaved offset for a byte in RS block.
+ */
+static inline u64 fec_interleave(struct dm_verity *v, u64 offset)
+{
+       u32 mod;
+
+       mod = do_div(offset, v->fec->rsn);
+       return offset + mod * (v->fec->rounds << v->data_dev_block_bits);
+}
+
+/*
+ * Decode an RS block using Reed-Solomon.
+ */
+static int fec_decode_rs8(struct dm_verity *v, struct dm_verity_fec_io *fio,
+                         u8 *data, u8 *fec, int neras)
+{
+       int i;
+       uint16_t par[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+
+       for (i = 0; i < v->fec->roots; i++)
+               par[i] = fec[i];
+
+       return decode_rs8(fio->rs, data, par, v->fec->rsn, NULL, neras,
+                         fio->erasures, 0, NULL);
+}
+
+/*
+ * Read error-correcting codes for the requested RS block. Returns a pointer
+ * to the data block. Caller is responsible for releasing buf.
+ */
+static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+                          unsigned *offset, struct dm_buffer **buf)
+{
+       u64 position, block;
+       u8 *res;
+
+       position = (index + rsb) * v->fec->roots;
+       block = position >> v->data_dev_block_bits;
+       *offset = (unsigned)(position - (block << v->data_dev_block_bits));
+
+       res = dm_bufio_read(v->fec->bufio, v->fec->start + block, buf);
+       if (unlikely(IS_ERR(res))) {
+               DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+                     v->data_dev->name, (unsigned long long)rsb,
+                     (unsigned long long)(v->fec->start + block),
+                     PTR_ERR(res));
+               *buf = NULL;
+       }
+
+       return res;
+}
+
+/* Loop over each preallocated buffer slot. */
+#define fec_for_each_prealloc_buffer(__i) \
+       for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++)
+
+/* Loop over each extra buffer slot. */
+#define fec_for_each_extra_buffer(io, __i) \
+       for (__i = DM_VERITY_FEC_BUF_PREALLOC; __i < DM_VERITY_FEC_BUF_MAX; __i++)
+
+/* Loop over each allocated buffer. */
+#define fec_for_each_buffer(io, __i) \
+       for (__i = 0; __i < (io)->nbufs; __i++)
+
+/* Loop over each RS block in each allocated buffer. */
+#define fec_for_each_buffer_rs_block(io, __i, __j) \
+       fec_for_each_buffer(io, __i) \
+               for (__j = 0; __j < 1 << DM_VERITY_FEC_BUF_RS_BITS; __j++)
+
+/*
+ * Return a pointer to the current RS block when called inside
+ * fec_for_each_buffer_rs_block.
+ */
+static inline u8 *fec_buffer_rs_block(struct dm_verity *v,
+                                     struct dm_verity_fec_io *fio,
+                                     unsigned i, unsigned j)
+{
+       return &fio->bufs[i][j * v->fec->rsn];
+}
+
+/*
+ * Return an index to the current RS block when called inside
+ * fec_for_each_buffer_rs_block.
+ */
+static inline unsigned fec_buffer_rs_index(unsigned i, unsigned j)
+{
+       return (i << DM_VERITY_FEC_BUF_RS_BITS) + j;
+}
+
+/*
+ * Decode all RS blocks from buffers and copy corrected bytes into fio->output
+ * starting from block_offset.
+ */
+static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio,
+                          u64 rsb, int byte_index, unsigned block_offset,
+                          int neras)
+{
+       int r, corrected = 0, res;
+       struct dm_buffer *buf;
+       unsigned n, i, offset;
+       u8 *par, *block;
+
+       par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+       if (IS_ERR(par))
+               return PTR_ERR(par);
+
+       /*
+        * Decode the RS blocks we have in bufs. Each RS block results in
+        * one corrected target byte and consumes fec->roots parity bytes.
+        */
+       fec_for_each_buffer_rs_block(fio, n, i) {
+               block = fec_buffer_rs_block(v, fio, n, i);
+               res = fec_decode_rs8(v, fio, block, &par[offset], neras);
+               if (res < 0) {
+                       dm_bufio_release(buf);
+
+                       r = res;
+                       goto error;
+               }
+
+               corrected += res;
+               fio->output[block_offset] = block[byte_index];
+
+               block_offset++;
+               if (block_offset >= 1 << v->data_dev_block_bits)
+                       goto done;
+
+               /* read the next block when we run out of parity bytes */
+               offset += v->fec->roots;
+               if (offset >= 1 << v->data_dev_block_bits) {
+                       dm_bufio_release(buf);
+
+                       par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+                       if (unlikely(IS_ERR(par)))
+                               return PTR_ERR(par);
+               }
+       }
+done:
+       r = corrected;
+error:
+       if (r < 0 && neras)
+               DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
+                           v->data_dev->name, (unsigned long long)rsb, r);
+       else if (r > 0) {
+               DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
+                            v->data_dev->name, (unsigned long long)rsb, r);
+               atomic_add_unless(&v->fec->corrected, 1, INT_MAX);
+       }
+
+       return r;
+}
+
+/*
+ * Locate data block erasures using verity hashes.
+ */
+static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
+                         u8 *want_digest, u8 *data)
+{
+       if (unlikely(verity_hash(v, verity_io_hash_desc(v, io),
+                                data, 1 << v->data_dev_block_bits,
+                                verity_io_real_digest(v, io))))
+               return 0;
+
+       return memcmp(verity_io_real_digest(v, io), want_digest,
+                     v->digest_size) != 0;
+}
+
+/*
+ * Read data blocks that are part of the RS block and deinterleave as much as
+ * fits into buffers. Check for erasure locations if @neras is non-NULL.
+ */
+static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
+                        u64 rsb, u64 target, unsigned block_offset,
+                        int *neras)
+{
+       bool is_zero;
+       int i, j, target_index = -1;
+       struct dm_buffer *buf;
+       struct dm_bufio_client *bufio;
+       struct dm_verity_fec_io *fio = fec_io(io);
+       u64 block, ileaved;
+       u8 *bbuf, *rs_block;
+       u8 want_digest[v->digest_size];
+       unsigned n, k;
+
+       if (neras)
+               *neras = 0;
+
+       /*
+        * read each of the rsn data blocks that are part of the RS block, and
+        * interleave contents to available bufs
+        */
+       for (i = 0; i < v->fec->rsn; i++) {
+               ileaved = fec_interleave(v, rsb * v->fec->rsn + i);
+
+               /*
+                * target is the data block we want to correct, target_index is
+                * the index of this block within the rsn RS blocks
+                */
+               if (ileaved == target)
+                       target_index = i;
+
+               block = ileaved >> v->data_dev_block_bits;
+               bufio = v->fec->data_bufio;
+
+               if (block >= v->data_blocks) {
+                       block -= v->data_blocks;
+
+                       /*
+                        * blocks outside the area were assumed to contain
+                        * zeros when encoding data was generated
+                        */
+                       if (unlikely(block >= v->fec->hash_blocks))
+                               continue;
+
+                       block += v->hash_start;
+                       bufio = v->bufio;
+               }
+
+               bbuf = dm_bufio_read(bufio, block, &buf);
+               if (unlikely(IS_ERR(bbuf))) {
+                       DMWARN_LIMIT("%s: FEC %llu: read failed (%llu): %ld",
+                                    v->data_dev->name,
+                                    (unsigned long long)rsb,
+                                    (unsigned long long)block, PTR_ERR(bbuf));
+
+                       /* assume the block is corrupted */
+                       if (neras && *neras <= v->fec->roots)
+                               fio->erasures[(*neras)++] = i;
+
+                       continue;
+               }
+
+               /* locate erasures if the block is on the data device */
+               if (bufio == v->fec->data_bufio &&
+                   verity_hash_for_block(v, io, block, want_digest,
+                                         &is_zero) == 0) {
+                       /* skip known zero blocks entirely */
+                       if (is_zero)
+                               continue;
+
+                       /*
+                        * skip if we have already found the theoretical
+                        * maximum number (i.e. fec->roots) of erasures
+                        */
+                       if (neras && *neras <= v->fec->roots &&
+                           fec_is_erasure(v, io, want_digest, bbuf))
+                               fio->erasures[(*neras)++] = i;
+               }
+
+               /*
+                * deinterleave and copy the bytes that fit into bufs,
+                * starting from block_offset
+                */
+               fec_for_each_buffer_rs_block(fio, n, j) {
+                       k = fec_buffer_rs_index(n, j) + block_offset;
+
+                       if (k >= 1 << v->data_dev_block_bits)
+                               goto done;
+
+                       rs_block = fec_buffer_rs_block(v, fio, n, j);
+                       rs_block[i] = bbuf[k];
+               }
+done:
+               dm_bufio_release(buf);
+       }
+
+       return target_index;
+}
+
+/*
+ * Allocate RS control structure and FEC buffers from preallocated mempools,
+ * and attempt to allocate as many extra buffers as available.
+ */
+static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
+{
+       unsigned n;
+
+       if (!fio->rs) {
+               fio->rs = mempool_alloc(v->fec->rs_pool, 0);
+               if (unlikely(!fio->rs)) {
+                       DMERR("failed to allocate RS");
+                       return -ENOMEM;
+               }
+       }
+
+       fec_for_each_prealloc_buffer(n) {
+               if (fio->bufs[n])
+                       continue;
+
+               fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOIO);
+               if (unlikely(!fio->bufs[n])) {
+                       DMERR("failed to allocate FEC buffer");
+                       return -ENOMEM;
+               }
+       }
+
+       /* try to allocate the maximum number of buffers */
+       fec_for_each_extra_buffer(fio, n) {
+               if (fio->bufs[n])
+                       continue;
+
+               fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOIO);
+               /* we can manage with even one buffer if necessary */
+               if (unlikely(!fio->bufs[n]))
+                       break;
+       }
+       fio->nbufs = n;
+
+       if (!fio->output) {
+               fio->output = mempool_alloc(v->fec->output_pool, GFP_NOIO);
+
+               if (!fio->output) {
+                       DMERR("failed to allocate FEC page");
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize buffers and clear erasures. fec_read_bufs() assumes buffers are
+ * zeroed before deinterleaving.
+ */
+static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
+{
+       unsigned n;
+
+       fec_for_each_buffer(fio, n)
+               memset(fio->bufs[n], 0, v->fec->rsn << DM_VERITY_FEC_BUF_RS_BITS);
+
+       memset(fio->erasures, 0, sizeof(fio->erasures));
+}
+
+/*
+ * Decode all RS blocks in a single data block and return the target block
+ * (indicated by @offset) in fio->output. If @use_erasures is non-zero, uses
+ * hashes to locate erasures.
+ */
+static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
+                         struct dm_verity_fec_io *fio, u64 rsb, u64 offset,
+                         bool use_erasures)
+{
+       int r, neras = 0;
+       unsigned pos;
+
+       r = fec_alloc_bufs(v, fio);
+       if (unlikely(r < 0))
+               return r;
+
+       for (pos = 0; pos < 1 << v->data_dev_block_bits; ) {
+               fec_init_bufs(v, fio);
+
+               r = fec_read_bufs(v, io, rsb, offset, pos,
+                                 use_erasures ? &neras : NULL);
+               if (unlikely(r < 0))
+                       return r;
+
+               r = fec_decode_bufs(v, fio, rsb, r, pos, neras);
+               if (r < 0)
+                       return r;
+
+               pos += fio->nbufs << DM_VERITY_FEC_BUF_RS_BITS;
+       }
+
+       /* Always re-validate the corrected block against the expected hash */
+       r = verity_hash(v, verity_io_hash_desc(v, io), fio->output,
+                       1 << v->data_dev_block_bits,
+                       verity_io_real_digest(v, io));
+       if (unlikely(r < 0))
+               return r;
+
+       if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io),
+                  v->digest_size)) {
+               DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)",
+                           v->data_dev->name, (unsigned long long)rsb, neras);
+               return -EILSEQ;
+       }
+
+       return 0;
+}
+
+static int fec_bv_copy(struct dm_verity *v, struct dm_verity_io *io, u8 *data,
+                      size_t len)
+{
+       struct dm_verity_fec_io *fio = fec_io(io);
+
+       memcpy(data, &fio->output[fio->output_pos], len);
+       fio->output_pos += len;
+
+       return 0;
+}
+
+/*
+ * Correct errors in a block. Copies corrected block to dest if non-NULL,
+ * otherwise to a bio_vec starting from iter.
+ */
+int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
+                     enum verity_block_type type, sector_t block, u8 *dest,
+                     struct bvec_iter *iter)
+{
+       int r;
+       struct dm_verity_fec_io *fio = fec_io(io);
+       u64 offset, res, rsb;
+
+       if (!verity_fec_is_enabled(v))
+               return -EOPNOTSUPP;
+
+       if (type == DM_VERITY_BLOCK_TYPE_METADATA)
+               block += v->data_blocks;
+
+       /*
+        * For RS(M, N), the continuous FEC data is divided into blocks of N
+        * bytes. Since block size may not be divisible by N, the last block
+        * is zero padded when decoding.
+        *
+        * Each byte of the block is covered by a different RS(M, N) code,
+        * and each code is interleaved over N blocks to make it less likely
+        * that bursty corruption will leave us in unrecoverable state.
+        */
+
+       offset = block << v->data_dev_block_bits;
+
+       res = offset;
+       div64_u64(res, v->fec->rounds << v->data_dev_block_bits);
+
+       /*
+        * The base RS block we can feed to the interleaver to find out all
+        * blocks required for decoding.
+        */
+       rsb = offset - res * (v->fec->rounds << v->data_dev_block_bits);
+
+       /*
+        * Locating erasures is slow, so attempt to recover the block without
+        * them first. Do a second attempt with erasures if the corruption is
+        * bad enough.
+        */
+       r = fec_decode_rsb(v, io, fio, rsb, offset, false);
+       if (r < 0) {
+               r = fec_decode_rsb(v, io, fio, rsb, offset, true);
+               if (r < 0)
+                       return r;
+       }
+
+       if (dest)
+               memcpy(dest, fio->output, 1 << v->data_dev_block_bits);
+       else if (iter) {
+               fio->output_pos = 0;
+               r = verity_for_bv_block(v, io, iter, fec_bv_copy);
+       }
+
+       return r;
+}
+
+/*
+ * Clean up per-bio data.
+ */
+void verity_fec_finish_io(struct dm_verity_io *io)
+{
+       unsigned n;
+       struct dm_verity_fec *f = io->v->fec;
+       struct dm_verity_fec_io *fio = fec_io(io);
+
+       if (!verity_fec_is_enabled(io->v))
+               return;
+
+       mempool_free(fio->rs, f->rs_pool);
+
+       fec_for_each_prealloc_buffer(n)
+               mempool_free(fio->bufs[n], f->prealloc_pool);
+
+       fec_for_each_extra_buffer(fio, n)
+               mempool_free(fio->bufs[n], f->extra_pool);
+
+       mempool_free(fio->output, f->output_pool);
+}
+
+/*
+ * Initialize per-bio data.
+ */
+void verity_fec_init_io(struct dm_verity_io *io)
+{
+       struct dm_verity_fec_io *fio = fec_io(io);
+
+       if (!verity_fec_is_enabled(io->v))
+               return;
+
+       fio->rs = NULL;
+       memset(fio->bufs, 0, sizeof(fio->bufs));
+       fio->nbufs = 0;
+       fio->output = NULL;
+}
+
+/*
+ * Append feature arguments and values to the status table.
+ */
+unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
+                                char *result, unsigned maxlen)
+{
+       if (!verity_fec_is_enabled(v))
+               return sz;
+
+       DMEMIT(" " DM_VERITY_OPT_FEC_DEV " %s "
+              DM_VERITY_OPT_FEC_BLOCKS " %llu "
+              DM_VERITY_OPT_FEC_START " %llu "
+              DM_VERITY_OPT_FEC_ROOTS " %d",
+              v->fec->dev->name,
+              (unsigned long long)v->fec->blocks,
+              (unsigned long long)v->fec->start,
+              v->fec->roots);
+
+       return sz;
+}
+
+void verity_fec_dtr(struct dm_verity *v)
+{
+       struct dm_verity_fec *f = v->fec;
+       struct kobject *kobj = &f->kobj_holder.kobj;
+
+       if (!verity_fec_is_enabled(v))
+               goto out;
+
+       mempool_destroy(f->rs_pool);
+       mempool_destroy(f->prealloc_pool);
+       mempool_destroy(f->extra_pool);
+       kmem_cache_destroy(f->cache);
+
+       if (f->data_bufio)
+               dm_bufio_client_destroy(f->data_bufio);
+       if (f->bufio)
+               dm_bufio_client_destroy(f->bufio);
+
+       if (f->dev)
+               dm_put_device(v->ti, f->dev);
+
+       if (kobj->state_initialized) {
+               kobject_put(kobj);
+               wait_for_completion(dm_get_completion_from_kobject(kobj));
+       }
+
+out:
+       kfree(f);
+       v->fec = NULL;
+}
+
+static void *fec_rs_alloc(gfp_t gfp_mask, void *pool_data)
+{
+       struct dm_verity *v = (struct dm_verity *)pool_data;
+
+       return init_rs(8, 0x11d, 0, 1, v->fec->roots);
+}
+
+static void fec_rs_free(void *element, void *pool_data)
+{
+       struct rs_control *rs = (struct rs_control *)element;
+
+       if (rs)
+               free_rs(rs);
+}
+
+bool verity_is_fec_opt_arg(const char *arg_name)
+{
+       return (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV) ||
+               !strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS) ||
+               !strcasecmp(arg_name, DM_VERITY_OPT_FEC_START) ||
+               !strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS));
+}
+
+int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+                             unsigned *argc, const char *arg_name)
+{
+       int r;
+       struct dm_target *ti = v->ti;
+       const char *arg_value;
+       unsigned long long num_ll;
+       unsigned char num_c;
+       char dummy;
+
+       if (!*argc) {
+               ti->error = "FEC feature arguments require a value";
+               return -EINVAL;
+       }
+
+       arg_value = dm_shift_arg(as);
+       (*argc)--;
+
+       if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) {
+               r = dm_get_device(ti, arg_value, FMODE_READ, &v->fec->dev);
+               if (r) {
+                       ti->error = "FEC device lookup failed";
+                       return r;
+               }
+
+       } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS)) {
+               if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 ||
+                   ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+                    >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) {
+                       ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS;
+                       return -EINVAL;
+               }
+               v->fec->blocks = num_ll;
+
+       } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_START)) {
+               if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 ||
+                   ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) >>
+                    (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) {
+                       ti->error = "Invalid " DM_VERITY_OPT_FEC_START;
+                       return -EINVAL;
+               }
+               v->fec->start = num_ll;
+
+       } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)) {
+               if (sscanf(arg_value, "%hhu%c", &num_c, &dummy) != 1 || !num_c ||
+                   num_c < (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MAX_RSN) ||
+                   num_c > (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN)) {
+                       ti->error = "Invalid " DM_VERITY_OPT_FEC_ROOTS;
+                       return -EINVAL;
+               }
+               v->fec->roots = num_c;
+
+       } else {
+               ti->error = "Unrecognized verity FEC feature request";
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static ssize_t corrected_show(struct kobject *kobj, struct kobj_attribute *attr,
+                             char *buf)
+{
+       struct dm_verity_fec *f = container_of(kobj, struct dm_verity_fec,
+                                              kobj_holder.kobj);
+
+       return sprintf(buf, "%d\n", atomic_read(&f->corrected));
+}
+
+static struct kobj_attribute attr_corrected = __ATTR_RO(corrected);
+
+static struct attribute *fec_attrs[] = {
+       &attr_corrected.attr,
+       NULL
+};
+
+static struct kobj_type fec_ktype = {
+       .sysfs_ops = &kobj_sysfs_ops,
+       .default_attrs = fec_attrs
+};
+
+/*
+ * Allocate dm_verity_fec for v->fec. Must be called before verity_fec_ctr.
+ */
+int verity_fec_ctr_alloc(struct dm_verity *v)
+{
+       struct dm_verity_fec *f;
+
+       f = kzalloc(sizeof(struct dm_verity_fec), GFP_KERNEL);
+       if (!f) {
+               v->ti->error = "Cannot allocate FEC structure";
+               return -ENOMEM;
+       }
+       v->fec = f;
+
+       return 0;
+}
+
+/*
+ * Validate arguments and preallocate memory. Must be called after arguments
+ * have been parsed using verity_fec_parse_opt_args.
+ */
+int verity_fec_ctr(struct dm_verity *v)
+{
+       int r;
+       struct dm_verity_fec *f = v->fec;
+       struct dm_target *ti = v->ti;
+       struct mapped_device *md = dm_table_get_md(ti->table);
+       u64 hash_blocks;
+
+       if (!verity_fec_is_enabled(v)) {
+               verity_fec_dtr(v);
+               return 0;
+       }
+
+       /* Create a kobject and sysfs attributes */
+       init_completion(&f->kobj_holder.completion);
+
+       r = kobject_init_and_add(&f->kobj_holder.kobj, &fec_ktype,
+                                &disk_to_dev(dm_disk(md))->kobj, "%s", "fec");
+       if (r) {
+               ti->error = "Cannot create kobject";
+               return r;
+       }
+
+       /*
+        * FEC is computed over data blocks, possible metadata, and
+        * hash blocks. In other words, FEC covers total of fec_blocks
+        * blocks consisting of the following:
+        *
+        *  data blocks | hash blocks | metadata (optional)
+        *
+        * We allow metadata after hash blocks to support a use case
+        * where all data is stored on the same device and FEC covers
+        * the entire area.
+        *
+        * If metadata is included, we require it to be available on the
+        * hash device after the hash blocks.
+        */
+
+       hash_blocks = v->hash_blocks - v->hash_start;
+
+       /*
+        * Require matching block sizes for data and hash devices for
+        * simplicity.
+        */
+       if (v->data_dev_block_bits != v->hash_dev_block_bits) {
+               ti->error = "Block sizes must match to use FEC";
+               return -EINVAL;
+       }
+
+       if (!f->roots) {
+               ti->error = "Missing " DM_VERITY_OPT_FEC_ROOTS;
+               return -EINVAL;
+       }
+       f->rsn = DM_VERITY_FEC_RSM - f->roots;
+
+       if (!f->blocks) {
+               ti->error = "Missing " DM_VERITY_OPT_FEC_BLOCKS;
+               return -EINVAL;
+       }
+
+       f->rounds = f->blocks;
+       if (sector_div(f->rounds, f->rsn))
+               f->rounds++;
+
+       /*
+        * Due to optional metadata, f->blocks can be larger than
+        * data_blocks and hash_blocks combined.
+        */
+       if (f->blocks < v->data_blocks + hash_blocks || !f->rounds) {
+               ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS;
+               return -EINVAL;
+       }
+
+       /*
+        * Metadata is accessed through the hash device, so we require
+        * it to be large enough.
+        */
+       f->hash_blocks = f->blocks - v->data_blocks;
+       if (dm_bufio_get_device_size(v->bufio) < f->hash_blocks) {
+               ti->error = "Hash device is too small for "
+                       DM_VERITY_OPT_FEC_BLOCKS;
+               return -E2BIG;
+       }
+
+       f->bufio = dm_bufio_client_create(f->dev->bdev,
+                                         1 << v->data_dev_block_bits,
+                                         1, 0, NULL, NULL);
+       if (IS_ERR(f->bufio)) {
+               ti->error = "Cannot initialize FEC bufio client";
+               return PTR_ERR(f->bufio);
+       }
+
+       if (dm_bufio_get_device_size(f->bufio) <
+           ((f->start + f->rounds * f->roots) >> v->data_dev_block_bits)) {
+               ti->error = "FEC device is too small";
+               return -E2BIG;
+       }
+
+       f->data_bufio = dm_bufio_client_create(v->data_dev->bdev,
+                                              1 << v->data_dev_block_bits,
+                                              1, 0, NULL, NULL);
+       if (IS_ERR(f->data_bufio)) {
+               ti->error = "Cannot initialize FEC data bufio client";
+               return PTR_ERR(f->data_bufio);
+       }
+
+       if (dm_bufio_get_device_size(f->data_bufio) < v->data_blocks) {
+               ti->error = "Data device is too small";
+               return -E2BIG;
+       }
+
+       /* Preallocate an rs_control structure for each worker thread */
+       f->rs_pool = mempool_create(num_online_cpus(), fec_rs_alloc,
+                                   fec_rs_free, (void *) v);
+       if (!f->rs_pool) {
+               ti->error = "Cannot allocate RS pool";
+               return -ENOMEM;
+       }
+
+       f->cache = kmem_cache_create("dm_verity_fec_buffers",
+                                    f->rsn << DM_VERITY_FEC_BUF_RS_BITS,
+                                    0, 0, NULL);
+       if (!f->cache) {
+               ti->error = "Cannot create FEC buffer cache";
+               return -ENOMEM;
+       }
+
+       /* Preallocate DM_VERITY_FEC_BUF_PREALLOC buffers for each thread */
+       f->prealloc_pool = mempool_create_slab_pool(num_online_cpus() *
+                                                   DM_VERITY_FEC_BUF_PREALLOC,
+                                                   f->cache);
+       if (!f->prealloc_pool) {
+               ti->error = "Cannot allocate FEC buffer prealloc pool";
+               return -ENOMEM;
+       }
+
+       f->extra_pool = mempool_create_slab_pool(0, f->cache);
+       if (!f->extra_pool) {
+               ti->error = "Cannot allocate FEC buffer extra pool";
+               return -ENOMEM;
+       }
+
+       /* Preallocate an output buffer for each thread */
+       f->output_pool = mempool_create_kmalloc_pool(num_online_cpus(),
+                                                    1 << v->data_dev_block_bits);
+       if (!f->output_pool) {
+               ti->error = "Cannot allocate FEC output pool";
+               return -ENOMEM;
+       }
+
+       /* Reserve space for our per-bio data */
+       ti->per_bio_data_size += sizeof(struct dm_verity_fec_io);
+
+       return 0;
+}
diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
new file mode 100644 (file)
index 0000000..8c4bee0
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Sami Tolvanen <samitolvanen@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef DM_VERITY_FEC_H
+#define DM_VERITY_FEC_H
+
+#include "dm.h"
+#include "dm-verity.h"
+#include <linux/rslib.h>
+
+/* Reed-Solomon(M, N) parameters */
+#define DM_VERITY_FEC_RSM              255
+#define DM_VERITY_FEC_MAX_RSN          253
+#define DM_VERITY_FEC_MIN_RSN          231     /* ~10% space overhead */
+
+/* buffers for deinterleaving and decoding */
+#define DM_VERITY_FEC_BUF_PREALLOC     1       /* buffers to preallocate */
+#define DM_VERITY_FEC_BUF_RS_BITS      4       /* 1 << RS blocks per buffer */
+/* we need buffers for at most 1 << block size RS blocks */
+#define DM_VERITY_FEC_BUF_MAX \
+       (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS))
+
+#define DM_VERITY_OPT_FEC_DEV          "use_fec_from_device"
+#define DM_VERITY_OPT_FEC_BLOCKS       "fec_blocks"
+#define DM_VERITY_OPT_FEC_START                "fec_start"
+#define DM_VERITY_OPT_FEC_ROOTS                "fec_roots"
+
+/* configuration */
+struct dm_verity_fec {
+       struct dm_dev *dev;     /* parity data device */
+       struct dm_bufio_client *data_bufio;     /* for data dev access */
+       struct dm_bufio_client *bufio;          /* for parity data access */
+       sector_t start;         /* parity data start in blocks */
+       sector_t blocks;        /* number of blocks covered */
+       sector_t rounds;        /* number of interleaving rounds */
+       sector_t hash_blocks;   /* blocks covered after v->hash_start */
+       unsigned char roots;    /* number of parity bytes, M-N of RS(M, N) */
+       unsigned char rsn;      /* N of RS(M, N) */
+       mempool_t *rs_pool;     /* mempool for fio->rs */
+       mempool_t *prealloc_pool;       /* mempool for preallocated buffers */
+       mempool_t *extra_pool;  /* mempool for extra buffers */
+       mempool_t *output_pool; /* mempool for output */
+       struct kmem_cache *cache;       /* cache for buffers */
+       atomic_t corrected;             /* corrected errors */
+       struct dm_kobject_holder kobj_holder;   /* for sysfs attributes */
+};
+
+/* per-bio data */
+struct dm_verity_fec_io {
+       struct rs_control *rs;  /* Reed-Solomon state */
+       int erasures[DM_VERITY_FEC_MAX_RSN];    /* erasures for decode_rs8 */
+       u8 *bufs[DM_VERITY_FEC_BUF_MAX];        /* bufs for deinterleaving */
+       unsigned nbufs;         /* number of buffers allocated */
+       u8 *output;             /* buffer for corrected output */
+       size_t output_pos;
+};
+
+#ifdef CONFIG_DM_VERITY_FEC
+
+/* each feature parameter requires a value */
+#define DM_VERITY_OPTS_FEC     8
+
+extern bool verity_fec_is_enabled(struct dm_verity *v);
+
+extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
+                            enum verity_block_type type, sector_t block,
+                            u8 *dest, struct bvec_iter *iter);
+
+extern unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
+                                       char *result, unsigned maxlen);
+
+extern void verity_fec_finish_io(struct dm_verity_io *io);
+extern void verity_fec_init_io(struct dm_verity_io *io);
+
+extern bool verity_is_fec_opt_arg(const char *arg_name);
+extern int verity_fec_parse_opt_args(struct dm_arg_set *as,
+                                    struct dm_verity *v, unsigned *argc,
+                                    const char *arg_name);
+
+extern void verity_fec_dtr(struct dm_verity *v);
+
+extern int verity_fec_ctr_alloc(struct dm_verity *v);
+extern int verity_fec_ctr(struct dm_verity *v);
+
+#else /* !CONFIG_DM_VERITY_FEC */
+
+#define DM_VERITY_OPTS_FEC     0
+
+static inline bool verity_fec_is_enabled(struct dm_verity *v)
+{
+       return false;
+}
+
+static inline int verity_fec_decode(struct dm_verity *v,
+                                   struct dm_verity_io *io,
+                                   enum verity_block_type type,
+                                   sector_t block, u8 *dest,
+                                   struct bvec_iter *iter)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline unsigned verity_fec_status_table(struct dm_verity *v,
+                                              unsigned sz, char *result,
+                                              unsigned maxlen)
+{
+       return sz;
+}
+
+static inline void verity_fec_finish_io(struct dm_verity_io *io)
+{
+}
+
+static inline void verity_fec_init_io(struct dm_verity_io *io)
+{
+}
+
+static inline bool verity_is_fec_opt_arg(const char *arg_name)
+{
+       return false;
+}
+
+static inline int verity_fec_parse_opt_args(struct dm_arg_set *as,
+                                           struct dm_verity *v,
+                                           unsigned *argc,
+                                           const char *arg_name)
+{
+       return -EINVAL;
+}
+
+static inline void verity_fec_dtr(struct dm_verity *v)
+{
+}
+
+static inline int verity_fec_ctr_alloc(struct dm_verity *v)
+{
+       return 0;
+}
+
+static inline int verity_fec_ctr(struct dm_verity *v)
+{
+       return 0;
+}
+
+#endif /* CONFIG_DM_VERITY_FEC */
+
+#endif /* DM_VERITY_FEC_H */
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
new file mode 100644 (file)
index 0000000..5c5d30c
--- /dev/null
@@ -0,0 +1,1093 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ *
+ * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
+ * default prefetch value. Data are read in "prefetch_cluster" chunks from the
+ * hash device. Setting this greatly improves performance when data and hash
+ * are on the same disk on different partitions on devices with poor random
+ * access behavior.
+ */
+
+#include "dm-verity.h"
+#include "dm-verity-fec.h"
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+#define DM_MSG_PREFIX                  "verity"
+
+#define DM_VERITY_ENV_LENGTH           42
+#define DM_VERITY_ENV_VAR_NAME         "DM_VERITY_ERR_BLOCK_NR"
+
+#define DM_VERITY_DEFAULT_PREFETCH_SIZE        262144
+
+#define DM_VERITY_MAX_CORRUPTED_ERRS   100
+
+#define DM_VERITY_OPT_LOGGING          "ignore_corruption"
+#define DM_VERITY_OPT_RESTART          "restart_on_corruption"
+#define DM_VERITY_OPT_IGN_ZEROES       "ignore_zero_blocks"
+
+#define DM_VERITY_OPTS_MAX             (2 + DM_VERITY_OPTS_FEC)
+
+static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
+
+module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
+
+struct dm_verity_prefetch_work {
+       struct work_struct work;
+       struct dm_verity *v;
+       sector_t block;
+       unsigned n_blocks;
+};
+
+/*
+ * Auxiliary structure appended to each dm-bufio buffer. If the value
+ * hash_verified is nonzero, hash of the block has been verified.
+ *
+ * The variable hash_verified is set to 0 when allocating the buffer, then
+ * it can be changed to 1 and it is never reset to 0 again.
+ *
+ * There is no lock around this value, a race condition can at worst cause
+ * that multiple processes verify the hash of the same buffer simultaneously
+ * and write 1 to hash_verified simultaneously.
+ * This condition is harmless, so we don't need locking.
+ */
+struct buffer_aux {
+       int hash_verified;
+};
+
+/*
+ * Initialize struct buffer_aux for a freshly created buffer.
+ */
+static void dm_bufio_alloc_callback(struct dm_buffer *buf)
+{
+       struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
+       aux->hash_verified = 0;
+}
+
+/*
+ * Translate input sector number to the sector number on the target device.
+ */
+static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
+{
+       return v->data_start + dm_target_offset(v->ti, bi_sector);
+}
+
+/*
+ * Return hash position of a specified block at a specified tree level
+ * (0 is the lowest level).
+ * The lowest "hash_per_block_bits"-bits of the result denote hash position
+ * inside a hash block. The remaining bits denote location of the hash block.
+ */
+static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
+                                        int level)
+{
+       return block >> (level * v->hash_per_block_bits);
+}
+
+/*
+ * Wrapper for crypto_shash_init, which handles verity salting.
+ */
+static int verity_hash_init(struct dm_verity *v, struct shash_desc *desc)
+{
+       int r;
+
+       desc->tfm = v->tfm;
+       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       r = crypto_shash_init(desc);
+
+       if (unlikely(r < 0)) {
+               DMERR("crypto_shash_init failed: %d", r);
+               return r;
+       }
+
+       if (likely(v->version >= 1)) {
+               r = crypto_shash_update(desc, v->salt, v->salt_size);
+
+               if (unlikely(r < 0)) {
+                       DMERR("crypto_shash_update failed: %d", r);
+                       return r;
+               }
+       }
+
+       return 0;
+}
+
+static int verity_hash_update(struct dm_verity *v, struct shash_desc *desc,
+                             const u8 *data, size_t len)
+{
+       int r = crypto_shash_update(desc, data, len);
+
+       if (unlikely(r < 0))
+               DMERR("crypto_shash_update failed: %d", r);
+
+       return r;
+}
+
+static int verity_hash_final(struct dm_verity *v, struct shash_desc *desc,
+                            u8 *digest)
+{
+       int r;
+
+       if (unlikely(!v->version)) {
+               r = crypto_shash_update(desc, v->salt, v->salt_size);
+
+               if (r < 0) {
+                       DMERR("crypto_shash_update failed: %d", r);
+                       return r;
+               }
+       }
+
+       r = crypto_shash_final(desc, digest);
+
+       if (unlikely(r < 0))
+               DMERR("crypto_shash_final failed: %d", r);
+
+       return r;
+}
+
+int verity_hash(struct dm_verity *v, struct shash_desc *desc,
+               const u8 *data, size_t len, u8 *digest)
+{
+       int r;
+
+       r = verity_hash_init(v, desc);
+       if (unlikely(r < 0))
+               return r;
+
+       r = verity_hash_update(v, desc, data, len);
+       if (unlikely(r < 0))
+               return r;
+
+       return verity_hash_final(v, desc, digest);
+}
+
+static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
+                                sector_t *hash_block, unsigned *offset)
+{
+       sector_t position = verity_position_at_level(v, block, level);
+       unsigned idx;
+
+       *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
+
+       if (!offset)
+               return;
+
+       idx = position & ((1 << v->hash_per_block_bits) - 1);
+       if (!v->version)
+               *offset = idx * v->digest_size;
+       else
+               *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
+}
+
+/*
+ * Handle verification errors.
+ */
+static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
+                            unsigned long long block)
+{
+       char verity_env[DM_VERITY_ENV_LENGTH];
+       char *envp[] = { verity_env, NULL };
+       const char *type_str = "";
+       struct mapped_device *md = dm_table_get_md(v->ti->table);
+
+       /* Corruption should be visible in device status in all modes */
+       v->hash_failed = 1;
+
+       if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
+               goto out;
+
+       v->corrupted_errs++;
+
+       switch (type) {
+       case DM_VERITY_BLOCK_TYPE_DATA:
+               type_str = "data";
+               break;
+       case DM_VERITY_BLOCK_TYPE_METADATA:
+               type_str = "metadata";
+               break;
+       default:
+               BUG();
+       }
+
+       DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
+               block);
+
+       if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
+               DMERR("%s: reached maximum errors", v->data_dev->name);
+
+       snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu",
+               DM_VERITY_ENV_VAR_NAME, type, block);
+
+       kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp);
+
+out:
+       if (v->mode == DM_VERITY_MODE_LOGGING)
+               return 0;
+
+       if (v->mode == DM_VERITY_MODE_RESTART)
+               kernel_restart("dm-verity device corrupted");
+
+       return 1;
+}
+
+/*
+ * Verify hash of a metadata block pertaining to the specified data block
+ * ("block" argument) at a specified level ("level" argument).
+ *
+ * On successful return, verity_io_want_digest(v, io) contains the hash value
+ * for a lower tree level or for the data block (if we're at the lowest level).
+ *
+ * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
+ * If "skip_unverified" is false, unverified buffer is hashed and verified
+ * against current value of verity_io_want_digest(v, io).
+ */
+static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
+                              sector_t block, int level, bool skip_unverified,
+                              u8 *want_digest)
+{
+       struct dm_buffer *buf;
+       struct buffer_aux *aux;
+       u8 *data;
+       int r;
+       sector_t hash_block;
+       unsigned offset;
+
+       verity_hash_at_level(v, block, level, &hash_block, &offset);
+
+       data = dm_bufio_read(v->bufio, hash_block, &buf);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       aux = dm_bufio_get_aux_data(buf);
+
+       if (!aux->hash_verified) {
+               if (skip_unverified) {
+                       r = 1;
+                       goto release_ret_r;
+               }
+
+               r = verity_hash(v, verity_io_hash_desc(v, io),
+                               data, 1 << v->hash_dev_block_bits,
+                               verity_io_real_digest(v, io));
+               if (unlikely(r < 0))
+                       goto release_ret_r;
+
+               if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
+                                 v->digest_size) == 0))
+                       aux->hash_verified = 1;
+               else if (verity_fec_decode(v, io,
+                                          DM_VERITY_BLOCK_TYPE_METADATA,
+                                          hash_block, data, NULL) == 0)
+                       aux->hash_verified = 1;
+               else if (verity_handle_err(v,
+                                          DM_VERITY_BLOCK_TYPE_METADATA,
+                                          hash_block)) {
+                       r = -EIO;
+                       goto release_ret_r;
+               }
+       }
+
+       data += offset;
+       memcpy(want_digest, data, v->digest_size);
+       r = 0;
+
+release_ret_r:
+       dm_bufio_release(buf);
+       return r;
+}
+
+/*
+ * Find a hash for a given block, write it to digest and verify the integrity
+ * of the hash tree if necessary.
+ */
+int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
+                         sector_t block, u8 *digest, bool *is_zero)
+{
+       int r = 0, i;
+
+       if (likely(v->levels)) {
+               /*
+                * First, we try to get the requested hash for
+                * the current block. If the hash block itself is
+                * verified, zero is returned. If it isn't, this
+                * function returns 1 and we fall back to whole
+                * chain verification.
+                */
+               r = verity_verify_level(v, io, block, 0, true, digest);
+               if (likely(r <= 0))
+                       goto out;
+       }
+
+       memcpy(digest, v->root_digest, v->digest_size);
+
+       for (i = v->levels - 1; i >= 0; i--) {
+               r = verity_verify_level(v, io, block, i, false, digest);
+               if (unlikely(r))
+                       goto out;
+       }
+out:
+       if (!r && v->zero_digest)
+               *is_zero = !memcmp(v->zero_digest, digest, v->digest_size);
+       else
+               *is_zero = false;
+
+       return r;
+}
+
+/*
+ * Calls function process for 1 << v->data_dev_block_bits bytes in the bio_vec
+ * starting from iter.
+ */
+int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
+                       struct bvec_iter *iter,
+                       int (*process)(struct dm_verity *v,
+                                      struct dm_verity_io *io, u8 *data,
+                                      size_t len))
+{
+       unsigned todo = 1 << v->data_dev_block_bits;
+       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+
+       do {
+               int r;
+               u8 *page;
+               unsigned len;
+               struct bio_vec bv = bio_iter_iovec(bio, *iter);
+
+               page = kmap_atomic(bv.bv_page);
+               len = bv.bv_len;
+
+               if (likely(len >= todo))
+                       len = todo;
+
+               r = process(v, io, page + bv.bv_offset, len);
+               kunmap_atomic(page);
+
+               if (r < 0)
+                       return r;
+
+               bio_advance_iter(bio, iter, len);
+               todo -= len;
+       } while (todo);
+
+       return 0;
+}
+
+static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io,
+                                u8 *data, size_t len)
+{
+       return verity_hash_update(v, verity_io_hash_desc(v, io), data, len);
+}
+
+static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
+                         u8 *data, size_t len)
+{
+       memset(data, 0, len);
+       return 0;
+}
+
+/*
+ * Verify one "dm_verity_io" structure.
+ */
+static int verity_verify_io(struct dm_verity_io *io)
+{
+       bool is_zero;
+       struct dm_verity *v = io->v;
+       struct bvec_iter start;
+       unsigned b;
+
+       for (b = 0; b < io->n_blocks; b++) {
+               int r;
+               struct shash_desc *desc = verity_io_hash_desc(v, io);
+
+               r = verity_hash_for_block(v, io, io->block + b,
+                                         verity_io_want_digest(v, io),
+                                         &is_zero);
+               if (unlikely(r < 0))
+                       return r;
+
+               if (is_zero) {
+                       /*
+                        * If we expect a zero block, don't validate, just
+                        * return zeros.
+                        */
+                       r = verity_for_bv_block(v, io, &io->iter,
+                                               verity_bv_zero);
+                       if (unlikely(r < 0))
+                               return r;
+
+                       continue;
+               }
+
+               r = verity_hash_init(v, desc);
+               if (unlikely(r < 0))
+                       return r;
+
+               start = io->iter;
+               r = verity_for_bv_block(v, io, &io->iter, verity_bv_hash_update);
+               if (unlikely(r < 0))
+                       return r;
+
+               r = verity_hash_final(v, desc, verity_io_real_digest(v, io));
+               if (unlikely(r < 0))
+                       return r;
+
+               if (likely(memcmp(verity_io_real_digest(v, io),
+                                 verity_io_want_digest(v, io), v->digest_size) == 0))
+                       continue;
+               else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
+                                          io->block + b, NULL, &start) == 0)
+                       continue;
+               else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
+                                          io->block + b))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * End one "io" structure with a given error.
+ */
+static void verity_finish_io(struct dm_verity_io *io, int error)
+{
+       struct dm_verity *v = io->v;
+       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+
+       bio->bi_end_io = io->orig_bi_end_io;
+       bio->bi_error = error;
+
+       verity_fec_finish_io(io);
+
+       bio_endio(bio);
+}
+
+static void verity_work(struct work_struct *w)
+{
+       struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
+
+       verity_finish_io(io, verity_verify_io(io));
+}
+
+static void verity_end_io(struct bio *bio)
+{
+       struct dm_verity_io *io = bio->bi_private;
+
+       if (bio->bi_error && !verity_fec_is_enabled(io->v)) {
+               verity_finish_io(io, bio->bi_error);
+               return;
+       }
+
+       INIT_WORK(&io->work, verity_work);
+       queue_work(io->v->verify_wq, &io->work);
+}
+
+/*
+ * Prefetch buffers for the specified io.
+ * The root buffer is not prefetched, it is assumed that it will be cached
+ * all the time.
+ */
+static void verity_prefetch_io(struct work_struct *work)
+{
+       struct dm_verity_prefetch_work *pw =
+               container_of(work, struct dm_verity_prefetch_work, work);
+       struct dm_verity *v = pw->v;
+       int i;
+
+       for (i = v->levels - 2; i >= 0; i--) {
+               sector_t hash_block_start;
+               sector_t hash_block_end;
+               verity_hash_at_level(v, pw->block, i, &hash_block_start, NULL);
+               verity_hash_at_level(v, pw->block + pw->n_blocks - 1, i, &hash_block_end, NULL);
+               if (!i) {
+                       unsigned cluster = ACCESS_ONCE(dm_verity_prefetch_cluster);
+
+                       cluster >>= v->data_dev_block_bits;
+                       if (unlikely(!cluster))
+                               goto no_prefetch_cluster;
+
+                       if (unlikely(cluster & (cluster - 1)))
+                               cluster = 1 << __fls(cluster);
+
+                       hash_block_start &= ~(sector_t)(cluster - 1);
+                       hash_block_end |= cluster - 1;
+                       if (unlikely(hash_block_end >= v->hash_blocks))
+                               hash_block_end = v->hash_blocks - 1;
+               }
+no_prefetch_cluster:
+               dm_bufio_prefetch(v->bufio, hash_block_start,
+                                 hash_block_end - hash_block_start + 1);
+       }
+
+       kfree(pw);
+}
+
+static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
+{
+       struct dm_verity_prefetch_work *pw;
+
+       pw = kmalloc(sizeof(struct dm_verity_prefetch_work),
+               GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
+
+       if (!pw)
+               return;
+
+       INIT_WORK(&pw->work, verity_prefetch_io);
+       pw->v = v;
+       pw->block = io->block;
+       pw->n_blocks = io->n_blocks;
+       queue_work(v->verify_wq, &pw->work);
+}
+
+/*
+ * Bio map function. It allocates dm_verity_io structure and bio vector and
+ * fills them. Then it issues prefetches and the I/O.
+ */
+static int verity_map(struct dm_target *ti, struct bio *bio)
+{
+       struct dm_verity *v = ti->private;
+       struct dm_verity_io *io;
+
+       bio->bi_bdev = v->data_dev->bdev;
+       bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector);
+
+       if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
+           ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
+               DMERR_LIMIT("unaligned io");
+               return -EIO;
+       }
+
+       if (bio_end_sector(bio) >>
+           (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
+               DMERR_LIMIT("io out of range");
+               return -EIO;
+       }
+
+       if (bio_data_dir(bio) == WRITE)
+               return -EIO;
+
+       io = dm_per_bio_data(bio, ti->per_bio_data_size);
+       io->v = v;
+       io->orig_bi_end_io = bio->bi_end_io;
+       io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
+       io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
+
+       bio->bi_end_io = verity_end_io;
+       bio->bi_private = io;
+       io->iter = bio->bi_iter;
+
+       verity_fec_init_io(io);
+
+       verity_submit_prefetch(v, io);
+
+       generic_make_request(bio);
+
+       return DM_MAPIO_SUBMITTED;
+}
+
+/*
+ * Status: V (valid) or C (corruption found)
+ */
+static void verity_status(struct dm_target *ti, status_type_t type,
+                         unsigned status_flags, char *result, unsigned maxlen)
+{
+       struct dm_verity *v = ti->private;
+       unsigned args = 0;
+       unsigned sz = 0;
+       unsigned x;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               DMEMIT("%c", v->hash_failed ? 'C' : 'V');
+               break;
+       case STATUSTYPE_TABLE:
+               DMEMIT("%u %s %s %u %u %llu %llu %s ",
+                       v->version,
+                       v->data_dev->name,
+                       v->hash_dev->name,
+                       1 << v->data_dev_block_bits,
+                       1 << v->hash_dev_block_bits,
+                       (unsigned long long)v->data_blocks,
+                       (unsigned long long)v->hash_start,
+                       v->alg_name
+                       );
+               for (x = 0; x < v->digest_size; x++)
+                       DMEMIT("%02x", v->root_digest[x]);
+               DMEMIT(" ");
+               if (!v->salt_size)
+                       DMEMIT("-");
+               else
+                       for (x = 0; x < v->salt_size; x++)
+                               DMEMIT("%02x", v->salt[x]);
+               if (v->mode != DM_VERITY_MODE_EIO)
+                       args++;
+               if (verity_fec_is_enabled(v))
+                       args += DM_VERITY_OPTS_FEC;
+               if (v->zero_digest)
+                       args++;
+               if (!args)
+                       return;
+               DMEMIT(" %u", args);
+               if (v->mode != DM_VERITY_MODE_EIO) {
+                       DMEMIT(" ");
+                       switch (v->mode) {
+                       case DM_VERITY_MODE_LOGGING:
+                               DMEMIT(DM_VERITY_OPT_LOGGING);
+                               break;
+                       case DM_VERITY_MODE_RESTART:
+                               DMEMIT(DM_VERITY_OPT_RESTART);
+                               break;
+                       default:
+                               BUG();
+                       }
+               }
+               if (v->zero_digest)
+                       DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
+               sz = verity_fec_status_table(v, sz, result, maxlen);
+               break;
+       }
+}
+
+static int verity_prepare_ioctl(struct dm_target *ti,
+               struct block_device **bdev, fmode_t *mode)
+{
+       struct dm_verity *v = ti->private;
+
+       *bdev = v->data_dev->bdev;
+
+       if (v->data_start ||
+           ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
+               return 1;
+       return 0;
+}
+
+static int verity_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct dm_verity *v = ti->private;
+
+       return fn(ti, v->data_dev, v->data_start, ti->len, data);
+}
+
+static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+       struct dm_verity *v = ti->private;
+
+       if (limits->logical_block_size < 1 << v->data_dev_block_bits)
+               limits->logical_block_size = 1 << v->data_dev_block_bits;
+
+       if (limits->physical_block_size < 1 << v->data_dev_block_bits)
+               limits->physical_block_size = 1 << v->data_dev_block_bits;
+
+       blk_limits_io_min(limits, limits->logical_block_size);
+}
+
+static void verity_dtr(struct dm_target *ti)
+{
+       struct dm_verity *v = ti->private;
+
+       if (v->verify_wq)
+               destroy_workqueue(v->verify_wq);
+
+       if (v->bufio)
+               dm_bufio_client_destroy(v->bufio);
+
+       kfree(v->salt);
+       kfree(v->root_digest);
+       kfree(v->zero_digest);
+
+       if (v->tfm)
+               crypto_free_shash(v->tfm);
+
+       kfree(v->alg_name);
+
+       if (v->hash_dev)
+               dm_put_device(ti, v->hash_dev);
+
+       if (v->data_dev)
+               dm_put_device(ti, v->data_dev);
+
+       verity_fec_dtr(v);
+
+       kfree(v);
+}
+
+static int verity_alloc_zero_digest(struct dm_verity *v)
+{
+       int r = -ENOMEM;
+       struct shash_desc *desc;
+       u8 *zero_data;
+
+       v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL);
+
+       if (!v->zero_digest)
+               return r;
+
+       desc = kmalloc(v->shash_descsize, GFP_KERNEL);
+
+       if (!desc)
+               return r; /* verity_dtr will free zero_digest */
+
+       zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL);
+
+       if (!zero_data)
+               goto out;
+
+       r = verity_hash(v, desc, zero_data, 1 << v->data_dev_block_bits,
+                       v->zero_digest);
+
+out:
+       kfree(desc);
+       kfree(zero_data);
+
+       return r;
+}
+
+static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
+{
+       int r;
+       unsigned argc;
+       struct dm_target *ti = v->ti;
+       const char *arg_name;
+
+       static struct dm_arg _args[] = {
+               {0, DM_VERITY_OPTS_MAX, "Invalid number of feature args"},
+       };
+
+       r = dm_read_arg_group(_args, as, &argc, &ti->error);
+       if (r)
+               return -EINVAL;
+
+       if (!argc)
+               return 0;
+
+       do {
+               arg_name = dm_shift_arg(as);
+               argc--;
+
+               if (!strcasecmp(arg_name, DM_VERITY_OPT_LOGGING)) {
+                       v->mode = DM_VERITY_MODE_LOGGING;
+                       continue;
+
+               } else if (!strcasecmp(arg_name, DM_VERITY_OPT_RESTART)) {
+                       v->mode = DM_VERITY_MODE_RESTART;
+                       continue;
+
+               } else if (!strcasecmp(arg_name, DM_VERITY_OPT_IGN_ZEROES)) {
+                       r = verity_alloc_zero_digest(v);
+                       if (r) {
+                               ti->error = "Cannot allocate zero digest";
+                               return r;
+                       }
+                       continue;
+
+               } else if (verity_is_fec_opt_arg(arg_name)) {
+                       r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
+                       if (r)
+                               return r;
+                       continue;
+               }
+
+               ti->error = "Unrecognized verity feature request";
+               return -EINVAL;
+       } while (argc && !r);
+
+       return r;
+}
+
+/*
+ * Target parameters:
+ *     <version>       The current format is version 1.
+ *                     Vsn 0 is compatible with original Chromium OS releases.
+ *     <data device>
+ *     <hash device>
+ *     <data block size>
+ *     <hash block size>
+ *     <the number of data blocks>
+ *     <hash start block>
+ *     <algorithm>
+ *     <digest>
+ *     <salt>          Hex string or "-" if no salt.
+ */
+static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+       struct dm_verity *v;
+       struct dm_arg_set as;
+       unsigned int num;
+       unsigned long long num_ll;
+       int r;
+       int i;
+       sector_t hash_position;
+       char dummy;
+
+       v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
+       if (!v) {
+               ti->error = "Cannot allocate verity structure";
+               return -ENOMEM;
+       }
+       ti->private = v;
+       v->ti = ti;
+
+       r = verity_fec_ctr_alloc(v);
+       if (r)
+               goto bad;
+
+       if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
+               ti->error = "Device must be readonly";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (argc < 10) {
+               ti->error = "Not enough arguments";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
+           num > 1) {
+               ti->error = "Invalid version";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->version = num;
+
+       r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
+       if (r) {
+               ti->error = "Data device lookup failed";
+               goto bad;
+       }
+
+       r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
+       if (r) {
+               ti->error = "Data device lookup failed";
+               goto bad;
+       }
+
+       if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
+           !num || (num & (num - 1)) ||
+           num < bdev_logical_block_size(v->data_dev->bdev) ||
+           num > PAGE_SIZE) {
+               ti->error = "Invalid data device block size";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->data_dev_block_bits = __ffs(num);
+
+       if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
+           !num || (num & (num - 1)) ||
+           num < bdev_logical_block_size(v->hash_dev->bdev) ||
+           num > INT_MAX) {
+               ti->error = "Invalid hash device block size";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->hash_dev_block_bits = __ffs(num);
+
+       if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
+           (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+           >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) {
+               ti->error = "Invalid data blocks";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->data_blocks = num_ll;
+
+       if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
+               ti->error = "Data device is too small";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
+           (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT))
+           >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) {
+               ti->error = "Invalid hash start";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->hash_start = num_ll;
+
+       v->alg_name = kstrdup(argv[7], GFP_KERNEL);
+       if (!v->alg_name) {
+               ti->error = "Cannot allocate algorithm name";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
+       if (IS_ERR(v->tfm)) {
+               ti->error = "Cannot initialize hash function";
+               r = PTR_ERR(v->tfm);
+               v->tfm = NULL;
+               goto bad;
+       }
+       v->digest_size = crypto_shash_digestsize(v->tfm);
+       if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
+               ti->error = "Digest size too big";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->shash_descsize =
+               sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
+
+       v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
+       if (!v->root_digest) {
+               ti->error = "Cannot allocate root digest";
+               r = -ENOMEM;
+               goto bad;
+       }
+       if (strlen(argv[8]) != v->digest_size * 2 ||
+           hex2bin(v->root_digest, argv[8], v->digest_size)) {
+               ti->error = "Invalid root digest";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (strcmp(argv[9], "-")) {
+               v->salt_size = strlen(argv[9]) / 2;
+               v->salt = kmalloc(v->salt_size, GFP_KERNEL);
+               if (!v->salt) {
+                       ti->error = "Cannot allocate salt";
+                       r = -ENOMEM;
+                       goto bad;
+               }
+               if (strlen(argv[9]) != v->salt_size * 2 ||
+                   hex2bin(v->salt, argv[9], v->salt_size)) {
+                       ti->error = "Invalid salt";
+                       r = -EINVAL;
+                       goto bad;
+               }
+       }
+
+       argv += 10;
+       argc -= 10;
+
+       /* Optional parameters */
+       if (argc) {
+               as.argc = argc;
+               as.argv = argv;
+
+               r = verity_parse_opt_args(&as, v);
+               if (r < 0)
+                       goto bad;
+       }
+
+       v->hash_per_block_bits =
+               __fls((1 << v->hash_dev_block_bits) / v->digest_size);
+
+       v->levels = 0;
+       if (v->data_blocks)
+               while (v->hash_per_block_bits * v->levels < 64 &&
+                      (unsigned long long)(v->data_blocks - 1) >>
+                      (v->hash_per_block_bits * v->levels))
+                       v->levels++;
+
+       if (v->levels > DM_VERITY_MAX_LEVELS) {
+               ti->error = "Too many tree levels";
+               r = -E2BIG;
+               goto bad;
+       }
+
+       hash_position = v->hash_start;
+       for (i = v->levels - 1; i >= 0; i--) {
+               sector_t s;
+               v->hash_level_block[i] = hash_position;
+               s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
+                                       >> ((i + 1) * v->hash_per_block_bits);
+               if (hash_position + s < hash_position) {
+                       ti->error = "Hash device offset overflow";
+                       r = -E2BIG;
+                       goto bad;
+               }
+               hash_position += s;
+       }
+       v->hash_blocks = hash_position;
+
+       v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
+               1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
+               dm_bufio_alloc_callback, NULL);
+       if (IS_ERR(v->bufio)) {
+               ti->error = "Cannot initialize dm-bufio";
+               r = PTR_ERR(v->bufio);
+               v->bufio = NULL;
+               goto bad;
+       }
+
+       if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
+               ti->error = "Hash device is too small";
+               r = -E2BIG;
+               goto bad;
+       }
+
+       /* WQ_UNBOUND greatly improves performance when running on ramdisk */
+       v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
+       if (!v->verify_wq) {
+               ti->error = "Cannot allocate workqueue";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       ti->per_bio_data_size = sizeof(struct dm_verity_io) +
+                               v->shash_descsize + v->digest_size * 2;
+
+       r = verity_fec_ctr(v);
+       if (r)
+               goto bad;
+
+       ti->per_bio_data_size = roundup(ti->per_bio_data_size,
+                                       __alignof__(struct dm_verity_io));
+
+       return 0;
+
+bad:
+       verity_dtr(ti);
+
+       return r;
+}
+
+static struct target_type verity_target = {
+       .name           = "verity",
+       .version        = {1, 3, 0},
+       .module         = THIS_MODULE,
+       .ctr            = verity_ctr,
+       .dtr            = verity_dtr,
+       .map            = verity_map,
+       .status         = verity_status,
+       .prepare_ioctl  = verity_prepare_ioctl,
+       .iterate_devices = verity_iterate_devices,
+       .io_hints       = verity_io_hints,
+};
+
+static int __init dm_verity_init(void)
+{
+       int r;
+
+       r = dm_register_target(&verity_target);
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       return r;
+}
+
+static void __exit dm_verity_exit(void)
+{
+       dm_unregister_target(&verity_target);
+}
+
+module_init(dm_verity_init);
+module_exit(dm_verity_exit);
+
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
+MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
+MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
deleted file mode 100644 (file)
index ccf4188..0000000
+++ /dev/null
@@ -1,995 +0,0 @@
-/*
- * Copyright (C) 2012 Red Hat, Inc.
- *
- * Author: Mikulas Patocka <mpatocka@redhat.com>
- *
- * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
- *
- * This file is released under the GPLv2.
- *
- * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
- * default prefetch value. Data are read in "prefetch_cluster" chunks from the
- * hash device. Setting this greatly improves performance when data and hash
- * are on the same disk on different partitions on devices with poor random
- * access behavior.
- */
-
-#include "dm-bufio.h"
-
-#include <linux/module.h>
-#include <linux/device-mapper.h>
-#include <linux/reboot.h>
-#include <crypto/hash.h>
-
-#define DM_MSG_PREFIX                  "verity"
-
-#define DM_VERITY_ENV_LENGTH           42
-#define DM_VERITY_ENV_VAR_NAME         "DM_VERITY_ERR_BLOCK_NR"
-
-#define DM_VERITY_DEFAULT_PREFETCH_SIZE        262144
-
-#define DM_VERITY_MAX_LEVELS           63
-#define DM_VERITY_MAX_CORRUPTED_ERRS   100
-
-#define DM_VERITY_OPT_LOGGING          "ignore_corruption"
-#define DM_VERITY_OPT_RESTART          "restart_on_corruption"
-
-static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
-
-module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
-
-enum verity_mode {
-       DM_VERITY_MODE_EIO,
-       DM_VERITY_MODE_LOGGING,
-       DM_VERITY_MODE_RESTART
-};
-
-enum verity_block_type {
-       DM_VERITY_BLOCK_TYPE_DATA,
-       DM_VERITY_BLOCK_TYPE_METADATA
-};
-
-struct dm_verity {
-       struct dm_dev *data_dev;
-       struct dm_dev *hash_dev;
-       struct dm_target *ti;
-       struct dm_bufio_client *bufio;
-       char *alg_name;
-       struct crypto_shash *tfm;
-       u8 *root_digest;        /* digest of the root block */
-       u8 *salt;               /* salt: its size is salt_size */
-       unsigned salt_size;
-       sector_t data_start;    /* data offset in 512-byte sectors */
-       sector_t hash_start;    /* hash start in blocks */
-       sector_t data_blocks;   /* the number of data blocks */
-       sector_t hash_blocks;   /* the number of hash blocks */
-       unsigned char data_dev_block_bits;      /* log2(data blocksize) */
-       unsigned char hash_dev_block_bits;      /* log2(hash blocksize) */
-       unsigned char hash_per_block_bits;      /* log2(hashes in hash block) */
-       unsigned char levels;   /* the number of tree levels */
-       unsigned char version;
-       unsigned digest_size;   /* digest size for the current hash algorithm */
-       unsigned shash_descsize;/* the size of temporary space for crypto */
-       int hash_failed;        /* set to 1 if hash of any block failed */
-       enum verity_mode mode;  /* mode for handling verification errors */
-       unsigned corrupted_errs;/* Number of errors for corrupted blocks */
-
-       struct workqueue_struct *verify_wq;
-
-       /* starting blocks for each tree level. 0 is the lowest level. */
-       sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
-};
-
-struct dm_verity_io {
-       struct dm_verity *v;
-
-       /* original values of bio->bi_end_io and bio->bi_private */
-       bio_end_io_t *orig_bi_end_io;
-       void *orig_bi_private;
-
-       sector_t block;
-       unsigned n_blocks;
-
-       struct bvec_iter iter;
-
-       struct work_struct work;
-
-       /*
-        * Three variably-size fields follow this struct:
-        *
-        * u8 hash_desc[v->shash_descsize];
-        * u8 real_digest[v->digest_size];
-        * u8 want_digest[v->digest_size];
-        *
-        * To access them use: io_hash_desc(), io_real_digest() and io_want_digest().
-        */
-};
-
-struct dm_verity_prefetch_work {
-       struct work_struct work;
-       struct dm_verity *v;
-       sector_t block;
-       unsigned n_blocks;
-};
-
-static struct shash_desc *io_hash_desc(struct dm_verity *v, struct dm_verity_io *io)
-{
-       return (struct shash_desc *)(io + 1);
-}
-
-static u8 *io_real_digest(struct dm_verity *v, struct dm_verity_io *io)
-{
-       return (u8 *)(io + 1) + v->shash_descsize;
-}
-
-static u8 *io_want_digest(struct dm_verity *v, struct dm_verity_io *io)
-{
-       return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
-}
-
-/*
- * Auxiliary structure appended to each dm-bufio buffer. If the value
- * hash_verified is nonzero, hash of the block has been verified.
- *
- * The variable hash_verified is set to 0 when allocating the buffer, then
- * it can be changed to 1 and it is never reset to 0 again.
- *
- * There is no lock around this value, a race condition can at worst cause
- * that multiple processes verify the hash of the same buffer simultaneously
- * and write 1 to hash_verified simultaneously.
- * This condition is harmless, so we don't need locking.
- */
-struct buffer_aux {
-       int hash_verified;
-};
-
-/*
- * Initialize struct buffer_aux for a freshly created buffer.
- */
-static void dm_bufio_alloc_callback(struct dm_buffer *buf)
-{
-       struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
-
-       aux->hash_verified = 0;
-}
-
-/*
- * Translate input sector number to the sector number on the target device.
- */
-static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
-{
-       return v->data_start + dm_target_offset(v->ti, bi_sector);
-}
-
-/*
- * Return hash position of a specified block at a specified tree level
- * (0 is the lowest level).
- * The lowest "hash_per_block_bits"-bits of the result denote hash position
- * inside a hash block. The remaining bits denote location of the hash block.
- */
-static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
-                                        int level)
-{
-       return block >> (level * v->hash_per_block_bits);
-}
-
-static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
-                                sector_t *hash_block, unsigned *offset)
-{
-       sector_t position = verity_position_at_level(v, block, level);
-       unsigned idx;
-
-       *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
-
-       if (!offset)
-               return;
-
-       idx = position & ((1 << v->hash_per_block_bits) - 1);
-       if (!v->version)
-               *offset = idx * v->digest_size;
-       else
-               *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
-}
-
-/*
- * Handle verification errors.
- */
-static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
-                            unsigned long long block)
-{
-       char verity_env[DM_VERITY_ENV_LENGTH];
-       char *envp[] = { verity_env, NULL };
-       const char *type_str = "";
-       struct mapped_device *md = dm_table_get_md(v->ti->table);
-
-       /* Corruption should be visible in device status in all modes */
-       v->hash_failed = 1;
-
-       if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
-               goto out;
-
-       v->corrupted_errs++;
-
-       switch (type) {
-       case DM_VERITY_BLOCK_TYPE_DATA:
-               type_str = "data";
-               break;
-       case DM_VERITY_BLOCK_TYPE_METADATA:
-               type_str = "metadata";
-               break;
-       default:
-               BUG();
-       }
-
-       DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
-               block);
-
-       if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
-               DMERR("%s: reached maximum errors", v->data_dev->name);
-
-       snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu",
-               DM_VERITY_ENV_VAR_NAME, type, block);
-
-       kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp);
-
-out:
-       if (v->mode == DM_VERITY_MODE_LOGGING)
-               return 0;
-
-       if (v->mode == DM_VERITY_MODE_RESTART)
-               kernel_restart("dm-verity device corrupted");
-
-       return 1;
-}
-
-/*
- * Verify hash of a metadata block pertaining to the specified data block
- * ("block" argument) at a specified level ("level" argument).
- *
- * On successful return, io_want_digest(v, io) contains the hash value for
- * a lower tree level or for the data block (if we're at the lowest leve).
- *
- * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
- * If "skip_unverified" is false, unverified buffer is hashed and verified
- * against current value of io_want_digest(v, io).
- */
-static int verity_verify_level(struct dm_verity_io *io, sector_t block,
-                              int level, bool skip_unverified)
-{
-       struct dm_verity *v = io->v;
-       struct dm_buffer *buf;
-       struct buffer_aux *aux;
-       u8 *data;
-       int r;
-       sector_t hash_block;
-       unsigned offset;
-
-       verity_hash_at_level(v, block, level, &hash_block, &offset);
-
-       data = dm_bufio_read(v->bufio, hash_block, &buf);
-       if (IS_ERR(data))
-               return PTR_ERR(data);
-
-       aux = dm_bufio_get_aux_data(buf);
-
-       if (!aux->hash_verified) {
-               struct shash_desc *desc;
-               u8 *result;
-
-               if (skip_unverified) {
-                       r = 1;
-                       goto release_ret_r;
-               }
-
-               desc = io_hash_desc(v, io);
-               desc->tfm = v->tfm;
-               desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-               r = crypto_shash_init(desc);
-               if (r < 0) {
-                       DMERR("crypto_shash_init failed: %d", r);
-                       goto release_ret_r;
-               }
-
-               if (likely(v->version >= 1)) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               goto release_ret_r;
-                       }
-               }
-
-               r = crypto_shash_update(desc, data, 1 << v->hash_dev_block_bits);
-               if (r < 0) {
-                       DMERR("crypto_shash_update failed: %d", r);
-                       goto release_ret_r;
-               }
-
-               if (!v->version) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               goto release_ret_r;
-                       }
-               }
-
-               result = io_real_digest(v, io);
-               r = crypto_shash_final(desc, result);
-               if (r < 0) {
-                       DMERR("crypto_shash_final failed: %d", r);
-                       goto release_ret_r;
-               }
-               if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
-                       if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA,
-                                             hash_block)) {
-                               r = -EIO;
-                               goto release_ret_r;
-                       }
-               } else
-                       aux->hash_verified = 1;
-       }
-
-       data += offset;
-
-       memcpy(io_want_digest(v, io), data, v->digest_size);
-
-       dm_bufio_release(buf);
-       return 0;
-
-release_ret_r:
-       dm_bufio_release(buf);
-
-       return r;
-}
-
-/*
- * Verify one "dm_verity_io" structure.
- */
-static int verity_verify_io(struct dm_verity_io *io)
-{
-       struct dm_verity *v = io->v;
-       struct bio *bio = dm_bio_from_per_bio_data(io,
-                                                  v->ti->per_bio_data_size);
-       unsigned b;
-       int i;
-
-       for (b = 0; b < io->n_blocks; b++) {
-               struct shash_desc *desc;
-               u8 *result;
-               int r;
-               unsigned todo;
-
-               if (likely(v->levels)) {
-                       /*
-                        * First, we try to get the requested hash for
-                        * the current block. If the hash block itself is
-                        * verified, zero is returned. If it isn't, this
-                        * function returns 0 and we fall back to whole
-                        * chain verification.
-                        */
-                       int r = verity_verify_level(io, io->block + b, 0, true);
-                       if (likely(!r))
-                               goto test_block_hash;
-                       if (r < 0)
-                               return r;
-               }
-
-               memcpy(io_want_digest(v, io), v->root_digest, v->digest_size);
-
-               for (i = v->levels - 1; i >= 0; i--) {
-                       int r = verity_verify_level(io, io->block + b, i, false);
-                       if (unlikely(r))
-                               return r;
-               }
-
-test_block_hash:
-               desc = io_hash_desc(v, io);
-               desc->tfm = v->tfm;
-               desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-               r = crypto_shash_init(desc);
-               if (r < 0) {
-                       DMERR("crypto_shash_init failed: %d", r);
-                       return r;
-               }
-
-               if (likely(v->version >= 1)) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               return r;
-                       }
-               }
-               todo = 1 << v->data_dev_block_bits;
-               do {
-                       u8 *page;
-                       unsigned len;
-                       struct bio_vec bv = bio_iter_iovec(bio, io->iter);
-
-                       page = kmap_atomic(bv.bv_page);
-                       len = bv.bv_len;
-                       if (likely(len >= todo))
-                               len = todo;
-                       r = crypto_shash_update(desc, page + bv.bv_offset, len);
-                       kunmap_atomic(page);
-
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               return r;
-                       }
-
-                       bio_advance_iter(bio, &io->iter, len);
-                       todo -= len;
-               } while (todo);
-
-               if (!v->version) {
-                       r = crypto_shash_update(desc, v->salt, v->salt_size);
-                       if (r < 0) {
-                               DMERR("crypto_shash_update failed: %d", r);
-                               return r;
-                       }
-               }
-
-               result = io_real_digest(v, io);
-               r = crypto_shash_final(desc, result);
-               if (r < 0) {
-                       DMERR("crypto_shash_final failed: %d", r);
-                       return r;
-               }
-               if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
-                       if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
-                                             io->block + b))
-                               return -EIO;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * End one "io" structure with a given error.
- */
-static void verity_finish_io(struct dm_verity_io *io, int error)
-{
-       struct dm_verity *v = io->v;
-       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
-
-       bio->bi_end_io = io->orig_bi_end_io;
-       bio->bi_private = io->orig_bi_private;
-       bio->bi_error = error;
-
-       bio_endio(bio);
-}
-
-static void verity_work(struct work_struct *w)
-{
-       struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
-
-       verity_finish_io(io, verity_verify_io(io));
-}
-
-static void verity_end_io(struct bio *bio)
-{
-       struct dm_verity_io *io = bio->bi_private;
-
-       if (bio->bi_error) {
-               verity_finish_io(io, bio->bi_error);
-               return;
-       }
-
-       INIT_WORK(&io->work, verity_work);
-       queue_work(io->v->verify_wq, &io->work);
-}
-
-/*
- * Prefetch buffers for the specified io.
- * The root buffer is not prefetched, it is assumed that it will be cached
- * all the time.
- */
-static void verity_prefetch_io(struct work_struct *work)
-{
-       struct dm_verity_prefetch_work *pw =
-               container_of(work, struct dm_verity_prefetch_work, work);
-       struct dm_verity *v = pw->v;
-       int i;
-
-       for (i = v->levels - 2; i >= 0; i--) {
-               sector_t hash_block_start;
-               sector_t hash_block_end;
-               verity_hash_at_level(v, pw->block, i, &hash_block_start, NULL);
-               verity_hash_at_level(v, pw->block + pw->n_blocks - 1, i, &hash_block_end, NULL);
-               if (!i) {
-                       unsigned cluster = ACCESS_ONCE(dm_verity_prefetch_cluster);
-
-                       cluster >>= v->data_dev_block_bits;
-                       if (unlikely(!cluster))
-                               goto no_prefetch_cluster;
-
-                       if (unlikely(cluster & (cluster - 1)))
-                               cluster = 1 << __fls(cluster);
-
-                       hash_block_start &= ~(sector_t)(cluster - 1);
-                       hash_block_end |= cluster - 1;
-                       if (unlikely(hash_block_end >= v->hash_blocks))
-                               hash_block_end = v->hash_blocks - 1;
-               }
-no_prefetch_cluster:
-               dm_bufio_prefetch(v->bufio, hash_block_start,
-                                 hash_block_end - hash_block_start + 1);
-       }
-
-       kfree(pw);
-}
-
-static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
-{
-       struct dm_verity_prefetch_work *pw;
-
-       pw = kmalloc(sizeof(struct dm_verity_prefetch_work),
-               GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
-
-       if (!pw)
-               return;
-
-       INIT_WORK(&pw->work, verity_prefetch_io);
-       pw->v = v;
-       pw->block = io->block;
-       pw->n_blocks = io->n_blocks;
-       queue_work(v->verify_wq, &pw->work);
-}
-
-/*
- * Bio map function. It allocates dm_verity_io structure and bio vector and
- * fills them. Then it issues prefetches and the I/O.
- */
-static int verity_map(struct dm_target *ti, struct bio *bio)
-{
-       struct dm_verity *v = ti->private;
-       struct dm_verity_io *io;
-
-       bio->bi_bdev = v->data_dev->bdev;
-       bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector);
-
-       if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
-           ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
-               DMERR_LIMIT("unaligned io");
-               return -EIO;
-       }
-
-       if (bio_end_sector(bio) >>
-           (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
-               DMERR_LIMIT("io out of range");
-               return -EIO;
-       }
-
-       if (bio_data_dir(bio) == WRITE)
-               return -EIO;
-
-       io = dm_per_bio_data(bio, ti->per_bio_data_size);
-       io->v = v;
-       io->orig_bi_end_io = bio->bi_end_io;
-       io->orig_bi_private = bio->bi_private;
-       io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
-       io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
-
-       bio->bi_end_io = verity_end_io;
-       bio->bi_private = io;
-       io->iter = bio->bi_iter;
-
-       verity_submit_prefetch(v, io);
-
-       generic_make_request(bio);
-
-       return DM_MAPIO_SUBMITTED;
-}
-
-/*
- * Status: V (valid) or C (corruption found)
- */
-static void verity_status(struct dm_target *ti, status_type_t type,
-                         unsigned status_flags, char *result, unsigned maxlen)
-{
-       struct dm_verity *v = ti->private;
-       unsigned sz = 0;
-       unsigned x;
-
-       switch (type) {
-       case STATUSTYPE_INFO:
-               DMEMIT("%c", v->hash_failed ? 'C' : 'V');
-               break;
-       case STATUSTYPE_TABLE:
-               DMEMIT("%u %s %s %u %u %llu %llu %s ",
-                       v->version,
-                       v->data_dev->name,
-                       v->hash_dev->name,
-                       1 << v->data_dev_block_bits,
-                       1 << v->hash_dev_block_bits,
-                       (unsigned long long)v->data_blocks,
-                       (unsigned long long)v->hash_start,
-                       v->alg_name
-                       );
-               for (x = 0; x < v->digest_size; x++)
-                       DMEMIT("%02x", v->root_digest[x]);
-               DMEMIT(" ");
-               if (!v->salt_size)
-                       DMEMIT("-");
-               else
-                       for (x = 0; x < v->salt_size; x++)
-                               DMEMIT("%02x", v->salt[x]);
-               if (v->mode != DM_VERITY_MODE_EIO) {
-                       DMEMIT(" 1 ");
-                       switch (v->mode) {
-                       case DM_VERITY_MODE_LOGGING:
-                               DMEMIT(DM_VERITY_OPT_LOGGING);
-                               break;
-                       case DM_VERITY_MODE_RESTART:
-                               DMEMIT(DM_VERITY_OPT_RESTART);
-                               break;
-                       default:
-                               BUG();
-                       }
-               }
-               break;
-       }
-}
-
-static int verity_prepare_ioctl(struct dm_target *ti,
-               struct block_device **bdev, fmode_t *mode)
-{
-       struct dm_verity *v = ti->private;
-
-       *bdev = v->data_dev->bdev;
-
-       if (v->data_start ||
-           ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
-               return 1;
-       return 0;
-}
-
-static int verity_iterate_devices(struct dm_target *ti,
-                                 iterate_devices_callout_fn fn, void *data)
-{
-       struct dm_verity *v = ti->private;
-
-       return fn(ti, v->data_dev, v->data_start, ti->len, data);
-}
-
-static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
-{
-       struct dm_verity *v = ti->private;
-
-       if (limits->logical_block_size < 1 << v->data_dev_block_bits)
-               limits->logical_block_size = 1 << v->data_dev_block_bits;
-
-       if (limits->physical_block_size < 1 << v->data_dev_block_bits)
-               limits->physical_block_size = 1 << v->data_dev_block_bits;
-
-       blk_limits_io_min(limits, limits->logical_block_size);
-}
-
-static void verity_dtr(struct dm_target *ti)
-{
-       struct dm_verity *v = ti->private;
-
-       if (v->verify_wq)
-               destroy_workqueue(v->verify_wq);
-
-       if (v->bufio)
-               dm_bufio_client_destroy(v->bufio);
-
-       kfree(v->salt);
-       kfree(v->root_digest);
-
-       if (v->tfm)
-               crypto_free_shash(v->tfm);
-
-       kfree(v->alg_name);
-
-       if (v->hash_dev)
-               dm_put_device(ti, v->hash_dev);
-
-       if (v->data_dev)
-               dm_put_device(ti, v->data_dev);
-
-       kfree(v);
-}
-
-/*
- * Target parameters:
- *     <version>       The current format is version 1.
- *                     Vsn 0 is compatible with original Chromium OS releases.
- *     <data device>
- *     <hash device>
- *     <data block size>
- *     <hash block size>
- *     <the number of data blocks>
- *     <hash start block>
- *     <algorithm>
- *     <digest>
- *     <salt>          Hex string or "-" if no salt.
- */
-static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
-{
-       struct dm_verity *v;
-       struct dm_arg_set as;
-       const char *opt_string;
-       unsigned int num, opt_params;
-       unsigned long long num_ll;
-       int r;
-       int i;
-       sector_t hash_position;
-       char dummy;
-
-       static struct dm_arg _args[] = {
-               {0, 1, "Invalid number of feature args"},
-       };
-
-       v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
-       if (!v) {
-               ti->error = "Cannot allocate verity structure";
-               return -ENOMEM;
-       }
-       ti->private = v;
-       v->ti = ti;
-
-       if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
-               ti->error = "Device must be readonly";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (argc < 10) {
-               ti->error = "Not enough arguments";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
-           num > 1) {
-               ti->error = "Invalid version";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->version = num;
-
-       r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
-       if (r) {
-               ti->error = "Data device lookup failed";
-               goto bad;
-       }
-
-       r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
-       if (r) {
-               ti->error = "Data device lookup failed";
-               goto bad;
-       }
-
-       if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
-           !num || (num & (num - 1)) ||
-           num < bdev_logical_block_size(v->data_dev->bdev) ||
-           num > PAGE_SIZE) {
-               ti->error = "Invalid data device block size";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->data_dev_block_bits = __ffs(num);
-
-       if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
-           !num || (num & (num - 1)) ||
-           num < bdev_logical_block_size(v->hash_dev->bdev) ||
-           num > INT_MAX) {
-               ti->error = "Invalid hash device block size";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->hash_dev_block_bits = __ffs(num);
-
-       if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
-           (sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
-           >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll) {
-               ti->error = "Invalid data blocks";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->data_blocks = num_ll;
-
-       if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
-               ti->error = "Data device is too small";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
-           (sector_t)(num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT))
-           >> (v->hash_dev_block_bits - SECTOR_SHIFT) != num_ll) {
-               ti->error = "Invalid hash start";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->hash_start = num_ll;
-
-       v->alg_name = kstrdup(argv[7], GFP_KERNEL);
-       if (!v->alg_name) {
-               ti->error = "Cannot allocate algorithm name";
-               r = -ENOMEM;
-               goto bad;
-       }
-
-       v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
-       if (IS_ERR(v->tfm)) {
-               ti->error = "Cannot initialize hash function";
-               r = PTR_ERR(v->tfm);
-               v->tfm = NULL;
-               goto bad;
-       }
-       v->digest_size = crypto_shash_digestsize(v->tfm);
-       if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
-               ti->error = "Digest size too big";
-               r = -EINVAL;
-               goto bad;
-       }
-       v->shash_descsize =
-               sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
-
-       v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
-       if (!v->root_digest) {
-               ti->error = "Cannot allocate root digest";
-               r = -ENOMEM;
-               goto bad;
-       }
-       if (strlen(argv[8]) != v->digest_size * 2 ||
-           hex2bin(v->root_digest, argv[8], v->digest_size)) {
-               ti->error = "Invalid root digest";
-               r = -EINVAL;
-               goto bad;
-       }
-
-       if (strcmp(argv[9], "-")) {
-               v->salt_size = strlen(argv[9]) / 2;
-               v->salt = kmalloc(v->salt_size, GFP_KERNEL);
-               if (!v->salt) {
-                       ti->error = "Cannot allocate salt";
-                       r = -ENOMEM;
-                       goto bad;
-               }
-               if (strlen(argv[9]) != v->salt_size * 2 ||
-                   hex2bin(v->salt, argv[9], v->salt_size)) {
-                       ti->error = "Invalid salt";
-                       r = -EINVAL;
-                       goto bad;
-               }
-       }
-
-       argv += 10;
-       argc -= 10;
-
-       /* Optional parameters */
-       if (argc) {
-               as.argc = argc;
-               as.argv = argv;
-
-               r = dm_read_arg_group(_args, &as, &opt_params, &ti->error);
-               if (r)
-                       goto bad;
-
-               while (opt_params) {
-                       opt_params--;
-                       opt_string = dm_shift_arg(&as);
-                       if (!opt_string) {
-                               ti->error = "Not enough feature arguments";
-                               r = -EINVAL;
-                               goto bad;
-                       }
-
-                       if (!strcasecmp(opt_string, DM_VERITY_OPT_LOGGING))
-                               v->mode = DM_VERITY_MODE_LOGGING;
-                       else if (!strcasecmp(opt_string, DM_VERITY_OPT_RESTART))
-                               v->mode = DM_VERITY_MODE_RESTART;
-                       else {
-                               ti->error = "Invalid feature arguments";
-                               r = -EINVAL;
-                               goto bad;
-                       }
-               }
-       }
-
-       v->hash_per_block_bits =
-               __fls((1 << v->hash_dev_block_bits) / v->digest_size);
-
-       v->levels = 0;
-       if (v->data_blocks)
-               while (v->hash_per_block_bits * v->levels < 64 &&
-                      (unsigned long long)(v->data_blocks - 1) >>
-                      (v->hash_per_block_bits * v->levels))
-                       v->levels++;
-
-       if (v->levels > DM_VERITY_MAX_LEVELS) {
-               ti->error = "Too many tree levels";
-               r = -E2BIG;
-               goto bad;
-       }
-
-       hash_position = v->hash_start;
-       for (i = v->levels - 1; i >= 0; i--) {
-               sector_t s;
-               v->hash_level_block[i] = hash_position;
-               s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
-                                       >> ((i + 1) * v->hash_per_block_bits);
-               if (hash_position + s < hash_position) {
-                       ti->error = "Hash device offset overflow";
-                       r = -E2BIG;
-                       goto bad;
-               }
-               hash_position += s;
-       }
-       v->hash_blocks = hash_position;
-
-       v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
-               1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
-               dm_bufio_alloc_callback, NULL);
-       if (IS_ERR(v->bufio)) {
-               ti->error = "Cannot initialize dm-bufio";
-               r = PTR_ERR(v->bufio);
-               v->bufio = NULL;
-               goto bad;
-       }
-
-       if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
-               ti->error = "Hash device is too small";
-               r = -E2BIG;
-               goto bad;
-       }
-
-       ti->per_bio_data_size = roundup(sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2, __alignof__(struct dm_verity_io));
-
-       /* WQ_UNBOUND greatly improves performance when running on ramdisk */
-       v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
-       if (!v->verify_wq) {
-               ti->error = "Cannot allocate workqueue";
-               r = -ENOMEM;
-               goto bad;
-       }
-
-       return 0;
-
-bad:
-       verity_dtr(ti);
-
-       return r;
-}
-
-static struct target_type verity_target = {
-       .name           = "verity",
-       .version        = {1, 2, 0},
-       .module         = THIS_MODULE,
-       .ctr            = verity_ctr,
-       .dtr            = verity_dtr,
-       .map            = verity_map,
-       .status         = verity_status,
-       .prepare_ioctl  = verity_prepare_ioctl,
-       .iterate_devices = verity_iterate_devices,
-       .io_hints       = verity_io_hints,
-};
-
-static int __init dm_verity_init(void)
-{
-       int r;
-
-       r = dm_register_target(&verity_target);
-       if (r < 0)
-               DMERR("register failed %d", r);
-
-       return r;
-}
-
-static void __exit dm_verity_exit(void)
-{
-       dm_unregister_target(&verity_target);
-}
-
-module_init(dm_verity_init);
-module_exit(dm_verity_exit);
-
-MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
-MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
-MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
-MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
-MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
new file mode 100644 (file)
index 0000000..fb419f4
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef DM_VERITY_H
+#define DM_VERITY_H
+
+#include "dm-bufio.h"
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+
+#define DM_VERITY_MAX_LEVELS           63
+
+enum verity_mode {
+       DM_VERITY_MODE_EIO,
+       DM_VERITY_MODE_LOGGING,
+       DM_VERITY_MODE_RESTART
+};
+
+enum verity_block_type {
+       DM_VERITY_BLOCK_TYPE_DATA,
+       DM_VERITY_BLOCK_TYPE_METADATA
+};
+
+struct dm_verity_fec;
+
+struct dm_verity {
+       struct dm_dev *data_dev;
+       struct dm_dev *hash_dev;
+       struct dm_target *ti;
+       struct dm_bufio_client *bufio;
+       char *alg_name;
+       struct crypto_shash *tfm;
+       u8 *root_digest;        /* digest of the root block */
+       u8 *salt;               /* salt: its size is salt_size */
+       u8 *zero_digest;        /* digest for a zero block */
+       unsigned salt_size;
+       sector_t data_start;    /* data offset in 512-byte sectors */
+       sector_t hash_start;    /* hash start in blocks */
+       sector_t data_blocks;   /* the number of data blocks */
+       sector_t hash_blocks;   /* the number of hash blocks */
+       unsigned char data_dev_block_bits;      /* log2(data blocksize) */
+       unsigned char hash_dev_block_bits;      /* log2(hash blocksize) */
+       unsigned char hash_per_block_bits;      /* log2(hashes in hash block) */
+       unsigned char levels;   /* the number of tree levels */
+       unsigned char version;
+       unsigned digest_size;   /* digest size for the current hash algorithm */
+       unsigned shash_descsize;/* the size of temporary space for crypto */
+       int hash_failed;        /* set to 1 if hash of any block failed */
+       enum verity_mode mode;  /* mode for handling verification errors */
+       unsigned corrupted_errs;/* Number of errors for corrupted blocks */
+
+       struct workqueue_struct *verify_wq;
+
+       /* starting blocks for each tree level. 0 is the lowest level. */
+       sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+
+       struct dm_verity_fec *fec;      /* forward error correction */
+};
+
+struct dm_verity_io {
+       struct dm_verity *v;
+
+       /* original value of bio->bi_end_io */
+       bio_end_io_t *orig_bi_end_io;
+
+       sector_t block;
+       unsigned n_blocks;
+
+       struct bvec_iter iter;
+
+       struct work_struct work;
+
+       /*
+        * Three variably-size fields follow this struct:
+        *
+        * u8 hash_desc[v->shash_descsize];
+        * u8 real_digest[v->digest_size];
+        * u8 want_digest[v->digest_size];
+        *
+        * To access them use: verity_io_hash_desc(), verity_io_real_digest()
+        * and verity_io_want_digest().
+        */
+};
+
+static inline struct shash_desc *verity_io_hash_desc(struct dm_verity *v,
+                                                    struct dm_verity_io *io)
+{
+       return (struct shash_desc *)(io + 1);
+}
+
+static inline u8 *verity_io_real_digest(struct dm_verity *v,
+                                       struct dm_verity_io *io)
+{
+       return (u8 *)(io + 1) + v->shash_descsize;
+}
+
+static inline u8 *verity_io_want_digest(struct dm_verity *v,
+                                       struct dm_verity_io *io)
+{
+       return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
+}
+
+static inline u8 *verity_io_digest_end(struct dm_verity *v,
+                                      struct dm_verity_io *io)
+{
+       return verity_io_want_digest(v, io) + v->digest_size;
+}
+
+extern int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
+                              struct bvec_iter *iter,
+                              int (*process)(struct dm_verity *v,
+                                             struct dm_verity_io *io,
+                                             u8 *data, size_t len));
+
+extern int verity_hash(struct dm_verity *v, struct shash_desc *desc,
+                      const u8 *data, size_t len, u8 *digest);
+
+extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
+                                sector_t block, u8 *digest, bool *is_zero);
+
+#endif /* DM_VERITY_H */
index dd834927bc66e87bf4ec433bc96889068d3bbb82..c338aebb4ccd54aa2ee40febd1103e1852b83b82 100644 (file)
@@ -1109,12 +1109,8 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
         * back into ->request_fn() could deadlock attempting to grab the
         * queue lock again.
         */
-       if (run_queue) {
-               if (md->queue->mq_ops)
-                       blk_mq_run_hw_queues(md->queue, true);
-               else
-                       blk_run_queue_async(md->queue);
-       }
+       if (!md->queue->mq_ops && run_queue)
+               blk_run_queue_async(md->queue);
 
        /*
         * dm_put() must be at the end of this function. See the comment above
@@ -1214,9 +1210,9 @@ static void dm_requeue_original_request(struct mapped_device *md,
 {
        int rw = rq_data_dir(rq);
 
+       rq_end_stats(md, rq);
        dm_unprep_request(rq);
 
-       rq_end_stats(md, rq);
        if (!rq->q->mq_ops)
                old_requeue_request(rq);
        else {
@@ -1336,7 +1332,10 @@ static void dm_complete_request(struct request *rq, int error)
        struct dm_rq_target_io *tio = tio_from_request(rq);
 
        tio->error = error;
-       blk_complete_request(rq);
+       if (!rq->q->mq_ops)
+               blk_complete_request(rq);
+       else
+               blk_mq_complete_request(rq, error);
 }
 
 /*
index b1e1f6b9578246c3a834a4c1e75ef8f6972045e6..c57fdf847b4767bb86c8b42548fe221785fd9b2e 100644 (file)
@@ -293,6 +293,8 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
         * go away inside make_request
         */
        sectors = bio_sectors(bio);
+       /* bio could be mergeable after passing to underlayer */
+       bio->bi_rw &= ~REQ_NOMERGE;
        mddev->pers->make_request(mddev, bio);
 
        cpu = part_stat_lock();
index 0a72ab6e6c204a6a1a56d7dff922753bb6294c76..dd483bb2e111ee400eee173b4a21846332e53977 100644 (file)
@@ -129,7 +129,9 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
        }
        multipath = conf->multipaths + mp_bh->path;
 
-       mp_bh->bio = *bio;
+       bio_init(&mp_bh->bio);
+       __bio_clone_fast(&mp_bh->bio, bio);
+
        mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset;
        mp_bh->bio.bi_bdev = multipath->rdev->bdev;
        mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT;
index c4b9134092260f22939027a0a82945b146a4ebf9..515554c7365b19400e6bbd0f8c2672c12e77feab 100644 (file)
@@ -2274,6 +2274,7 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
        if (fail) {
                spin_lock_irq(&conf->device_lock);
                list_add(&r1_bio->retry_list, &conf->bio_end_io_list);
+               conf->nr_queued++;
                spin_unlock_irq(&conf->device_lock);
                md_wakeup_thread(conf->mddev->thread);
        } else {
@@ -2391,8 +2392,10 @@ static void raid1d(struct md_thread *thread)
                LIST_HEAD(tmp);
                spin_lock_irqsave(&conf->device_lock, flags);
                if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) {
-                       list_add(&tmp, &conf->bio_end_io_list);
-                       list_del_init(&conf->bio_end_io_list);
+                       while (!list_empty(&conf->bio_end_io_list)) {
+                               list_move(conf->bio_end_io_list.prev, &tmp);
+                               conf->nr_queued--;
+                       }
                }
                spin_unlock_irqrestore(&conf->device_lock, flags);
                while (!list_empty(&tmp)) {
index ce959b4ae4dfd9a09d33828f5706d3a6aadd7f71..ebb0dd612ebdf1d19d75e66950abb496536fcb12 100644 (file)
@@ -2664,6 +2664,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
                if (fail) {
                        spin_lock_irq(&conf->device_lock);
                        list_add(&r10_bio->retry_list, &conf->bio_end_io_list);
+                       conf->nr_queued++;
                        spin_unlock_irq(&conf->device_lock);
                        md_wakeup_thread(conf->mddev->thread);
                } else {
@@ -2691,8 +2692,10 @@ static void raid10d(struct md_thread *thread)
                LIST_HEAD(tmp);
                spin_lock_irqsave(&conf->device_lock, flags);
                if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) {
-                       list_add(&tmp, &conf->bio_end_io_list);
-                       list_del_init(&conf->bio_end_io_list);
+                       while (!list_empty(&conf->bio_end_io_list)) {
+                               list_move(conf->bio_end_io_list.prev, &tmp);
+                               conf->nr_queued--;
+                       }
                }
                spin_unlock_irqrestore(&conf->device_lock, flags);
                while (!list_empty(&tmp)) {
index 704ef7fcfbf83239ff7ac119d37354576dea5221..10ce885445f61dc162159b4fb7bb77c55d28e64b 100644 (file)
@@ -340,8 +340,7 @@ static void release_inactive_stripe_list(struct r5conf *conf,
                                         int hash)
 {
        int size;
-       unsigned long do_wakeup = 0;
-       int i = 0;
+       bool do_wakeup = false;
        unsigned long flags;
 
        if (hash == NR_STRIPE_HASH_LOCKS) {
@@ -362,19 +361,15 @@ static void release_inactive_stripe_list(struct r5conf *conf,
                            !list_empty(list))
                                atomic_dec(&conf->empty_inactive_list_nr);
                        list_splice_tail_init(list, conf->inactive_list + hash);
-                       do_wakeup |= 1 << hash;
+                       do_wakeup = true;
                        spin_unlock_irqrestore(conf->hash_locks + hash, flags);
                }
                size--;
                hash--;
        }
 
-       for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
-               if (do_wakeup & (1 << i))
-                       wake_up(&conf->wait_for_stripe[i]);
-       }
-
        if (do_wakeup) {
+               wake_up(&conf->wait_for_stripe);
                if (atomic_read(&conf->active_stripes) == 0)
                        wake_up(&conf->wait_for_quiescent);
                if (conf->retry_read_aligned)
@@ -687,15 +682,14 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector,
                        if (!sh) {
                                set_bit(R5_INACTIVE_BLOCKED,
                                        &conf->cache_state);
-                               wait_event_exclusive_cmd(
-                                       conf->wait_for_stripe[hash],
+                               wait_event_lock_irq(
+                                       conf->wait_for_stripe,
                                        !list_empty(conf->inactive_list + hash) &&
                                        (atomic_read(&conf->active_stripes)
                                         < (conf->max_nr_stripes * 3 / 4)
                                         || !test_bit(R5_INACTIVE_BLOCKED,
                                                      &conf->cache_state)),
-                                       spin_unlock_irq(conf->hash_locks + hash),
-                                       spin_lock_irq(conf->hash_locks + hash));
+                                       *(conf->hash_locks + hash));
                                clear_bit(R5_INACTIVE_BLOCKED,
                                          &conf->cache_state);
                        } else {
@@ -720,9 +714,6 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector,
                }
        } while (sh == NULL);
 
-       if (!list_empty(conf->inactive_list + hash))
-               wake_up(&conf->wait_for_stripe[hash]);
-
        spin_unlock_irq(conf->hash_locks + hash);
        return sh;
 }
@@ -2091,6 +2082,14 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors)
        unsigned long cpu;
        int err = 0;
 
+       /*
+        * Never shrink. And mddev_suspend() could deadlock if this is called
+        * from raid5d. In that case, scribble_disks and scribble_sectors
+        * should equal to new_disks and new_sectors
+        */
+       if (conf->scribble_disks >= new_disks &&
+           conf->scribble_sectors >= new_sectors)
+               return 0;
        mddev_suspend(conf->mddev);
        get_online_cpus();
        for_each_present_cpu(cpu) {
@@ -2112,6 +2111,10 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors)
        }
        put_online_cpus();
        mddev_resume(conf->mddev);
+       if (!err) {
+               conf->scribble_disks = new_disks;
+               conf->scribble_sectors = new_sectors;
+       }
        return err;
 }
 
@@ -2192,7 +2195,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        cnt = 0;
        list_for_each_entry(nsh, &newstripes, lru) {
                lock_device_hash_lock(conf, hash);
-               wait_event_exclusive_cmd(conf->wait_for_stripe[hash],
+               wait_event_cmd(conf->wait_for_stripe,
                                    !list_empty(conf->inactive_list + hash),
                                    unlock_device_hash_lock(conf, hash),
                                    lock_device_hash_lock(conf, hash));
@@ -4238,7 +4241,6 @@ static void break_stripe_batch_list(struct stripe_head *head_sh,
                WARN_ON_ONCE(sh->state & ((1 << STRIPE_ACTIVE) |
                                          (1 << STRIPE_SYNCING) |
                                          (1 << STRIPE_REPLACED) |
-                                         (1 << STRIPE_PREREAD_ACTIVE) |
                                          (1 << STRIPE_DELAYED) |
                                          (1 << STRIPE_BIT_DELAY) |
                                          (1 << STRIPE_FULL_WRITE) |
@@ -4253,6 +4255,7 @@ static void break_stripe_batch_list(struct stripe_head *head_sh,
                                              (1 << STRIPE_REPLACED)));
 
                set_mask_bits(&sh->state, ~(STRIPE_EXPAND_SYNC_FLAGS |
+                                           (1 << STRIPE_PREREAD_ACTIVE) |
                                            (1 << STRIPE_DEGRADED)),
                              head_sh->state & (1 << STRIPE_INSYNC));
 
@@ -6414,6 +6417,12 @@ static int raid5_alloc_percpu(struct r5conf *conf)
        }
        put_online_cpus();
 
+       if (!err) {
+               conf->scribble_disks = max(conf->raid_disks,
+                       conf->previous_raid_disks);
+               conf->scribble_sectors = max(conf->chunk_sectors,
+                       conf->prev_chunk_sectors);
+       }
        return err;
 }
 
@@ -6504,9 +6513,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        seqcount_init(&conf->gen_lock);
        mutex_init(&conf->cache_size_mutex);
        init_waitqueue_head(&conf->wait_for_quiescent);
-       for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
-               init_waitqueue_head(&conf->wait_for_stripe[i]);
-       }
+       init_waitqueue_head(&conf->wait_for_stripe);
        init_waitqueue_head(&conf->wait_for_overlap);
        INIT_LIST_HEAD(&conf->handle_list);
        INIT_LIST_HEAD(&conf->hold_list);
@@ -7015,8 +7022,8 @@ static int run(struct mddev *mddev)
                }
 
                if (discard_supported &&
-                  mddev->queue->limits.max_discard_sectors >= stripe &&
-                  mddev->queue->limits.discard_granularity >= stripe)
+                   mddev->queue->limits.max_discard_sectors >= (stripe >> 9) &&
+                   mddev->queue->limits.discard_granularity >= stripe)
                        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
                                                mddev->queue);
                else
index a415e1cd39b8fd09e441e60c742baa1f59f9f88d..517d4b68a1befcad9e4b383c0ed077133d25b3b3 100644 (file)
@@ -510,6 +510,8 @@ struct r5conf {
                                              * conversions
                                              */
        } __percpu *percpu;
+       int scribble_disks;
+       int scribble_sectors;
 #ifdef CONFIG_HOTPLUG_CPU
        struct notifier_block   cpu_notify;
 #endif
@@ -522,7 +524,7 @@ struct r5conf {
        atomic_t                empty_inactive_list_nr;
        struct llist_head       released_stripes;
        wait_queue_head_t       wait_for_quiescent;
-       wait_queue_head_t       wait_for_stripe[NR_STRIPE_HASH_LOCKS];
+       wait_queue_head_t       wait_for_stripe;
        wait_queue_head_t       wait_for_overlap;
        unsigned long           cache_state;
 #define R5_INACTIVE_BLOCKED    1       /* release of inactive stripes blocked,
index e4900df1140b9b10a729570aa075943e4beccee3..c24839cfcc3565ca83de9f4e6aeba8a9d57d46a2 100644 (file)
@@ -1161,12 +1161,23 @@ static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, in
        }
 }
 
+static void adv7511_notify_no_edid(struct v4l2_subdev *sd)
+{
+       struct adv7511_state *state = get_adv7511_state(sd);
+       struct adv7511_edid_detect ed;
+
+       /* We failed to read the EDID, so send an event for this. */
+       ed.present = false;
+       ed.segment = adv7511_rd(sd, 0xc4);
+       v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
+       v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0);
+}
+
 static void adv7511_edid_handler(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
        struct adv7511_state *state = container_of(dwork, struct adv7511_state, edid_handler);
        struct v4l2_subdev *sd = &state->sd;
-       struct adv7511_edid_detect ed;
 
        v4l2_dbg(1, debug, sd, "%s:\n", __func__);
 
@@ -1191,9 +1202,7 @@ static void adv7511_edid_handler(struct work_struct *work)
        }
 
        /* We failed to read the EDID, so send an event for this. */
-       ed.present = false;
-       ed.segment = adv7511_rd(sd, 0xc4);
-       v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
+       adv7511_notify_no_edid(sd);
        v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__);
 }
 
@@ -1264,7 +1273,6 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
        /* update read only ctrls */
        v4l2_ctrl_s_ctrl(state->hotplug_ctrl, adv7511_have_hotplug(sd) ? 0x1 : 0x0);
        v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, adv7511_have_rx_sense(sd) ? 0x1 : 0x0);
-       v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
 
        if ((status & MASK_ADV7511_HPD_DETECT) && ((status & MASK_ADV7511_MSEN_DETECT) || state->edid.segments)) {
                v4l2_dbg(1, debug, sd, "%s: hotplug and (rx-sense or edid)\n", __func__);
@@ -1294,6 +1302,7 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
                }
                adv7511_s_power(sd, false);
                memset(&state->edid, 0, sizeof(struct adv7511_state_edid));
+               adv7511_notify_no_edid(sd);
        }
 }
 
@@ -1370,6 +1379,7 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
                }
                /* one more segment read ok */
                state->edid.segments = segment + 1;
+               v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x1);
                if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
                        /* Request next EDID segment */
                        v4l2_dbg(1, debug, sd, "%s: request segment %d\n", __func__, state->edid.segments);
@@ -1389,7 +1399,6 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
                ed.present = true;
                ed.segment = 0;
                state->edid_detect_counter++;
-               v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
                v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
                return ed.present;
        }
index 15a4ebc2844d4f5882ea31cdf80c0f648b04a751..51dbef2f9a4899e641b6fb315af8c0014f888577 100644 (file)
@@ -2334,6 +2334,19 @@ static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
        return 0;
 }
 
+static void bttv_get_width_mask_vid_cap(const struct bttv_format *fmt,
+                                       unsigned int *width_mask,
+                                       unsigned int *width_bias)
+{
+       if (fmt->flags & FORMAT_FLAGS_PLANAR) {
+               *width_mask = ~15; /* width must be a multiple of 16 pixels */
+               *width_bias = 8;   /* nearest */
+       } else {
+               *width_mask = ~3; /* width must be a multiple of 4 pixels */
+               *width_bias = 2;  /* nearest */
+       }
+}
+
 static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
                                                struct v4l2_format *f)
 {
@@ -2343,6 +2356,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
        enum v4l2_field field;
        __s32 width, height;
        __s32 height2;
+       unsigned int width_mask, width_bias;
        int rc;
 
        fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2375,9 +2389,9 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
        width = f->fmt.pix.width;
        height = f->fmt.pix.height;
 
+       bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
        rc = limit_scaled_size_lock(fh, &width, &height, field,
-                              /* width_mask: 4 pixels */ ~3,
-                              /* width_bias: nearest */ 2,
+                              width_mask, width_bias,
                               /* adjust_size */ 1,
                               /* adjust_crop */ 0);
        if (0 != rc)
@@ -2410,6 +2424,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
        struct bttv_fh *fh = priv;
        struct bttv *btv = fh->btv;
        __s32 width, height;
+       unsigned int width_mask, width_bias;
        enum v4l2_field field;
 
        retval = bttv_switch_type(fh, f->type);
@@ -2424,9 +2439,10 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
        height = f->fmt.pix.height;
        field = f->fmt.pix.field;
 
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       bttv_get_width_mask_vid_cap(fmt, &width_mask, &width_bias);
        retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
-                              /* width_mask: 4 pixels */ ~3,
-                              /* width_bias: nearest */ 2,
+                              width_mask, width_bias,
                               /* adjust_size */ 1,
                               /* adjust_crop */ 1);
        if (0 != retval)
@@ -2434,8 +2450,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.field = field;
 
-       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-
        /* update our state informations */
        fh->fmt              = fmt;
        fh->cap.field        = f->fmt.pix.field;
index 518086c7aed5cb2bc26e0c873231327e14018ca2..15e56c07b217566ff28e01d616348bfbf9a8bc0e 100644 (file)
@@ -1219,10 +1219,13 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
        f->fmt.pix.height       = dev->height;
        f->fmt.pix.field        = dev->field;
        f->fmt.pix.pixelformat  = dev->fmt->fourcc;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * dev->fmt->depth) >> 3;
+       if (dev->fmt->planar)
+               f->fmt.pix.bytesperline = f->fmt.pix.width;
+       else
+               f->fmt.pix.bytesperline =
+                       (f->fmt.pix.width * dev->fmt->depth) / 8;
        f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
+               (f->fmt.pix.height * f->fmt.pix.width * dev->fmt->depth) / 8;
        f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
        return 0;
 }
@@ -1298,10 +1301,13 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
        if (f->fmt.pix.height > maxh)
                f->fmt.pix.height = maxh;
        f->fmt.pix.width &= ~0x03;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fmt->depth) >> 3;
+       if (fmt->planar)
+               f->fmt.pix.bytesperline = f->fmt.pix.width;
+       else
+               f->fmt.pix.bytesperline =
+                       (f->fmt.pix.width * fmt->depth) / 8;
        f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
+               (f->fmt.pix.height * f->fmt.pix.width * fmt->depth) / 8;
        f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
 
        return 0;
index 654e964f84a2f4eac941a204b03de0ace256b2f4..d76511c1c1e3f13f1065f97e64e0e239b594aca3 100644 (file)
@@ -1342,7 +1342,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
 
        /* Calculate bytesused field */
        if (dst_buf->sequence == 0) {
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0,
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr +
                                        ctx->vpu_header_size[0] +
                                        ctx->vpu_header_size[1] +
                                        ctx->vpu_header_size[2]);
index 15516a6e3a3916c090762d360ee10fdaeba0efbc..323aad3c89de687a580ec15694ae7d59b8b3d1f9 100644 (file)
@@ -2119,14 +2119,12 @@ static int coda_probe(struct platform_device *pdev)
 
        pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
 
-       if (of_id) {
+       if (of_id)
                dev->devtype = of_id->data;
-       } else if (pdev_id) {
+       else if (pdev_id)
                dev->devtype = &coda_devdata[pdev_id->driver_data];
-       } else {
-               ret = -EINVAL;
-               goto err_v4l2_register;
-       }
+       else
+               return -EINVAL;
 
        spin_lock_init(&dev->irqlock);
        INIT_LIST_HEAD(&dev->instances);
index 6310acab60e79b3d97978950ce97c3155fed2b29..d41ae950d1a13a923a1f3d372a5ffa1884435ae6 100644 (file)
@@ -154,6 +154,7 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
        mutex_lock(sru->ctrls.lock);
        ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
               & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
+       vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
        mutex_unlock(sru->ctrls.lock);
 
        vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
index 0934024fb89d37b00ca01233a59bf76e4ec7acab..d91ded795c93b9da8e0fcf00fcd20ae723df621e 100644 (file)
@@ -159,7 +159,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
           Set the status so poll routines can check and avoid
           access after disconnect.
        */
-       dev->dev_state = DEV_DISCONNECTED;
+       set_bit(DEV_DISCONNECTED, &dev->dev_state);
 
        au0828_rc_unregister(dev);
        /* Digital TV */
index b0f0679719798c4b8212b9dabee3f992b018c17a..3d6687f0407dfe4c301ca2e9f4bca594c9201522 100644 (file)
@@ -130,7 +130,7 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
        bool first = true;
 
        /* do nothing if device is disconnected */
-       if (ir->dev->dev_state == DEV_DISCONNECTED)
+       if (test_bit(DEV_DISCONNECTED, &ir->dev->dev_state))
                return 0;
 
        /* Check IR int */
@@ -260,7 +260,7 @@ static void au0828_rc_stop(struct rc_dev *rc)
        cancel_delayed_work_sync(&ir->work);
 
        /* do nothing if device is disconnected */
-       if (ir->dev->dev_state != DEV_DISCONNECTED) {
+       if (!test_bit(DEV_DISCONNECTED, &ir->dev->dev_state)) {
                /* Disable IR */
                au8522_rc_clear(ir, 0xe0, 1 << 4);
        }
index 45c622e234f7fb4bade7608cfdda352f908b608e..7b2fe1b56039e5edd78b9a5ec55fd7a0cb42ec79 100644 (file)
@@ -104,14 +104,13 @@ static inline void print_err_status(struct au0828_dev *dev,
 
 static int check_dev(struct au0828_dev *dev)
 {
-       if (dev->dev_state & DEV_DISCONNECTED) {
+       if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) {
                pr_info("v4l2 ioctl: device not present\n");
                return -ENODEV;
        }
 
-       if (dev->dev_state & DEV_MISCONFIGURED) {
-               pr_info("v4l2 ioctl: device is misconfigured; "
-                      "close and open it again\n");
+       if (test_bit(DEV_MISCONFIGURED, &dev->dev_state)) {
+               pr_info("v4l2 ioctl: device is misconfigured; close and open it again\n");
                return -EIO;
        }
        return 0;
@@ -519,8 +518,8 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
        if (!dev)
                return 0;
 
-       if ((dev->dev_state & DEV_DISCONNECTED) ||
-           (dev->dev_state & DEV_MISCONFIGURED))
+       if (test_bit(DEV_DISCONNECTED, &dev->dev_state) ||
+           test_bit(DEV_MISCONFIGURED, &dev->dev_state))
                return 0;
 
        if (urb->status < 0) {
@@ -766,10 +765,10 @@ static int au0828_stream_interrupt(struct au0828_dev *dev)
        int ret = 0;
 
        dev->stream_state = STREAM_INTERRUPT;
-       if (dev->dev_state == DEV_DISCONNECTED)
+       if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
                return -ENODEV;
        else if (ret) {
-               dev->dev_state = DEV_MISCONFIGURED;
+               set_bit(DEV_MISCONFIGURED, &dev->dev_state);
                dprintk(1, "%s device is misconfigured!\n", __func__);
                return ret;
        }
@@ -958,7 +957,7 @@ static int au0828_v4l2_open(struct file *filp)
        int ret;
 
        dprintk(1,
-               "%s called std_set %d dev_state %d stream users %d users %d\n",
+               "%s called std_set %d dev_state %ld stream users %d users %d\n",
                __func__, dev->std_set_in_tuner_core, dev->dev_state,
                dev->streaming_users, dev->users);
 
@@ -977,7 +976,7 @@ static int au0828_v4l2_open(struct file *filp)
                au0828_analog_stream_enable(dev);
                au0828_analog_stream_reset(dev);
                dev->stream_state = STREAM_OFF;
-               dev->dev_state |= DEV_INITIALIZED;
+               set_bit(DEV_INITIALIZED, &dev->dev_state);
        }
        dev->users++;
        mutex_unlock(&dev->lock);
@@ -991,7 +990,7 @@ static int au0828_v4l2_close(struct file *filp)
        struct video_device *vdev = video_devdata(filp);
 
        dprintk(1,
-               "%s called std_set %d dev_state %d stream users %d users %d\n",
+               "%s called std_set %d dev_state %ld stream users %d users %d\n",
                __func__, dev->std_set_in_tuner_core, dev->dev_state,
                dev->streaming_users, dev->users);
 
@@ -1007,7 +1006,7 @@ static int au0828_v4l2_close(struct file *filp)
                del_timer_sync(&dev->vbi_timeout);
        }
 
-       if (dev->dev_state == DEV_DISCONNECTED)
+       if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
                goto end;
 
        if (dev->users == 1) {
@@ -1036,7 +1035,7 @@ static void au0828_init_tuner(struct au0828_dev *dev)
                .type = V4L2_TUNER_ANALOG_TV,
        };
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        if (dev->std_set_in_tuner_core)
@@ -1108,7 +1107,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
        struct video_device *vdev = video_devdata(file);
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        strlcpy(cap->driver, "au0828", sizeof(cap->driver));
@@ -1151,7 +1150,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        f->fmt.pix.width = dev->width;
@@ -1170,7 +1169,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
@@ -1182,7 +1181,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct au0828_dev *dev = video_drvdata(file);
        int rc;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        rc = check_dev(dev);
@@ -1204,7 +1203,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        if (norm == dev->std)
@@ -1236,7 +1235,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        *norm = dev->std;
@@ -1259,7 +1258,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
                [AU0828_VMUX_DEBUG] = "tv debug"
        };
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        tmp = input->index;
@@ -1289,7 +1288,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        *i = dev->ctrl_input;
@@ -1300,7 +1299,7 @@ static void au0828_s_input(struct au0828_dev *dev, int index)
 {
        int i;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        switch (AUVI_INPUT(index).type) {
@@ -1385,7 +1384,7 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        a->index = dev->ctrl_ainput;
@@ -1405,7 +1404,7 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
        if (a->index != dev->ctrl_ainput)
                return -EINVAL;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
        return 0;
 }
@@ -1417,7 +1416,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
        if (t->index != 0)
                return -EINVAL;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        strcpy(t->name, "Auvitek tuner");
@@ -1437,7 +1436,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
        if (t->index != 0)
                return -EINVAL;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        au0828_init_tuner(dev);
@@ -1459,7 +1458,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
        if (freq->tuner != 0)
                return -EINVAL;
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
        freq->frequency = dev->ctrl_freq;
        return 0;
@@ -1474,7 +1473,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        if (freq->tuner != 0)
                return -EINVAL;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        au0828_init_tuner(dev);
@@ -1500,7 +1499,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        format->fmt.vbi.samples_per_line = dev->vbi_width;
@@ -1526,7 +1525,7 @@ static int vidioc_cropcap(struct file *file, void *priv,
        if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        cc->bounds.left = 0;
@@ -1548,7 +1547,7 @@ static int vidioc_g_register(struct file *file, void *priv,
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        reg->val = au0828_read(dev, reg->reg);
@@ -1561,7 +1560,7 @@ static int vidioc_s_register(struct file *file, void *priv,
 {
        struct au0828_dev *dev = video_drvdata(file);
 
-       dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+       dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
                dev->std_set_in_tuner_core, dev->dev_state);
 
        return au0828_writereg(dev, reg->reg, reg->val);
index 60b59391ea2ae48eee40cd124ade5c4ea50ca309..d1b6405a05a44648c3dca2ad733c5552d0001c52 100644 (file)
@@ -21,6 +21,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/bitops.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -122,9 +123,9 @@ enum au0828_stream_state {
 
 /* device state */
 enum au0828_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04
+       DEV_INITIALIZED = 0,
+       DEV_DISCONNECTED = 1,
+       DEV_MISCONFIGURED = 2
 };
 
 struct au0828_dev;
@@ -248,7 +249,7 @@ struct au0828_dev {
        int input_type;
        int std_set_in_tuner_core;
        unsigned int ctrl_input;
-       enum au0828_dev_state dev_state;
+       long unsigned int dev_state; /* defined at enum au0828_dev_state */;
        enum au0828_stream_state stream_state;
        wait_queue_head_t open;
 
index b79c36fd8cd24c66d441c5b807cb65a65b6673f6..58f23bcfe94ecc01966d746269c42049aa30d143 100644 (file)
@@ -91,6 +91,7 @@ static const struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x0471, 0x0312) },
        { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
        { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
+       { USB_DEVICE(0x0471, 0x032C) }, /* Philips SPC 880NC PC Camera */
        { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
        { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
        { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -811,6 +812,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        name = "Philips SPC 900NC webcam";
                        type_id = 740;
                        break;
+               case 0x032C:
+                       PWC_INFO("Philips SPC 880NC USB webcam detected.\n");
+                       name = "Philips SPC 880NC webcam";
+                       type_id = 740;
+                       break;
                default:
                        return -ENODEV;
                        break;
index b693206f66dd3d05462aa59f88bd6445aaed88f4..d1dc1a198e3ed0894e1efce9c1a4f14f3a74295b 100644 (file)
@@ -1463,9 +1463,23 @@ static int usbvision_probe(struct usb_interface *intf,
 
        if (usbvision_device_data[model].interface >= 0)
                interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
-       else
+       else if (ifnum < dev->actconfig->desc.bNumInterfaces)
                interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+       else {
+               dev_err(&intf->dev, "interface %d is invalid, max is %d\n",
+                   ifnum, dev->actconfig->desc.bNumInterfaces - 1);
+               ret = -ENODEV;
+               goto err_usb;
+       }
+
+       if (interface->desc.bNumEndpoints < 2) {
+               dev_err(&intf->dev, "interface %d has %d endpoints, but must"
+                   " have minimum 2\n", ifnum, interface->desc.bNumEndpoints);
+               ret = -ENODEV;
+               goto err_usb;
+       }
        endpoint = &interface->endpoint[1].desc;
+
        if (!usb_endpoint_xfer_isoc(endpoint)) {
                dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
                    __func__, ifnum);
index 8fd84a67478a77423cc6bc051e0654276561502c..019644ff627d775f7f4b67e29b46baab9dadabbf 100644 (file)
@@ -415,7 +415,8 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                get_user(kp->index, &up->index) ||
                get_user(kp->type, &up->type) ||
                get_user(kp->flags, &up->flags) ||
-               get_user(kp->memory, &up->memory))
+               get_user(kp->memory, &up->memory) ||
+               get_user(kp->length, &up->length))
                        return -EFAULT;
 
        if (V4L2_TYPE_IS_OUTPUT(kp->type))
@@ -427,9 +428,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                        return -EFAULT;
 
        if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-               if (get_user(kp->length, &up->length))
-                       return -EFAULT;
-
                num_planes = kp->length;
                if (num_planes == 0) {
                        kp->m.planes = NULL;
@@ -462,16 +460,14 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
        } else {
                switch (kp->memory) {
                case V4L2_MEMORY_MMAP:
-                       if (get_user(kp->length, &up->length) ||
-                               get_user(kp->m.offset, &up->m.offset))
+                       if (get_user(kp->m.offset, &up->m.offset))
                                return -EFAULT;
                        break;
                case V4L2_MEMORY_USERPTR:
                        {
                        compat_long_t tmp;
 
-                       if (get_user(kp->length, &up->length) ||
-                           get_user(tmp, &up->m.userptr))
+                       if (get_user(tmp, &up->m.userptr))
                                return -EFAULT;
 
                        kp->m.userptr = (unsigned long)compat_ptr(tmp);
@@ -513,7 +509,8 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
                put_user(kp->sequence, &up->sequence) ||
                put_user(kp->reserved2, &up->reserved2) ||
-               put_user(kp->reserved, &up->reserved))
+               put_user(kp->reserved, &up->reserved) ||
+               put_user(kp->length, &up->length))
                        return -EFAULT;
 
        if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
@@ -536,13 +533,11 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
        } else {
                switch (kp->memory) {
                case V4L2_MEMORY_MMAP:
-                       if (put_user(kp->length, &up->length) ||
-                               put_user(kp->m.offset, &up->m.offset))
+                       if (put_user(kp->m.offset, &up->m.offset))
                                return -EFAULT;
                        break;
                case V4L2_MEMORY_USERPTR:
-                       if (put_user(kp->length, &up->length) ||
-                               put_user(kp->m.userptr, &up->m.userptr))
+                       if (put_user(kp->m.userptr, &up->m.userptr))
                                return -EFAULT;
                        break;
                case V4L2_MEMORY_OVERLAY:
index 33bdd81065e81cd66de55fd533d8bda86b0c678f..11f39791ec3391f349ee5a0a008daa69166ad409 100644 (file)
@@ -1502,7 +1502,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
  * Will sleep if required for nonblocking == false.
  */
 static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
-                               int nonblocking)
+                            void *pb, int nonblocking)
 {
        unsigned long flags;
        int ret;
@@ -1523,10 +1523,10 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
        /*
         * Only remove the buffer from done_list if v4l2_buffer can handle all
         * the planes.
-        * Verifying planes is NOT necessary since it already has been checked
-        * before the buffer is queued/prepared. So it can never fail.
         */
-       list_del(&(*vb)->done_entry);
+       ret = call_bufop(q, verify_planes_array, *vb, pb);
+       if (!ret)
+               list_del(&(*vb)->done_entry);
        spin_unlock_irqrestore(&q->done_lock, flags);
 
        return ret;
@@ -1604,7 +1604,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking)
        struct vb2_buffer *vb = NULL;
        int ret;
 
-       ret = __vb2_get_done_vb(q, &vb, nonblocking);
+       ret = __vb2_get_done_vb(q, &vb, pb, nonblocking);
        if (ret < 0)
                return ret;
 
index dbec5923fcf07d85ddde50a70686ddc4c397c5ed..3c3b517f1d1cacb5a7131263cd80c112bd22d619 100644 (file)
@@ -49,7 +49,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
        vec = frame_vector_create(nr);
        if (!vec)
                return ERR_PTR(-ENOMEM);
-       ret = get_vaddr_frames(start, nr, write, 1, vec);
+       ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec);
        if (ret < 0)
                goto out_destroy;
        /* We accept only complete set of PFNs */
index 502984c724ff5efd14ef10250dd5d8e653468111..6c441be8f893d8e931825b63b810d67ae67a2864 100644 (file)
@@ -67,6 +67,11 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer
        return 0;
 }
 
+static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb)
+{
+       return __verify_planes_array(vb, pb);
+}
+
 /**
  * __verify_length() - Verify that the bytesused value for each plane fits in
  * the plane length and that the data offset doesn't exceed the bytesused value.
@@ -432,6 +437,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 }
 
 static const struct vb2_buf_ops v4l2_buf_ops = {
+       .verify_planes_array    = __verify_planes_array_core,
        .fill_user_buffer       = __fill_v4l2_buffer,
        .fill_vb2_buffer        = __fill_vb2_buffer,
        .set_timestamp          = __set_timestamp,
index 6255513f54c7c2df29da53edb6a1dd2521b2dd4e..68aa31ae553a64c2aff19668d7a6e3b8e34c53c4 100644 (file)
@@ -445,6 +445,7 @@ int intel_lpss_probe(struct device *dev,
 err_remove_ltr:
        intel_lpss_debugfs_remove(lpss);
        intel_lpss_ltr_hide(lpss);
+       intel_lpss_unregister_clock(lpss);
 
 err_clk_register:
        ida_simple_remove(&intel_lpss_devid_ida, lpss->devid);
index 9afddaf6a23ce80af7f4fcd337ef82f5559778be..c51644f63f11bebfa9da017ae16703e3af759e61 100644 (file)
@@ -443,7 +443,7 @@ config ARM_CHARLCD
          still useful.
 
 config BMP085
-       bool
+       tristate
        depends on SYSFS
 
 config BMP085_I2C
index 15e88078ba1e6a70ec82b3c713fd8c19ebb425d7..f1a0b99f5a9a3e0cbc44eb1a69ac774f134569f4 100644 (file)
@@ -216,7 +216,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
                         */
                        value = swab16(value);
 
-                       if (dpot->uid == DPOT_UID(AD5271_ID))
+                       if (dpot->uid == DPOT_UID(AD5274_ID))
                                value = value >> 2;
                return value;
        default:
index 09a406058c4650ddf71114c26201889620003b9e..efbb6945eb18601bc04c9f9580bba5085f5f90df 100644 (file)
@@ -288,7 +288,6 @@ unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq,
 void cxl_unmap_irq(unsigned int virq, void *cookie)
 {
        free_irq(virq, cookie);
-       irq_dispose_mapping(virq);
 }
 
 static int cxl_register_one_irq(struct cxl *adapter,
index 0b05aa9387996484759e748831eba5304ac3a409..1a173d0af694407312b5a45bbe0d0bde70e0d12b 100644 (file)
@@ -53,6 +53,11 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
        bus = cl->dev;
 
        mutex_lock(&bus->device_lock);
+       if (bus->dev_state != MEI_DEV_ENABLED) {
+               rets = -ENODEV;
+               goto out;
+       }
+
        if (!mei_cl_is_connected(cl)) {
                rets = -ENODEV;
                goto out;
@@ -109,6 +114,10 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
        bus = cl->dev;
 
        mutex_lock(&bus->device_lock);
+       if (bus->dev_state != MEI_DEV_ENABLED) {
+               rets = -ENODEV;
+               goto out;
+       }
 
        cb = mei_cl_read_cb(cl, NULL);
        if (cb)
index 8310b4dbff0602ea5f4bd50f3ce87a9e58e854a7..6a451bd65bf3f8914586e3916f39c847730f15a8 100644 (file)
@@ -1511,7 +1511,7 @@ off_t scif_register_pinned_pages(scif_epd_t epd,
        if ((map_flags & SCIF_MAP_FIXED) &&
            ((ALIGN(offset, PAGE_SIZE) != offset) ||
            (offset < 0) ||
-           (offset + (off_t)len < offset)))
+           (len > LONG_MAX - offset)))
                return -EINVAL;
 
        might_sleep();
@@ -1614,7 +1614,7 @@ off_t scif_register(scif_epd_t epd, void *addr, size_t len, off_t offset,
        if ((map_flags & SCIF_MAP_FIXED) &&
            ((ALIGN(offset, PAGE_SIZE) != offset) ||
            (offset < 0) ||
-           (offset + (off_t)len < offset)))
+           (len > LONG_MAX - offset)))
                return -EINVAL;
 
        /* Unsupported protection requested */
@@ -1732,7 +1732,8 @@ scif_unregister(scif_epd_t epd, off_t offset, size_t len)
 
        /* Offset is not page aligned or offset+len wraps around */
        if ((ALIGN(offset, PAGE_SIZE) != offset) ||
-           (offset + (off_t)len < offset))
+           (offset < 0) ||
+           (len > LONG_MAX - offset))
                return -EINVAL;
 
        err = scif_verify_epd(ep);
index 5562308699bc292d5dce1e63fdea2452c38164f5..6142ec1b9dfbbc2a8a368977d2f3e40e022556c7 100644 (file)
@@ -68,3 +68,15 @@ config MMC_TEST
 
          This driver is only of interest to those developing or
          testing a host driver. Most people should say N here.
+
+config MMC_SIMULATE_MAX_SPEED
+       bool "Turn on maximum speed control per block device"
+       depends on MMC_BLOCK
+       help
+         Say Y here to enable MMC device speed limiting. Used to test and
+         simulate the behavior of the system when confronted with a slow MMC.
+
+         Enables max_read_speed, max_write_speed and cache_size attributes to
+         control the write or read maximum KB/second speed behaviors.
+
+         If unsure, say N here.
index 9fef7f04c4e6da764c9e640d534bb9c61e8aa377..67f44aed500030df7f0190d8323143d76d1f4b63 100644 (file)
@@ -288,6 +288,250 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+
+static int max_read_speed, max_write_speed, cache_size = 4;
+
+module_param(max_read_speed, int, S_IRUSR | S_IRGRP);
+MODULE_PARM_DESC(max_read_speed, "maximum KB/s read speed 0=off");
+module_param(max_write_speed, int, S_IRUSR | S_IRGRP);
+MODULE_PARM_DESC(max_write_speed, "maximum KB/s write speed 0=off");
+module_param(cache_size, int, S_IRUSR | S_IRGRP);
+MODULE_PARM_DESC(cache_size, "MB high speed memory or SLC cache");
+
+/*
+ * helper macros and expectations:
+ *  size    - unsigned long number of bytes
+ *  jiffies - unsigned long HZ timestamp difference
+ *  speed   - unsigned KB/s transfer rate
+ */
+#define size_and_speed_to_jiffies(size, speed) \
+               ((size) * HZ / (speed) / 1024UL)
+#define jiffies_and_speed_to_size(jiffies, speed) \
+               (((speed) * (jiffies) * 1024UL) / HZ)
+#define jiffies_and_size_to_speed(jiffies, size) \
+               ((size) * HZ / (jiffies) / 1024UL)
+
+/* Limits to report warning */
+/* jiffies_and_size_to_speed(10*HZ, queue_max_hw_sectors(q) * 512UL) ~ 25 */
+#define MIN_SPEED(q) 250 /* 10 times faster than a floppy disk */
+#define MAX_SPEED(q) jiffies_and_size_to_speed(1, queue_max_sectors(q) * 512UL)
+
+#define speed_valid(speed) ((speed) > 0)
+
+static const char off[] = "off\n";
+
+static int max_speed_show(int speed, char *buf)
+{
+       if (speed)
+               return scnprintf(buf, PAGE_SIZE, "%uKB/s\n", speed);
+       else
+               return scnprintf(buf, PAGE_SIZE, off);
+}
+
+static int max_speed_store(const char *buf, struct request_queue *q)
+{
+       unsigned int limit, set = 0;
+
+       if (!strncasecmp(off, buf, sizeof(off) - 2))
+               return set;
+       if (kstrtouint(buf, 0, &set) || (set > INT_MAX))
+               return -EINVAL;
+       if (set == 0)
+               return set;
+       limit = MAX_SPEED(q);
+       if (set > limit)
+               pr_warn("max speed %u ineffective above %u\n", set, limit);
+       limit = MIN_SPEED(q);
+       if (set < limit)
+               pr_warn("max speed %u painful below %u\n", set, limit);
+       return set;
+}
+
+static ssize_t max_write_speed_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       int ret = max_speed_show(atomic_read(&md->queue.max_write_speed), buf);
+
+       mmc_blk_put(md);
+       return ret;
+}
+
+static ssize_t max_write_speed_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       int set = max_speed_store(buf, md->queue.queue);
+
+       if (set < 0) {
+               mmc_blk_put(md);
+               return set;
+       }
+
+       atomic_set(&md->queue.max_write_speed, set);
+       mmc_blk_put(md);
+       return count;
+}
+
+static const DEVICE_ATTR(max_write_speed, S_IRUGO | S_IWUSR,
+       max_write_speed_show, max_write_speed_store);
+
+static ssize_t max_read_speed_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       int ret = max_speed_show(atomic_read(&md->queue.max_read_speed), buf);
+
+       mmc_blk_put(md);
+       return ret;
+}
+
+static ssize_t max_read_speed_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       int set = max_speed_store(buf, md->queue.queue);
+
+       if (set < 0) {
+               mmc_blk_put(md);
+               return set;
+       }
+
+       atomic_set(&md->queue.max_read_speed, set);
+       mmc_blk_put(md);
+       return count;
+}
+
+static const DEVICE_ATTR(max_read_speed, S_IRUGO | S_IWUSR,
+       max_read_speed_show, max_read_speed_store);
+
+static ssize_t cache_size_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       struct mmc_queue *mq = &md->queue;
+       int cache_size = atomic_read(&mq->cache_size);
+       int ret;
+
+       if (!cache_size)
+               ret = scnprintf(buf, PAGE_SIZE, off);
+       else {
+               int speed = atomic_read(&mq->max_write_speed);
+
+               if (!speed_valid(speed))
+                       ret = scnprintf(buf, PAGE_SIZE, "%uMB\n", cache_size);
+               else { /* We accept race between cache_jiffies and cache_used */
+                       unsigned long size = jiffies_and_speed_to_size(
+                               jiffies - mq->cache_jiffies, speed);
+                       long used = atomic_long_read(&mq->cache_used);
+
+                       if (size >= used)
+                               size = 0;
+                       else
+                               size = (used - size) * 100 / cache_size
+                                       / 1024UL / 1024UL;
+
+                       ret = scnprintf(buf, PAGE_SIZE, "%uMB %lu%% used\n",
+                               cache_size, size);
+               }
+       }
+
+       mmc_blk_put(md);
+       return ret;
+}
+
+static ssize_t cache_size_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct mmc_blk_data *md;
+       unsigned int set = 0;
+
+       if (strncasecmp(off, buf, sizeof(off) - 2)
+        && (kstrtouint(buf, 0, &set) || (set > INT_MAX)))
+               return -EINVAL;
+
+       md = mmc_blk_get(dev_to_disk(dev));
+       atomic_set(&md->queue.cache_size, set);
+       mmc_blk_put(md);
+       return count;
+}
+
+static const DEVICE_ATTR(cache_size, S_IRUGO | S_IWUSR,
+       cache_size_show, cache_size_store);
+
+/* correct for write-back */
+static long mmc_blk_cache_used(struct mmc_queue *mq, unsigned long waitfor)
+{
+       long used = 0;
+       int speed = atomic_read(&mq->max_write_speed);
+
+       if (speed_valid(speed)) {
+               unsigned long size = jiffies_and_speed_to_size(
+                                       waitfor - mq->cache_jiffies, speed);
+               used = atomic_long_read(&mq->cache_used);
+
+               if (size >= used)
+                       used = 0;
+               else
+                       used -= size;
+       }
+
+       atomic_long_set(&mq->cache_used, used);
+       mq->cache_jiffies = waitfor;
+
+       return used;
+}
+
+static void mmc_blk_simulate_delay(
+       struct mmc_queue *mq,
+       struct request *req,
+       unsigned long waitfor)
+{
+       int max_speed;
+
+       if (!req)
+               return;
+
+       max_speed = (rq_data_dir(req) == READ)
+               ? atomic_read(&mq->max_read_speed)
+               : atomic_read(&mq->max_write_speed);
+       if (speed_valid(max_speed)) {
+               unsigned long bytes = blk_rq_bytes(req);
+
+               if (rq_data_dir(req) != READ) {
+                       int cache_size = atomic_read(&mq->cache_size);
+
+                       if (cache_size) {
+                               unsigned long size = cache_size * 1024L * 1024L;
+                               long used = mmc_blk_cache_used(mq, waitfor);
+
+                               used += bytes;
+                               atomic_long_set(&mq->cache_used, used);
+                               bytes = 0;
+                               if (used > size)
+                                       bytes = used - size;
+                       }
+               }
+               waitfor += size_and_speed_to_jiffies(bytes, max_speed);
+               if (time_is_after_jiffies(waitfor)) {
+                       long msecs = jiffies_to_msecs(waitfor - jiffies);
+
+                       if (likely(msecs > 0))
+                               msleep(msecs);
+               }
+       }
+}
+
+#else
+
+#define mmc_blk_simulate_delay(mq, req, waitfor)
+
+#endif
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
        struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -1264,6 +1508,23 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
        if (ret)
                ret = -EIO;
 
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+       else if (atomic_read(&mq->cache_size)) {
+               long used = mmc_blk_cache_used(mq, jiffies);
+
+               if (used) {
+                       int speed = atomic_read(&mq->max_write_speed);
+
+                       if (speed_valid(speed)) {
+                               unsigned long msecs = jiffies_to_msecs(
+                                       size_and_speed_to_jiffies(
+                                               used, speed));
+                               if (msecs)
+                                       msleep(msecs);
+                       }
+               }
+       }
+#endif
        blk_end_request_all(req, ret);
 
        return ret ? 0 : 1;
@@ -1943,6 +2204,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
        struct mmc_async_req *areq;
        const u8 packed_nr = 2;
        u8 reqs = 0;
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+       unsigned long waitfor = jiffies;
+#endif
 
        if (!rqc && !mq->mqrq_prev->req)
                return 0;
@@ -1993,6 +2257,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                         */
                        mmc_blk_reset_success(md, type);
 
+                       mmc_blk_simulate_delay(mq, rqc, waitfor);
+
                        if (mmc_packed_cmd(mq_rq->cmd_type)) {
                                ret = mmc_blk_end_packed_req(mq_rq);
                                break;
@@ -2411,6 +2677,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
                                        card->ext_csd.boot_ro_lockable)
                                device_remove_file(disk_to_dev(md->disk),
                                        &md->power_ro_lock);
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+                       device_remove_file(disk_to_dev(md->disk),
+                                               &dev_attr_max_write_speed);
+                       device_remove_file(disk_to_dev(md->disk),
+                                               &dev_attr_max_read_speed);
+                       device_remove_file(disk_to_dev(md->disk),
+                                               &dev_attr_cache_size);
+#endif
 
                        del_gendisk(md->disk);
                }
@@ -2446,6 +2720,24 @@ static int mmc_add_disk(struct mmc_blk_data *md)
        ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
        if (ret)
                goto force_ro_fail;
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+       atomic_set(&md->queue.max_write_speed, max_write_speed);
+       ret = device_create_file(disk_to_dev(md->disk),
+                       &dev_attr_max_write_speed);
+       if (ret)
+               goto max_write_speed_fail;
+       atomic_set(&md->queue.max_read_speed, max_read_speed);
+       ret = device_create_file(disk_to_dev(md->disk),
+                       &dev_attr_max_read_speed);
+       if (ret)
+               goto max_read_speed_fail;
+       atomic_set(&md->queue.cache_size, cache_size);
+       atomic_long_set(&md->queue.cache_used, 0);
+       md->queue.cache_jiffies = jiffies;
+       ret = device_create_file(disk_to_dev(md->disk), &dev_attr_cache_size);
+       if (ret)
+               goto cache_size_fail;
+#endif
 
        if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
             card->ext_csd.boot_ro_lockable) {
@@ -2470,6 +2762,14 @@ static int mmc_add_disk(struct mmc_blk_data *md)
        return ret;
 
 power_ro_lock_fail:
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+       device_remove_file(disk_to_dev(md->disk), &dev_attr_cache_size);
+cache_size_fail:
+       device_remove_file(disk_to_dev(md->disk), &dev_attr_max_read_speed);
+max_read_speed_fail:
+       device_remove_file(disk_to_dev(md->disk), &dev_attr_max_write_speed);
+max_write_speed_fail:
+#endif
        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
 force_ro_fail:
        del_gendisk(md->disk);
index 36cddab57d776322c3912241f274e06620a77251..d890d8832e217a94f6d55aa79d25faadbbb7e352 100644 (file)
@@ -58,6 +58,14 @@ struct mmc_queue {
        struct mmc_queue_req    mqrq[2];
        struct mmc_queue_req    *mqrq_cur;
        struct mmc_queue_req    *mqrq_prev;
+#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
+       atomic_t max_write_speed;
+       atomic_t max_read_speed;
+       atomic_t cache_size;
+       /* i/o tracking */
+       atomic_long_t cache_used;
+       unsigned long cache_jiffies;
+#endif
 };
 
 extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
index 1c1b45ef3faf847d4087d61904ed18c1a6f7ce5e..aad3243a48fce34a2fdd3631f94669b4947cdbb3 100644 (file)
@@ -1436,6 +1436,12 @@ static int mmc_spi_probe(struct spi_device *spi)
                                             host->pdata->cd_debounce);
                if (status != 0)
                        goto fail_add_host;
+
+               /* The platform has a CD GPIO signal that may support
+                * interrupts, so let mmc_gpiod_request_cd_irq() decide
+                * if polling is needed or not.
+                */
+               mmc->caps &= ~MMC_CAP_NEEDS_POLL;
                mmc_gpiod_request_cd_irq(mmc);
        }
 
index 45ee07d3a76150390f82926f0343d50d953fcaf0..610154836d791b056ad7d0e3574b1eb6ef0854dc 100644 (file)
@@ -390,6 +390,7 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
        slot->cd_idx = 0;
        slot->cd_override_level = true;
        if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD ||
+           slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD ||
            slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD)
                slot->host->mmc_host_ops.get_cd = bxt_get_cd;
 
@@ -1171,6 +1172,30 @@ static const struct pci_device_id pci_ids[] = {
                .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sd,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BXTM_EMMC,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BXTM_SDIO,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BXTM_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sd,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_APL_EMMC,
index d1a0b4db60db41d67ad7d0e34652f2d13d2d3507..89e7151684a1fea26c35f27fee1c5ae2332e4eb8 100644 (file)
@@ -28,6 +28,9 @@
 #define PCI_DEVICE_ID_INTEL_BXT_SD     0x0aca
 #define PCI_DEVICE_ID_INTEL_BXT_EMMC   0x0acc
 #define PCI_DEVICE_ID_INTEL_BXT_SDIO   0x0ad0
+#define PCI_DEVICE_ID_INTEL_BXTM_SD    0x1aca
+#define PCI_DEVICE_ID_INTEL_BXTM_EMMC  0x1acc
+#define PCI_DEVICE_ID_INTEL_BXTM_SDIO  0x1ad0
 #define PCI_DEVICE_ID_INTEL_APL_SD     0x5aca
 #define PCI_DEVICE_ID_INTEL_APL_EMMC   0x5acc
 #define PCI_DEVICE_ID_INTEL_APL_SDIO   0x5ad0
index 6e13fa8471bf253980ccdfa6c529f858058cb6f4..5031d4fa068f61d82d14d81570982eaa2e63e09c 100644 (file)
@@ -666,9 +666,20 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        if (!data)
                target_timeout = cmd->busy_timeout * 1000;
        else {
-               target_timeout = data->timeout_ns / 1000;
-               if (host->clock)
-                       target_timeout += data->timeout_clks / host->clock;
+               target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
+               if (host->clock && data->timeout_clks) {
+                       unsigned long long val;
+
+                       /*
+                        * data->timeout_clks is in units of clock cycles.
+                        * host->clock is in Hz.  target_timeout is in us.
+                        * Hence, us = 1000000 * cycles / Hz.  Round up.
+                        */
+                       val = 1000000 * data->timeout_clks;
+                       if (do_div(val, host->clock))
+                               target_timeout++;
+                       target_timeout += val;
+               }
        }
 
        /*
index ad9ffea7d659d28e057f13c1b7912ca7243743ac..6234eab38ff3efe8b22b8386f4d635496dad0d08 100644 (file)
@@ -397,38 +397,26 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
 }
 
 static struct dma_chan *
-sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
-                        struct sh_mmcif_plat_data *pdata,
-                        enum dma_transfer_direction direction)
+sh_mmcif_request_dma_pdata(struct sh_mmcif_host *host, uintptr_t slave_id)
 {
-       struct dma_slave_config cfg = { 0, };
-       struct dma_chan *chan;
-       void *slave_data = NULL;
-       struct resource *res;
-       struct device *dev = sh_mmcif_host_to_dev(host);
        dma_cap_mask_t mask;
-       int ret;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
+       if (slave_id <= 0)
+               return NULL;
 
-       if (pdata)
-               slave_data = direction == DMA_MEM_TO_DEV ?
-                       (void *)pdata->slave_id_tx :
-                       (void *)pdata->slave_id_rx;
-
-       chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
-                               slave_data, dev,
-                               direction == DMA_MEM_TO_DEV ? "tx" : "rx");
-
-       dev_dbg(dev, "%s: %s: got channel %p\n", __func__,
-               direction == DMA_MEM_TO_DEV ? "TX" : "RX", chan);
+       return dma_request_channel(mask, shdma_chan_filter, (void *)slave_id);
+}
 
-       if (!chan)
-               return NULL;
+static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
+                                    struct dma_chan *chan,
+                                    enum dma_transfer_direction direction)
+{
+       struct resource *res;
+       struct dma_slave_config cfg = { 0, };
 
        res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
-
        cfg.direction = direction;
 
        if (direction == DMA_DEV_TO_MEM) {
@@ -439,38 +427,42 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
                cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        }
 
-       ret = dmaengine_slave_config(chan, &cfg);
-       if (ret < 0) {
-               dma_release_channel(chan);
-               return NULL;
-       }
-
-       return chan;
+       return dmaengine_slave_config(chan, &cfg);
 }
 
-static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
-                                struct sh_mmcif_plat_data *pdata)
+static void sh_mmcif_request_dma(struct sh_mmcif_host *host)
 {
        struct device *dev = sh_mmcif_host_to_dev(host);
        host->dma_active = false;
 
-       if (pdata) {
-               if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
-                       return;
-       } else if (!dev->of_node) {
-               return;
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       if (IS_ENABLED(CONFIG_SUPERH) && dev->platform_data) {
+               struct sh_mmcif_plat_data *pdata = dev->platform_data;
+
+               host->chan_tx = sh_mmcif_request_dma_pdata(host,
+                                                       pdata->slave_id_tx);
+               host->chan_rx = sh_mmcif_request_dma_pdata(host,
+                                                       pdata->slave_id_rx);
+       } else {
+               host->chan_tx = dma_request_slave_channel(dev, "tx");
+               host->chan_rx = dma_request_slave_channel(dev, "rx");
        }
+       dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx,
+               host->chan_rx);
 
-       /* We can only either use DMA for both Tx and Rx or not use it at all */
-       host->chan_tx = sh_mmcif_request_dma_one(host, pdata, DMA_MEM_TO_DEV);
-       if (!host->chan_tx)
-               return;
+       if (!host->chan_tx || !host->chan_rx ||
+           sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) ||
+           sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM))
+               goto error;
 
-       host->chan_rx = sh_mmcif_request_dma_one(host, pdata, DMA_DEV_TO_MEM);
-       if (!host->chan_rx) {
+       return;
+
+error:
+       if (host->chan_tx)
                dma_release_channel(host->chan_tx);
-               host->chan_tx = NULL;
-       }
+       if (host->chan_rx)
+               dma_release_channel(host->chan_rx);
+       host->chan_tx = host->chan_rx = NULL;
 }
 
 static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
@@ -1102,7 +1094,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (ios->power_mode == MMC_POWER_UP) {
                if (!host->card_present) {
                        /* See if we also get DMA */
-                       sh_mmcif_request_dma(host, dev->platform_data);
+                       sh_mmcif_request_dma(host);
                        host->card_present = true;
                }
                sh_mmcif_set_power(host, ios);
index 12c6190c6e338be6a25c878db9e5870bf3a02fef..4a07ba1195b589693432e0c37d71f283f9d1074a 100644 (file)
@@ -309,6 +309,36 @@ static const u16 brcmnand_regs_v60[] = {
        [BRCMNAND_FC_BASE]              = 0x400,
 };
 
+/* BRCMNAND v7.1 */
+static const u16 brcmnand_regs_v71[] = {
+       [BRCMNAND_CMD_START]            =  0x04,
+       [BRCMNAND_CMD_EXT_ADDRESS]      =  0x08,
+       [BRCMNAND_CMD_ADDRESS]          =  0x0c,
+       [BRCMNAND_INTFC_STATUS]         =  0x14,
+       [BRCMNAND_CS_SELECT]            =  0x18,
+       [BRCMNAND_CS_XOR]               =  0x1c,
+       [BRCMNAND_LL_OP]                =  0x20,
+       [BRCMNAND_CS0_BASE]             =  0x50,
+       [BRCMNAND_CS1_BASE]             =     0,
+       [BRCMNAND_CORR_THRESHOLD]       =  0xdc,
+       [BRCMNAND_CORR_THRESHOLD_EXT]   =  0xe0,
+       [BRCMNAND_UNCORR_COUNT]         =  0xfc,
+       [BRCMNAND_CORR_COUNT]           = 0x100,
+       [BRCMNAND_CORR_EXT_ADDR]        = 0x10c,
+       [BRCMNAND_CORR_ADDR]            = 0x110,
+       [BRCMNAND_UNCORR_EXT_ADDR]      = 0x114,
+       [BRCMNAND_UNCORR_ADDR]          = 0x118,
+       [BRCMNAND_SEMAPHORE]            = 0x150,
+       [BRCMNAND_ID]                   = 0x194,
+       [BRCMNAND_ID_EXT]               = 0x198,
+       [BRCMNAND_LL_RDATA]             = 0x19c,
+       [BRCMNAND_OOB_READ_BASE]        = 0x200,
+       [BRCMNAND_OOB_READ_10_BASE]     =     0,
+       [BRCMNAND_OOB_WRITE_BASE]       = 0x280,
+       [BRCMNAND_OOB_WRITE_10_BASE]    =     0,
+       [BRCMNAND_FC_BASE]              = 0x400,
+};
+
 enum brcmnand_cs_reg {
        BRCMNAND_CS_CFG_EXT = 0,
        BRCMNAND_CS_CFG,
@@ -404,7 +434,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
        }
 
        /* Register offsets */
-       if (ctrl->nand_version >= 0x0600)
+       if (ctrl->nand_version >= 0x0701)
+               ctrl->reg_offsets = brcmnand_regs_v71;
+       else if (ctrl->nand_version >= 0x0600)
                ctrl->reg_offsets = brcmnand_regs_v60;
        else if (ctrl->nand_version >= 0x0500)
                ctrl->reg_offsets = brcmnand_regs_v50;
index 3ff583f165cdfce7138f3f02d771fcb9d8f99e5e..ce7b2cab5762e5854cc4a11175876a53162e6215 100644 (file)
@@ -3979,7 +3979,6 @@ static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
  * This is the first phase of the normal nand_scan() function. It reads the
  * flash ID and sets up MTD fields accordingly.
  *
- * The mtd->owner field must be set to the module of the caller.
  */
 int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                    struct nand_flash_dev *table)
@@ -4403,19 +4402,12 @@ EXPORT_SYMBOL(nand_scan_tail);
  *
  * This fills out all the uninitialized function pointers with the defaults.
  * The flash ID is read and the mtd/chip structures are filled with the
- * appropriate values. The mtd->owner field must be set to the module of the
- * caller.
+ * appropriate values.
  */
 int nand_scan(struct mtd_info *mtd, int maxchips)
 {
        int ret;
 
-       /* Many callers got this wrong, so check for it for a while... */
-       if (!mtd->owner && caller_is_module()) {
-               pr_crit("%s called with NULL mtd->owner!\n", __func__);
-               BUG();
-       }
-
        ret = nand_scan_ident(mtd, maxchips, NULL);
        if (!ret)
                ret = nand_scan_tail(mtd);
index 43b3392ffee7e255555d88948e4dbe2aa47867d2..652d018328735c6761711b63850106cc70f0e08c 100644 (file)
@@ -2599,6 +2599,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
  */
 static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
+       struct onenand_chip *this = mtd->priv;
        int ret;
 
        ret = onenand_block_isbad(mtd, ofs);
@@ -2610,7 +2611,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
        }
 
        onenand_get_device(mtd, FL_WRITING);
-       ret = mtd_block_markbad(mtd, ofs);
+       ret = this->block_markbad(mtd, ofs);
        onenand_release_device(mtd);
        return ret;
 }
index 32477c4eb421390e250645f94b0eefdab871a043..37e4135ab213d64b158f7165994e5000d1dd4bb7 100644 (file)
@@ -1067,45 +1067,6 @@ static int spansion_quad_enable(struct spi_nor *nor)
        return 0;
 }
 
-static int micron_quad_enable(struct spi_nor *nor)
-{
-       int ret;
-       u8 val;
-
-       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading EVCR\n", ret);
-               return ret;
-       }
-
-       write_enable(nor);
-
-       /* set EVCR, enable quad I/O */
-       nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
-       ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error while writing EVCR register\n");
-               return ret;
-       }
-
-       ret = spi_nor_wait_till_ready(nor);
-       if (ret)
-               return ret;
-
-       /* read EVCR and check it */
-       ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
-       if (ret < 0) {
-               dev_err(nor->dev, "error %d reading EVCR\n", ret);
-               return ret;
-       }
-       if (val & EVCR_QUAD_EN_MICRON) {
-               dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 {
        int status;
@@ -1119,12 +1080,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
                }
                return status;
        case SNOR_MFR_MICRON:
-               status = micron_quad_enable(nor);
-               if (status) {
-                       dev_err(nor->dev, "Micron quad-read not enabled\n");
-                       return -EINVAL;
-               }
-               return status;
+               return 0;
        default:
                status = spansion_quad_enable(nor);
                if (status) {
index 28bbca0af238bb6a2642045a2e4e0273e38f2dc5..b3d70a7a52620ff8d228b3b1a96a7f89fab081b3 100644 (file)
@@ -3260,6 +3260,30 @@ static int bond_close(struct net_device *bond_dev)
        return 0;
 }
 
+/* fold stats, assuming all rtnl_link_stats64 fields are u64, but
+ * that some drivers can provide 32bit values only.
+ */
+static void bond_fold_stats(struct rtnl_link_stats64 *_res,
+                           const struct rtnl_link_stats64 *_new,
+                           const struct rtnl_link_stats64 *_old)
+{
+       const u64 *new = (const u64 *)_new;
+       const u64 *old = (const u64 *)_old;
+       u64 *res = (u64 *)_res;
+       int i;
+
+       for (i = 0; i < sizeof(*_res) / sizeof(u64); i++) {
+               u64 nv = new[i];
+               u64 ov = old[i];
+
+               /* detects if this particular field is 32bit only */
+               if (((nv | ov) >> 32) == 0)
+                       res[i] += (u32)nv - (u32)ov;
+               else
+                       res[i] += nv - ov;
+       }
+}
+
 static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
                                                struct rtnl_link_stats64 *stats)
 {
@@ -3268,43 +3292,23 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
        struct list_head *iter;
        struct slave *slave;
 
+       spin_lock(&bond->stats_lock);
        memcpy(stats, &bond->bond_stats, sizeof(*stats));
 
-       bond_for_each_slave(bond, slave, iter) {
-               const struct rtnl_link_stats64 *sstats =
+       rcu_read_lock();
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               const struct rtnl_link_stats64 *new =
                        dev_get_stats(slave->dev, &temp);
-               struct rtnl_link_stats64 *pstats = &slave->slave_stats;
-
-               stats->rx_packets +=  sstats->rx_packets - pstats->rx_packets;
-               stats->rx_bytes += sstats->rx_bytes - pstats->rx_bytes;
-               stats->rx_errors += sstats->rx_errors - pstats->rx_errors;
-               stats->rx_dropped += sstats->rx_dropped - pstats->rx_dropped;
-
-               stats->tx_packets += sstats->tx_packets - pstats->tx_packets;;
-               stats->tx_bytes += sstats->tx_bytes - pstats->tx_bytes;
-               stats->tx_errors += sstats->tx_errors - pstats->tx_errors;
-               stats->tx_dropped += sstats->tx_dropped - pstats->tx_dropped;
-
-               stats->multicast += sstats->multicast - pstats->multicast;
-               stats->collisions += sstats->collisions - pstats->collisions;
-
-               stats->rx_length_errors += sstats->rx_length_errors - pstats->rx_length_errors;
-               stats->rx_over_errors += sstats->rx_over_errors - pstats->rx_over_errors;
-               stats->rx_crc_errors += sstats->rx_crc_errors - pstats->rx_crc_errors;
-               stats->rx_frame_errors += sstats->rx_frame_errors - pstats->rx_frame_errors;
-               stats->rx_fifo_errors += sstats->rx_fifo_errors - pstats->rx_fifo_errors;
-               stats->rx_missed_errors += sstats->rx_missed_errors - pstats->rx_missed_errors;
-
-               stats->tx_aborted_errors += sstats->tx_aborted_errors - pstats->tx_aborted_errors;
-               stats->tx_carrier_errors += sstats->tx_carrier_errors - pstats->tx_carrier_errors;
-               stats->tx_fifo_errors += sstats->tx_fifo_errors - pstats->tx_fifo_errors;
-               stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors - pstats->tx_heartbeat_errors;
-               stats->tx_window_errors += sstats->tx_window_errors - pstats->tx_window_errors;
+
+               bond_fold_stats(stats, new, &slave->slave_stats);
 
                /* save off the slave stats for the next run */
-               memcpy(pstats, sstats, sizeof(*sstats));
+               memcpy(&slave->slave_stats, new, sizeof(*new));
        }
+       rcu_read_unlock();
+
        memcpy(&bond->bond_stats, stats, sizeof(*stats));
+       spin_unlock(&bond->stats_lock);
 
        return stats;
 }
@@ -4118,6 +4122,7 @@ void bond_setup(struct net_device *bond_dev)
        struct bonding *bond = netdev_priv(bond_dev);
 
        spin_lock_init(&bond->mode_lock);
+       spin_lock_init(&bond->stats_lock);
        bond->params = bonding_defaults;
 
        /* Initialize pointers */
index 17f017ab4dac6d560ffd0e79aa5f0c95a0e8077c..0fb3f8de88e9e8f897ad16abc70db06b54c64bcb 100644 (file)
@@ -1197,7 +1197,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev,
                        dev->stats.tx_bytes += tx_cb_ptr->skb->len;
                        dma_unmap_single(&dev->dev,
                                         dma_unmap_addr(tx_cb_ptr, dma_addr),
-                                        tx_cb_ptr->skb->len,
+                                        dma_unmap_len(tx_cb_ptr, dma_len),
                                         DMA_TO_DEVICE);
                        bcmgenet_free_cb(tx_cb_ptr);
                } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
@@ -1308,7 +1308,7 @@ static int bcmgenet_xmit_single(struct net_device *dev,
        }
 
        dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
-       dma_unmap_len_set(tx_cb_ptr, dma_len, skb->len);
+       dma_unmap_len_set(tx_cb_ptr, dma_len, skb_len);
        length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
                        (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) |
                        DMA_TX_APPEND_CRC;
index 060dd39229747c4b1f43e4f9f374777bea4d95ec..1257b18e6b9025df3f0b7b2268cc563400d6a664 100644 (file)
@@ -270,11 +270,17 @@ jme_reset_mac_processor(struct jme_adapter *jme)
 }
 
 static inline void
-jme_clear_pm(struct jme_adapter *jme)
+jme_clear_pm_enable_wol(struct jme_adapter *jme)
 {
        jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs);
 }
 
+static inline void
+jme_clear_pm_disable_wol(struct jme_adapter *jme)
+{
+       jwrite32(jme, JME_PMCS, PMCS_STMASK);
+}
+
 static int
 jme_reload_eeprom(struct jme_adapter *jme)
 {
@@ -1853,7 +1859,7 @@ jme_open(struct net_device *netdev)
        struct jme_adapter *jme = netdev_priv(netdev);
        int rc;
 
-       jme_clear_pm(jme);
+       jme_clear_pm_disable_wol(jme);
        JME_NAPI_ENABLE(jme);
 
        tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
@@ -1925,11 +1931,11 @@ jme_wait_link(struct jme_adapter *jme)
 static void
 jme_powersave_phy(struct jme_adapter *jme)
 {
-       if (jme->reg_pmcs) {
+       if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) {
                jme_set_100m_half(jme);
                if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
                        jme_wait_link(jme);
-               jme_clear_pm(jme);
+               jme_clear_pm_enable_wol(jme);
        } else {
                jme_phy_off(jme);
        }
@@ -2646,9 +2652,6 @@ jme_set_wol(struct net_device *netdev,
        if (wol->wolopts & WAKE_MAGIC)
                jme->reg_pmcs |= PMCS_MFEN;
 
-       jwrite32(jme, JME_PMCS, jme->reg_pmcs);
-       device_set_wakeup_enable(&jme->pdev->dev, !!(jme->reg_pmcs));
-
        return 0;
 }
 
@@ -3172,8 +3175,8 @@ jme_init_one(struct pci_dev *pdev,
        jme->mii_if.mdio_read = jme_mdio_read;
        jme->mii_if.mdio_write = jme_mdio_write;
 
-       jme_clear_pm(jme);
-       device_set_wakeup_enable(&pdev->dev, true);
+       jme_clear_pm_disable_wol(jme);
+       device_init_wakeup(&pdev->dev, true);
 
        jme_set_phyfifo_5level(jme);
        jme->pcirev = pdev->revision;
@@ -3304,7 +3307,7 @@ jme_resume(struct device *dev)
        if (!netif_running(netdev))
                return 0;
 
-       jme_clear_pm(jme);
+       jme_clear_pm_disable_wol(jme);
        jme_phy_on(jme);
        if (test_bit(JME_FLAG_SSET, &jme->flags))
                jme_set_settings(netdev, &jme->old_ecmd);
@@ -3312,13 +3315,14 @@ jme_resume(struct device *dev)
                jme_reset_phy_processor(jme);
        jme_phy_calibration(jme);
        jme_phy_setEA(jme);
-       jme_start_irq(jme);
        netif_device_attach(netdev);
 
        atomic_inc(&jme->link_changing);
 
        jme_reset_link(jme);
 
+       jme_start_irq(jme);
+
        return 0;
 }
 
index ed622fa29dfab61c448c0c446ad2cae467ee1df2..a4ac6fedac75b714231040215bdb9d7bdeda3d9d 100644 (file)
@@ -3404,7 +3404,7 @@ static int mvneta_probe(struct platform_device *pdev)
        dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
        dev->hw_features |= dev->features;
        dev->vlan_features |= dev->features;
-       dev->priv_flags |= IFF_UNICAST_FLT;
+       dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE;
        dev->gso_max_segs = MVNETA_MAX_TSO_SEGS;
 
        err = register_netdev(dev);
index cad6c44df91c4de9b97d367ede4f2562c65fc86b..d314d96dcb1cd41bb481022a05e3d1567cd10c89 100644 (file)
@@ -3132,7 +3132,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
                case QP_TRANS_RTS2RTS:
                case QP_TRANS_SQD2SQD:
                case QP_TRANS_SQD2RTS:
-                       if (slave != mlx4_master_func_num(dev))
+                       if (slave != mlx4_master_func_num(dev)) {
                                if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
                                        port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
                                        if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
@@ -3151,6 +3151,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
                                        if (qp_ctx->alt_path.mgid_index >= num_gids)
                                                return -EINVAL;
                                }
+                       }
                        break;
                default:
                        break;
index 4365c8bccc6d291f6f8f60a03fe8726f20ad93b5..605f6410f867e17eaf5b5f6b63f6a60ce65c0cf7 100644 (file)
@@ -61,6 +61,8 @@ struct mlxsw_sp {
 #define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
                unsigned int interval; /* ms */
        } fdb_notify;
+#define MLXSW_SP_MIN_AGEING_TIME 10
+#define MLXSW_SP_MAX_AGEING_TIME 1000000
 #define MLXSW_SP_DEFAULT_AGEING_TIME 300
        u32 ageing_time;
        struct {
index 7dbeafa659340eea3dbd28f5ad53c4b4cd8e4b05..d4c4c2b5156c0311ac72b7f14c5d0472a567ac3f 100644 (file)
@@ -232,8 +232,13 @@ static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
        unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
        u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
 
-       if (switchdev_trans_ph_prepare(trans))
-               return 0;
+       if (switchdev_trans_ph_prepare(trans)) {
+               if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
+                   ageing_time > MLXSW_SP_MAX_AGEING_TIME)
+                       return -ERANGE;
+               else
+                       return 0;
+       }
 
        return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
 }
index 46bbea8e023c0194e408ec9e269456c9456136e2..55007f1e6bbcc77981414e9db1e73d8db8502988 100644 (file)
@@ -566,6 +566,7 @@ struct qlcnic_adapter_stats {
        u64  tx_dma_map_error;
        u64  spurious_intr;
        u64  mac_filter_limit_overrun;
+       u64  mbx_spurious_intr;
 };
 
 /*
@@ -1099,7 +1100,7 @@ struct qlcnic_mailbox {
        unsigned long           status;
        spinlock_t              queue_lock;     /* Mailbox queue lock */
        spinlock_t              aen_lock;       /* Mailbox response/AEN lock */
-       atomic_t                rsp_status;
+       u32                     rsp_status;
        u32                     num_cmds;
 };
 
index 37a731be7d399f6ae14d5c0e1f889599f9fd2d5d..f9640d5ce6baa774d1f980a2c6eb652fc301eab8 100644 (file)
@@ -491,7 +491,7 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 
 static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
 {
-       atomic_set(&mbx->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
+       mbx->rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
        complete(&mbx->completion);
 }
 
@@ -510,7 +510,7 @@ static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
        if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                __qlcnic_83xx_process_aen(adapter);
        } else {
-               if (atomic_read(&mbx->rsp_status) != rsp_status)
+               if (mbx->rsp_status != rsp_status)
                        qlcnic_83xx_notify_mbx_response(mbx);
        }
 out:
@@ -1023,7 +1023,7 @@ static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
                if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                        __qlcnic_83xx_process_aen(adapter);
                } else {
-                       if (atomic_read(&mbx->rsp_status) != rsp_status)
+                       if (mbx->rsp_status != rsp_status)
                                qlcnic_83xx_notify_mbx_response(mbx);
                }
        }
@@ -2338,9 +2338,9 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
 
 static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 {
+       u32 mask, resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
        struct qlcnic_adapter *adapter = data;
        struct qlcnic_mailbox *mbx;
-       u32 mask, resp, event;
        unsigned long flags;
 
        mbx = adapter->ahw->mailbox;
@@ -2350,10 +2350,14 @@ static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
                goto out;
 
        event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+       if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                __qlcnic_83xx_process_aen(adapter);
-       else
-               qlcnic_83xx_notify_mbx_response(mbx);
+       } else {
+               if (mbx->rsp_status != rsp_status)
+                       qlcnic_83xx_notify_mbx_response(mbx);
+               else
+                       adapter->stats.mbx_spurious_intr++;
+       }
 
 out:
        mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
@@ -4050,10 +4054,10 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
        struct qlcnic_adapter *adapter = mbx->adapter;
        const struct qlcnic_mbx_ops *mbx_ops = mbx->ops;
        struct device *dev = &adapter->pdev->dev;
-       atomic_t *rsp_status = &mbx->rsp_status;
        struct list_head *head = &mbx->cmd_q;
        struct qlcnic_hardware_context *ahw;
        struct qlcnic_cmd_args *cmd = NULL;
+       unsigned long flags;
 
        ahw = adapter->ahw;
 
@@ -4063,7 +4067,9 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
                        return;
                }
 
-               atomic_set(rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
+               spin_lock_irqsave(&mbx->aen_lock, flags);
+               mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
+               spin_unlock_irqrestore(&mbx->aen_lock, flags);
 
                spin_lock(&mbx->queue_lock);
 
index 494e8105adee7834341353ddc81cf65a70a33b9c..0a2318cad34d74a6000f710a375848b1c3f54f45 100644 (file)
@@ -59,7 +59,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
         QLC_OFF(stats.mac_filter_limit_overrun)},
        {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
         QLC_OFF(stats.spurious_intr)},
-
+       {"mbx spurious intr", QLC_SIZEOF(stats.mbx_spurious_intr),
+        QLC_OFF(stats.mbx_spurious_intr)},
 };
 
 static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
index 997976426799d90a328cef4ff958b92ce3ba491c..b28e73ea2c258850f1a00cb195e45f4751900f43 100644 (file)
@@ -1648,7 +1648,18 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
                return;
        }
        skb_reserve(new_skb, NET_IP_ALIGN);
+
+       pci_dma_sync_single_for_cpu(qdev->pdev,
+                                   dma_unmap_addr(sbq_desc, mapaddr),
+                                   dma_unmap_len(sbq_desc, maplen),
+                                   PCI_DMA_FROMDEVICE);
+
        memcpy(skb_put(new_skb, length), skb->data, length);
+
+       pci_dma_sync_single_for_device(qdev->pdev,
+                                      dma_unmap_addr(sbq_desc, mapaddr),
+                                      dma_unmap_len(sbq_desc, maplen),
+                                      PCI_DMA_FROMDEVICE);
        skb = new_skb;
 
        /* Frame error, so drop the packet. */
index 689a4a5c8dcfc30fba2675e17293e98691648dd2..1ef03939d25f478356112fbe376ff79cfd1e8eaa 100644 (file)
@@ -811,7 +811,7 @@ qcaspi_netdev_setup(struct net_device *dev)
        dev->netdev_ops = &qcaspi_netdev_ops;
        qcaspi_set_ethtool_ops(dev);
        dev->watchdog_timeo = QCASPI_TX_TIMEOUT;
-       dev->flags = IFF_MULTICAST;
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->tx_queue_len = 100;
 
        qca = netdev_priv(dev);
index 6a8fc0f341ff2528fdda1cb97f8e2934d99c5f14..36fc9427418f325b433349e08700801387b412ba 100644 (file)
@@ -1185,11 +1185,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
                        break;
                sh_eth_set_receive_align(skb);
 
-               /* RX descriptor */
-               rxdesc = &mdp->rx_ring[i];
                /* The size of the buffer is a multiple of 32 bytes. */
                buf_len = ALIGN(mdp->rx_buf_sz, 32);
-               rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
                dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
                                          DMA_FROM_DEVICE);
                if (dma_mapping_error(&ndev->dev, dma_addr)) {
@@ -1197,6 +1194,10 @@ static void sh_eth_ring_format(struct net_device *ndev)
                        break;
                }
                mdp->rx_skbuff[i] = skb;
+
+               /* RX descriptor */
+               rxdesc = &mdp->rx_ring[i];
+               rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
                rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
                rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
@@ -1212,7 +1213,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
        mdp->dirty_rx = (u32) (i - mdp->num_rx_ring);
 
        /* Mark the last entry as wrapping the ring. */
-       rxdesc->status |= cpu_to_edmac(mdp, RD_RDLE);
+       if (rxdesc)
+               rxdesc->status |= cpu_to_edmac(mdp, RD_RDLE);
 
        memset(mdp->tx_ring, 0, tx_ringsize);
 
index 52ec3d6e056a02d6fe9a7992608b4a30e52c2744..2b34622a4bfe891be5d8f96609a5ec5b35d4bced 100644 (file)
@@ -239,6 +239,7 @@ struct rocker {
        struct {
                u64 id;
        } hw;
+       unsigned long ageing_time;
        spinlock_t cmd_ring_lock;               /* for cmd ring accesses */
        struct rocker_dma_ring_info cmd_ring;
        struct rocker_dma_ring_info event_ring;
@@ -3704,7 +3705,7 @@ static void rocker_fdb_cleanup(unsigned long data)
        struct rocker_port *rocker_port;
        struct rocker_fdb_tbl_entry *entry;
        struct hlist_node *tmp;
-       unsigned long next_timer = jiffies + BR_MIN_AGEING_TIME;
+       unsigned long next_timer = jiffies + rocker->ageing_time;
        unsigned long expires;
        unsigned long lock_flags;
        int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE |
@@ -4367,8 +4368,12 @@ static int rocker_port_bridge_ageing_time(struct rocker_port *rocker_port,
                                          struct switchdev_trans *trans,
                                          u32 ageing_time)
 {
+       struct rocker *rocker = rocker_port->rocker;
+
        if (!switchdev_trans_ph_prepare(trans)) {
                rocker_port->ageing_time = clock_t_to_jiffies(ageing_time);
+               if (rocker_port->ageing_time < rocker->ageing_time)
+                       rocker->ageing_time = rocker_port->ageing_time;
                mod_timer(&rocker_port->rocker->fdb_cleanup_timer, jiffies);
        }
 
@@ -5206,10 +5211,13 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_init_tbls;
        }
 
+       rocker->ageing_time = BR_DEFAULT_AGEING_TIME;
        setup_timer(&rocker->fdb_cleanup_timer, rocker_fdb_cleanup,
                    (unsigned long) rocker);
        mod_timer(&rocker->fdb_cleanup_timer, jiffies);
 
+       rocker->ageing_time = BR_DEFAULT_AGEING_TIME;
+
        err = rocker_probe_ports(rocker);
        if (err) {
                dev_err(&pdev->dev, "failed to probe ports\n");
index 696852eb23c3f07a9e31668c7854617943822d11..7a3f990c193546c42888f937497718d18c2b80e5 100644 (file)
@@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty)
 
        /* Module stuff handled via irda_ldisc.owner - Jean II */
 
-       /* First make sure we're not already connected. */
-       if (tty->disc_data != NULL) {
-               priv = tty->disc_data;
-               if (priv && priv->magic == IRTTY_MAGIC) {
-                       ret = -EEXIST;
-                       goto out;
-               }
-               tty->disc_data = NULL;          /* ### */
-       }
-
        /* stop the underlying  driver */
        irtty_stop_receiver(tty, TRUE);
        if (tty->ops->stop)
index 0fc521941c718dbcdea487a18a900984ad176ea5..159a68782bec9ac172c5fa168fe7dc05605f7ad4 100644 (file)
@@ -760,6 +760,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                        macvtap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
                if (copylen > good_linear)
                        copylen = good_linear;
+               else if (copylen < ETH_HLEN)
+                       copylen = ETH_HLEN;
                linear = copylen;
                i = *from;
                iov_iter_advance(&i, copylen);
@@ -769,10 +771,11 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        if (!zerocopy) {
                copylen = len;
-               if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > good_linear)
+               linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
+               if (linear > good_linear)
                        linear = good_linear;
-               else
-                       linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
+               else if (linear < ETH_HLEN)
+                       linear = ETH_HLEN;
        }
 
        skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen,
index 9a863c6a6a33aa7883f6fa105fca917ae177e25c..174e06ec7c2fe88014ee77c8a60e99788e459072 100644 (file)
@@ -567,7 +567,7 @@ static int get_filter(void __user *arg, struct sock_filter **p)
 
 static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct ppp_file *pf = file->private_data;
+       struct ppp_file *pf;
        struct ppp *ppp;
        int err = -EFAULT, val, val2, i;
        struct ppp_idle idle;
@@ -577,9 +577,14 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
 
-       if (!pf)
-               return ppp_unattached_ioctl(current->nsproxy->net_ns,
-                                       pf, file, cmd, arg);
+       mutex_lock(&ppp_mutex);
+
+       pf = file->private_data;
+       if (!pf) {
+               err = ppp_unattached_ioctl(current->nsproxy->net_ns,
+                                          pf, file, cmd, arg);
+               goto out;
+       }
 
        if (cmd == PPPIOCDETACH) {
                /*
@@ -594,7 +599,6 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 * this fd and reopening /dev/ppp.
                 */
                err = -EINVAL;
-               mutex_lock(&ppp_mutex);
                if (pf->kind == INTERFACE) {
                        ppp = PF_TO_PPP(pf);
                        rtnl_lock();
@@ -608,15 +612,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                } else
                        pr_warn("PPPIOCDETACH file->f_count=%ld\n",
                                atomic_long_read(&file->f_count));
-               mutex_unlock(&ppp_mutex);
-               return err;
+               goto out;
        }
 
        if (pf->kind == CHANNEL) {
                struct channel *pch;
                struct ppp_channel *chan;
 
-               mutex_lock(&ppp_mutex);
                pch = PF_TO_CHANNEL(pf);
 
                switch (cmd) {
@@ -638,17 +640,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                err = chan->ops->ioctl(chan, cmd, arg);
                        up_read(&pch->chan_sem);
                }
-               mutex_unlock(&ppp_mutex);
-               return err;
+               goto out;
        }
 
        if (pf->kind != INTERFACE) {
                /* can't happen */
                pr_err("PPP: not interface or channel??\n");
-               return -EINVAL;
+               err = -EINVAL;
+               goto out;
        }
 
-       mutex_lock(&ppp_mutex);
        ppp = PF_TO_PPP(pf);
        switch (cmd) {
        case PPPIOCSMRU:
@@ -823,7 +824,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        default:
                err = -ENOTTY;
        }
+
+out:
        mutex_unlock(&ppp_mutex);
+
        return err;
 }
 
@@ -836,7 +840,6 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
        struct ppp_net *pn;
        int __user *p = (int __user *)arg;
 
-       mutex_lock(&ppp_mutex);
        switch (cmd) {
        case PPPIOCNEWUNIT:
                /* Create a new ppp unit */
@@ -886,7 +889,7 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
        default:
                err = -ENOTTY;
        }
-       mutex_unlock(&ppp_mutex);
+
        return err;
 }
 
@@ -2290,7 +2293,7 @@ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan)
 
        pch->ppp = NULL;
        pch->chan = chan;
-       pch->chan_net = net;
+       pch->chan_net = get_net(net);
        chan->ppp = pch;
        init_ppp_file(&pch->file, CHANNEL);
        pch->file.hdrlen = chan->hdrlen;
@@ -2387,6 +2390,8 @@ ppp_unregister_channel(struct ppp_channel *chan)
        spin_lock_bh(&pn->all_channels_lock);
        list_del(&pch->list);
        spin_unlock_bh(&pn->all_channels_lock);
+       put_net(pch->chan_net);
+       pch->chan_net = NULL;
 
        pch->file.dead = 1;
        wake_up_interruptible(&pch->file.rwait);
@@ -2803,6 +2808,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,
 
 out2:
        mutex_unlock(&pn->all_ppp_mutex);
+       rtnl_unlock();
        free_netdev(dev);
 out1:
        *retp = ret;
index 01f08a7751f7aeb9c39be52a7766ec2800885fc8..e7034c55e7968d977d8313ad696618837d014a6e 100644 (file)
@@ -280,7 +280,7 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo
        struct net_device *ndev = dev_id;
        struct rionet_private *rnet = netdev_priv(ndev);
 
-       spin_lock(&rnet->lock);
+       spin_lock(&rnet->tx_lock);
 
        if (netif_msg_intr(rnet))
                printk(KERN_INFO
@@ -299,7 +299,7 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo
        if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
                netif_wake_queue(ndev);
 
-       spin_unlock(&rnet->lock);
+       spin_unlock(&rnet->tx_lock);
 }
 
 static int rionet_open(struct net_device *ndev)
index 2228a539184a00b1f4f5a32dafe794616fefdacc..de0d15e03e037b9b392362844e452ff5bceadea3 100644 (file)
@@ -621,7 +621,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte
 
        /* Re-attach the filter to persist device */
        if (!skip_filter && (tun->filter_attached == true)) {
-               err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
+               err = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
+                                        lockdep_rtnl_is_held());
                if (!err)
                        goto out;
        }
@@ -1000,7 +1001,6 @@ static void tun_net_init(struct net_device *dev)
                /* Zero header length */
                dev->type = ARPHRD_NONE;
                dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-               dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
                break;
 
        case IFF_TAP:
@@ -1012,7 +1012,6 @@ static void tun_net_init(struct net_device *dev)
 
                eth_hw_addr_random(dev);
 
-               dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
                break;
        }
 }
@@ -1463,6 +1462,8 @@ static void tun_setup(struct net_device *dev)
 
        dev->ethtool_ops = &tun_ethtool_ops;
        dev->destructor = tun_free_netdev;
+       /* We prefer our own queue length */
+       dev->tx_queue_len = TUN_READQ_SIZE;
 }
 
 /* Trivial set of netlink ops to allow deleting tun or tap
@@ -1804,7 +1805,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
 
        for (i = 0; i < n; i++) {
                tfile = rtnl_dereference(tun->tfiles[i]);
-               sk_detach_filter(tfile->socket.sk);
+               __sk_detach_filter(tfile->socket.sk, lockdep_rtnl_is_held());
        }
 
        tun->filter_attached = false;
@@ -1817,7 +1818,8 @@ static int tun_attach_filter(struct tun_struct *tun)
 
        for (i = 0; i < tun->numqueues; i++) {
                tfile = rtnl_dereference(tun->tfiles[i]);
-               ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
+               ret = __sk_attach_filter(&tun->fprog, tfile->socket.sk,
+                                        lockdep_rtnl_is_held());
                if (ret) {
                        tun_detach_filter(tun, i);
                        return ret;
index 3da70bf9936a846c5939c389c2d91af1c674af58..7cba2c3759df76fba3087d0acd654bd9d77896d7 100644 (file)
@@ -160,6 +160,12 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
        info->u = header.usb_cdc_union_desc;
        info->header = header.usb_cdc_header_desc;
        info->ether = header.usb_cdc_ether_desc;
+       if (!info->u) {
+               if (rndis)
+                       goto skip;
+               else /* in that case a quirk is mandatory */
+                       goto bad_desc;
+       }
        /* we need a master/control interface (what we're
         * probed with) and a slave/data interface; union
         * descriptors sort this all out.
@@ -256,7 +262,7 @@ skip:
                        goto bad_desc;
                }
 
-       } else if (!info->header || !info->u || (!rndis && !info->ether)) {
+       } else if (!info->header || (!rndis && !info->ether)) {
                dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
                        info->header ? "" : "header ",
                        info->u ? "" : "union ",
index e8a1144c5a8bfa28c1ddca137c56c888b176ab32..8c2bb77db049db97852c3a485674cd505a3a524d 100644 (file)
@@ -794,7 +794,11 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
 
        iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
-       /* reset data interface */
+       /* Reset data interface. Some devices will not reset properly
+        * unless they are configured first.  Toggle the altsetting to
+        * force a reset
+        */
+       usb_set_interface(dev->udev, iface_no, data_altsetting);
        temp = usb_set_interface(dev->udev, iface_no, 0);
        if (temp) {
                dev_dbg(&intf->dev, "set interface failed\n");
index 982e0acd1a36748c964d131d552e27a60f54fc1d..a34f491224c1c002565348ef0cf676373c2236e8 100644 (file)
@@ -699,6 +699,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x19d2, 0x1426, 2)},    /* ZTE MF91 */
        {QMI_FIXED_INTF(0x19d2, 0x1428, 2)},    /* Telewell TW-LTE 4G v2 */
        {QMI_FIXED_INTF(0x19d2, 0x2002, 4)},    /* ZTE (Vodafone) K3765-Z */
+       {QMI_FIXED_INTF(0x2001, 0x7e19, 4)},    /* D-Link DWM-221 B1 */
        {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
        {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
@@ -718,8 +719,10 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1199, 0x9061, 8)},    /* Sierra Wireless Modem */
        {QMI_FIXED_INTF(0x1199, 0x9070, 8)},    /* Sierra Wireless MC74xx/EM74xx */
        {QMI_FIXED_INTF(0x1199, 0x9070, 10)},   /* Sierra Wireless MC74xx/EM74xx */
-       {QMI_FIXED_INTF(0x1199, 0x9071, 8)},    /* Sierra Wireless MC74xx/EM74xx */
-       {QMI_FIXED_INTF(0x1199, 0x9071, 10)},   /* Sierra Wireless MC74xx/EM74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9071, 8)},    /* Sierra Wireless MC74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9071, 10)},   /* Sierra Wireless MC74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9079, 8)},    /* Sierra Wireless EM74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9079, 10)},   /* Sierra Wireless EM74xx */
        {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},    /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
        {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},    /* Alcatel L800MA */
        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
index 0744bf2ef2d6e42044c6c31f7c74b0ec120e07d3..c2ea4e5666fb965fd089f27cfbdee5715cd66538 100644 (file)
@@ -1766,6 +1766,13 @@ out3:
        if (info->unbind)
                info->unbind (dev, udev);
 out1:
+       /* subdrivers must undo all they did in bind() if they
+        * fail it, but we may fail later and a deferred kevent
+        * may trigger an error resubmitting itself and, worse,
+        * schedule a timer. So we kill it all just in case.
+        */
+       cancel_work_sync(&dev->kevent);
+       del_timer_sync(&dev->delay);
        free_netdev(net);
 out:
        return status;
index 0a242b200df4c9e8198a9a74764eb05f89f13cbd..903bda437839f7ed758193a9519920825ba40d8d 100644 (file)
@@ -114,20 +114,23 @@ static struct dst_ops vrf_dst_ops = {
 #if IS_ENABLED(CONFIG_IPV6)
 static bool check_ipv6_frame(const struct sk_buff *skb)
 {
-       const struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->data;
-       size_t hlen = sizeof(*ipv6h);
+       const struct ipv6hdr *ipv6h;
+       struct ipv6hdr _ipv6h;
        bool rc = true;
 
-       if (skb->len < hlen)
+       ipv6h = skb_header_pointer(skb, 0, sizeof(_ipv6h), &_ipv6h);
+       if (!ipv6h)
                goto out;
 
        if (ipv6h->nexthdr == NEXTHDR_ICMP) {
                const struct icmp6hdr *icmph;
+               struct icmp6hdr _icmph;
 
-               if (skb->len < hlen + sizeof(*icmph))
+               icmph = skb_header_pointer(skb, sizeof(_ipv6h),
+                                          sizeof(_icmph), &_icmph);
+               if (!icmph)
                        goto out;
 
-               icmph = (struct icmp6hdr *)(skb->data + sizeof(*ipv6h));
                switch (icmph->icmp6_type) {
                case NDISC_ROUTER_SOLICITATION:
                case NDISC_ROUTER_ADVERTISEMENT:
index e0fcda4ddd55a401b5aedc9e4d79ace206758afb..3c0df70e2f53aa0020b79e93f3adf92b43fee0b3 100644 (file)
@@ -1306,8 +1306,10 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                gbp = (struct vxlanhdr_gbp *)vxh;
                md->gbp = ntohs(gbp->policy_id);
 
-               if (tun_dst)
+               if (tun_dst) {
                        tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
+                       tun_dst->u.tun_info.options_len = sizeof(*md);
+               }
 
                if (gbp->dont_learn)
                        md->gbp |= VXLAN_GBP_DONT_LEARN;
index 44541dbc5c28c3f04400755ff94f2bc8fc2c5f38..69b994f3b8c528406ef3f28c02147b0070a074e3 100644 (file)
@@ -2516,7 +2516,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                 dev->mem_start   = card->phys_mem
                                  + BUF_OFFSET ( txBuffer[i][0][0]);
                 dev->mem_end     = card->phys_mem
-                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER][0]);
+                                 + BUF_OFFSET ( txBuffer[i][NUM_TX_BUFFER - 1][LEN_RX_BUFFER - 1]);
                 dev->base_addr   = card->pci_conf;
                 dev->irq         = card->irq;
 
index 8f8793004b9f021c7f689e13dabcf32f10e2c3a0..1b271b99c49eee91a96639ee019d370f61d0cda0 100644 (file)
@@ -274,6 +274,9 @@ void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah,
        };
        static const int inc[4] = { 0, 100, 0, 0 };
 
+       memset(&mask_m, 0, sizeof(int8_t) * 123);
+       memset(&mask_p, 0, sizeof(int8_t) * 123);
+
        cur_bin = -6000;
        upper = bin + 100;
        lower = bin - 100;
@@ -424,14 +427,9 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
        int tmp, new;
        int i;
 
-       int8_t mask_m[123];
-       int8_t mask_p[123];
        int cur_bb_spur;
        bool is2GHz = IS_CHAN_2GHZ(chan);
 
-       memset(&mask_m, 0, sizeof(int8_t) * 123);
-       memset(&mask_p, 0, sizeof(int8_t) * 123);
-
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
                cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
                if (AR_NO_SPUR == cur_bb_spur)
index db6624527d9959d3ffd10a32f3fa76cb0b6dff83..53d7445a5d12c1edaaf012e4e853560ec1f75e39 100644 (file)
@@ -178,14 +178,9 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
        int i;
        struct chan_centers centers;
 
-       int8_t mask_m[123];
-       int8_t mask_p[123];
        int cur_bb_spur;
        bool is2GHz = IS_CHAN_2GHZ(chan);
 
-       memset(&mask_m, 0, sizeof(int8_t) * 123);
-       memset(&mask_p, 0, sizeof(int8_t) * 123);
-
        ath9k_hw_get_channel_centers(ah, chan, &centers);
        freq = centers.synth_center;
 
index cc81482c934d61e6a40c3b181435348040c93cd2..113a43fca9cfa14f6d220eaaaeb51e95a20efbef 100644 (file)
@@ -403,10 +403,9 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
 
        if (match) {
                if (AR_SREV_9287(ah)) {
-                       /* FIXME: array overrun? */
                        for (i = 0; i < numXpdGains; i++) {
                                minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
-                               maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
+                               maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
                                                data_9287[idxL].pwrPdg[i],
                                                data_9287[idxL].vpdPdg[i],
@@ -416,7 +415,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
                } else if (eeprom_4k) {
                        for (i = 0; i < numXpdGains; i++) {
                                minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
-                               maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
+                               maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
                                                data_4k[idxL].pwrPdg[i],
                                                data_4k[idxL].vpdPdg[i],
@@ -426,7 +425,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
                } else {
                        for (i = 0; i < numXpdGains; i++) {
                                minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
-                               maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
+                               maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
                                ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
                                                data_def[idxL].pwrPdg[i],
                                                data_def[idxL].vpdPdg[i],
index d906fa13ba9710a3e9250cd481d735aa71f767de..610c442c7ab2f8194f4c4777c44070eacab322a4 100644 (file)
@@ -106,7 +106,7 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
                                    sizeof(tx_ant_cmd), &tx_ant_cmd);
 }
 
-static void iwl_free_fw_paging(struct iwl_mvm *mvm)
+void iwl_free_fw_paging(struct iwl_mvm *mvm)
 {
        int i;
 
@@ -126,6 +126,8 @@ static void iwl_free_fw_paging(struct iwl_mvm *mvm)
                             get_order(mvm->fw_paging_db[i].fw_paging_size));
        }
        kfree(mvm->trans->paging_download_buf);
+       mvm->trans->paging_download_buf = NULL;
+
        memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db));
 }
 
index e88afac51c5d69fe5d6c8f4e032cdcf95f48a168..f96ab2f4b90ebc2b3522764705f30fd816413c1b 100644 (file)
@@ -1557,6 +1557,8 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
        /* the fw is stopped, the aux sta is dead: clean up driver state */
        iwl_mvm_del_aux_sta(mvm);
 
+       iwl_free_fw_paging(mvm);
+
        /*
         * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
         * won't be called in this case).
index 4bde2d027dcd34ce710722af8416e9c3a1159461..244e26c26821b81aa52befea899fa0e83293a9f9 100644 (file)
@@ -1190,6 +1190,9 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
 void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                                              struct iwl_rx_cmd_buffer *rxb);
 
+/* Paging */
+void iwl_free_fw_paging(struct iwl_mvm *mvm);
+
 /* MVM debugfs */
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
index 8c7204738aa3f076b28c55ef41bff4a3fdb42e36..00e0332e2544797883850dde60fc319e1b83cb07 100644 (file)
@@ -731,8 +731,8 @@ static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans)
         */
        val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0);
        if (val & (BIT(1) | BIT(17))) {
-               IWL_INFO(trans,
-                        "can't access the RSA semaphore it is write protected\n");
+               IWL_DEBUG_INFO(trans,
+                              "can't access the RSA semaphore it is write protected\n");
                return 0;
        }
 
index a6c8a4f7bfe96aa44b5f46db60c29944abf5a79b..d6c4f0f60839c3c595d6fa0e8a35eafdfabf81ce 100644 (file)
@@ -313,6 +313,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                        mwifiex_dbg(adapter, ERROR,
                                    "Attempt to reconnect on csa closed chan(%d)\n",
                                    bss_desc->channel);
+                       ret = -1;
                        goto done;
                }
 
index 7e2c43f701bc451463c5273ed3a5a1e49f6be15f..5f47356d694298a9df134dbf47cebe086ed0e844 100644 (file)
@@ -335,7 +335,7 @@ static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = {
        [ND_CMD_IMPLEMENTED] = { },
        [ND_CMD_SMART] = {
                .out_num = 2,
-               .out_sizes = { 4, 8, },
+               .out_sizes = { 4, 128, },
        },
        [ND_CMD_SMART_THRESHOLD] = {
                .out_num = 2,
@@ -513,10 +513,10 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
 
        /* fail write commands (when read-only) */
        if (read_only)
-               switch (ioctl_cmd) {
-               case ND_IOCTL_VENDOR:
-               case ND_IOCTL_SET_CONFIG_DATA:
-               case ND_IOCTL_ARS_START:
+               switch (cmd) {
+               case ND_CMD_VENDOR:
+               case ND_CMD_SET_CONFIG_DATA:
+               case ND_CMD_ARS_START:
                        dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
                                        nvdimm ? nvdimm_cmd_name(cmd)
                                        : nvdimm_bus_cmd_name(cmd));
index 71805a1aa0f3e5f002ee5d26339c53d49aadf951..9d3974591cd62d4ba1a6a31995ff964f022d060c 100644 (file)
@@ -275,7 +275,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn)
        } else {
                /* from init we validate */
                if (memcmp(nd_pfn->uuid, pfn_sb->uuid, 16) != 0)
-                       return -EINVAL;
+                       return -ENODEV;
        }
 
        /*
index 8ba19bba31569f22c6529a739fa1d30adf5c2f0f..2bb3c5799ac4b0146b2760d8823fb1eb28a6bdaa 100644 (file)
@@ -94,7 +94,7 @@ static int mxs_ocotp_read(void *context, const void *reg, size_t reg_size,
        if (ret)
                goto close_banks;
 
-       while (val_size) {
+       while (val_size >= reg_size) {
                if ((offset < OCOTP_DATA_OFFSET) || (offset % 16)) {
                        /* fill up non-data register */
                        *buf = 0;
@@ -103,7 +103,7 @@ static int mxs_ocotp_read(void *context, const void *reg, size_t reg_size,
                }
 
                buf++;
-               val_size--;
+               val_size -= reg_size;
                offset += reg_size;
        }
 
index 86fff625f6d5770ec493a301a30be8d3bfa11831..c6d196188bc9f06b0da4d22ec50fdaaf157d9601 100644 (file)
@@ -760,6 +760,16 @@ const void * __init of_flat_dt_match_machine(const void *default_match,
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
+#ifndef __early_init_dt_declare_initrd
+static void __early_init_dt_declare_initrd(unsigned long start,
+                                          unsigned long end)
+{
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
+}
+#endif
+
 /**
  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
  * @node: reference to node containing initrd location ('chosen')
@@ -782,9 +792,7 @@ static void __init early_init_dt_check_for_initrd(unsigned long node)
                return;
        end = of_read_number(prop, len/4);
 
-       initrd_start = (unsigned long)__va(start);
-       initrd_end = (unsigned long)__va(end);
-       initrd_below_start_ok = 1;
+       __early_init_dt_declare_initrd(start, end);
 
        pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n",
                 (unsigned long long)start, (unsigned long long)end);
@@ -1006,13 +1014,16 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 }
 
 #ifdef CONFIG_HAVE_MEMBLOCK
+#ifndef MIN_MEMBLOCK_ADDR
+#define MIN_MEMBLOCK_ADDR      __pa(PAGE_OFFSET)
+#endif
 #ifndef MAX_MEMBLOCK_ADDR
 #define MAX_MEMBLOCK_ADDR      ((phys_addr_t)~0)
 #endif
 
 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
 {
-       const u64 phys_offset = __pa(PAGE_OFFSET);
+       const u64 phys_offset = MIN_MEMBLOCK_ADDR;
 
        if (!PAGE_ALIGNED(base)) {
                if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
index 1a3556a9e9ea126b451b2a3c68e0407135af242f..ed01c0172e4a5f8b45e0a382b789f0cd20d60987 100644 (file)
@@ -32,11 +32,13 @@ int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
        phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
        phys_addr_t *res_base)
 {
+       phys_addr_t base;
        /*
         * We use __memblock_alloc_base() because memblock_alloc_base()
         * panic()s on allocation failure.
         */
-       phys_addr_t base = __memblock_alloc_base(size, align, end);
+       end = !end ? MEMBLOCK_ALLOC_ANYWHERE : end;
+       base = __memblock_alloc_base(size, align, end);
        if (!base)
                return -ENOMEM;
 
index edb1984201e9702162321c50f33f76ba362bac5a..7aafb5fb9336e2a657ee0aa19dac54957b0f42da 100644 (file)
@@ -179,6 +179,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
        u16 orig_cmd;
        struct pci_bus_region region, inverted_region;
 
+       if (dev->non_compliant_bars)
+               return 0;
+
        mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
 
        /* No printks while decoding is disabled! */
@@ -1174,6 +1177,7 @@ void pci_msi_setup_pci_dev(struct pci_dev *dev)
 int pci_setup_device(struct pci_dev *dev)
 {
        u32 class;
+       u16 cmd;
        u8 hdr_type;
        int pos = 0;
        struct pci_bus_region region;
@@ -1219,6 +1223,16 @@ int pci_setup_device(struct pci_dev *dev)
        /* device class may be changed after fixup */
        class = dev->class >> 8;
 
+       if (dev->non_compliant_bars) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+                       dev_info(&dev->dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");
+                       cmd &= ~PCI_COMMAND_IO;
+                       cmd &= ~PCI_COMMAND_MEMORY;
+                       pci_write_config_word(dev, PCI_COMMAND, cmd);
+               }
+       }
+
        switch (dev->hdr_type) {                    /* header type */
        case PCI_HEADER_TYPE_NORMAL:                /* standard header */
                if (class == PCI_CLASS_BRIDGE_PCI)
index 4c2fa05b4589e2095db8430b77fe338077a6c7d7..944674ee34644fa2583f2193ad738a4b5cbe4912 100644 (file)
@@ -56,6 +56,7 @@ struct db1x_pcmcia_sock {
        int     stschg_irq;     /* card-status-change irq */
        int     card_irq;       /* card irq */
        int     eject_irq;      /* db1200/pb1200 have these */
+       int     insert_gpio;    /* db1000 carddetect gpio */
 
 #define BOARD_TYPE_DEFAULT     0       /* most boards */
 #define BOARD_TYPE_DB1200      1       /* IRQs aren't gpios */
@@ -83,7 +84,7 @@ static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
 /* carddetect gpio: low-active */
 static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
 {
-       return !gpio_get_value(irq_to_gpio(sock->insert_irq));
+       return !gpio_get_value(sock->insert_gpio);
 }
 
 static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
@@ -457,9 +458,15 @@ static int db1x_pcmcia_socket_probe(struct platform_device *pdev)
        r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
        sock->card_irq = r ? r->start : 0;
 
-       /* insert: irq which triggers on card insertion/ejection */
+       /* insert: irq which triggers on card insertion/ejection
+        * BIG FAT NOTE: on DB1000/1100/1500/1550 we pass a GPIO here!
+        */
        r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
        sock->insert_irq = r ? r->start : -1;
+       if (sock->board_type == BOARD_TYPE_DEFAULT) {
+               sock->insert_gpio = r ? r->start : -1;
+               sock->insert_irq = r ? gpio_to_irq(r->start) : -1;
+       }
 
        /* stschg: irq which trigger on card status change (optional) */
        r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
index 2e6ca69635aa001531d2b9aca128d001b97d9aca..17dd8fe12b54ab6b44c31fcd3c3c917beda9691d 100644 (file)
@@ -779,7 +779,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
                }
                if (num_pulls) {
                        err = of_property_read_u32_index(np, "brcm,pull",
-                                       (num_funcs > 1) ? i : 0, &pull);
+                                       (num_pulls > 1) ? i : 0, &pull);
                        if (err)
                                goto out;
                        err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin,
index a5bb939873789710d0b00dfcda9805bd287ce92d..1029aa7889b55233fd0b5e3cf5d31ea245f9e2c7 100644 (file)
@@ -726,19 +726,18 @@ int imx_pinctrl_probe(struct platform_device *pdev,
 
        if (of_property_read_bool(dev_np, "fsl,input-sel")) {
                np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
-               if (np) {
-                       ipctl->input_sel_base = of_iomap(np, 0);
-                       if (IS_ERR(ipctl->input_sel_base)) {
-                               of_node_put(np);
-                               dev_err(&pdev->dev,
-                                       "iomuxc input select base address not found\n");
-                               return PTR_ERR(ipctl->input_sel_base);
-                       }
-               } else {
+               if (!np) {
                        dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
                        return -EINVAL;
                }
+
+               ipctl->input_sel_base = of_iomap(np, 0);
                of_node_put(np);
+               if (!ipctl->input_sel_base) {
+                       dev_err(&pdev->dev,
+                               "iomuxc input select base address not found\n");
+                       return -ENOMEM;
+               }
        }
 
        imx_pinctrl_desc.name = dev_name(&pdev->dev);
index 5c717275a7fa805f370cdd68815e64f8982b142b..3d8019eb3d8476686584371e822411cb631552cb 100644 (file)
@@ -939,7 +939,8 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
        struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
        int eint_num, virq, eint_offset;
        unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
-       static const unsigned int dbnc_arr[] = {0 , 1, 16, 32, 64, 128, 256};
+       static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000,
+                                               128000, 256000};
        const struct mtk_desc_pin *pin;
        struct irq_data *d;
 
@@ -957,9 +958,9 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
        if (!mtk_eint_can_en_debounce(pctl, eint_num))
                return -ENOSYS;
 
-       dbnc = ARRAY_SIZE(dbnc_arr);
-       for (i = 0; i < ARRAY_SIZE(dbnc_arr); i++) {
-               if (debounce <= dbnc_arr[i]) {
+       dbnc = ARRAY_SIZE(debounce_time);
+       for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+               if (debounce <= debounce_time[i]) {
                        dbnc = i;
                        break;
                }
index eebfae0c9b7c84a6eacc4ad450d0765e602a011f..f844b4ae7f796aa836784291572f687b67156c8a 100644 (file)
@@ -995,7 +995,7 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s,
                int val;
 
                if (pull)
-                       pullidx = data_out ? 1 : 2;
+                       pullidx = data_out ? 2 : 1;
 
                seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %s",
                           gpio,
index 85c9046c690e2c44ab0da44571ac75a252da9708..6b1a47f8c0969208406d1dcc662f21389a0a2027 100644 (file)
@@ -469,27 +469,27 @@ static const char * const pistachio_mips_pll_lock_groups[] = {
        "mfio83",
 };
 
-static const char * const pistachio_sys_pll_lock_groups[] = {
+static const char * const pistachio_audio_pll_lock_groups[] = {
        "mfio84",
 };
 
-static const char * const pistachio_wifi_pll_lock_groups[] = {
+static const char * const pistachio_rpu_v_pll_lock_groups[] = {
        "mfio85",
 };
 
-static const char * const pistachio_bt_pll_lock_groups[] = {
+static const char * const pistachio_rpu_l_pll_lock_groups[] = {
        "mfio86",
 };
 
-static const char * const pistachio_rpu_v_pll_lock_groups[] = {
+static const char * const pistachio_sys_pll_lock_groups[] = {
        "mfio87",
 };
 
-static const char * const pistachio_rpu_l_pll_lock_groups[] = {
+static const char * const pistachio_wifi_pll_lock_groups[] = {
        "mfio88",
 };
 
-static const char * const pistachio_audio_pll_lock_groups[] = {
+static const char * const pistachio_bt_pll_lock_groups[] = {
        "mfio89",
 };
 
@@ -559,12 +559,12 @@ enum pistachio_mux_option {
        PISTACHIO_FUNCTION_DREQ4,
        PISTACHIO_FUNCTION_DREQ5,
        PISTACHIO_FUNCTION_MIPS_PLL_LOCK,
+       PISTACHIO_FUNCTION_AUDIO_PLL_LOCK,
+       PISTACHIO_FUNCTION_RPU_V_PLL_LOCK,
+       PISTACHIO_FUNCTION_RPU_L_PLL_LOCK,
        PISTACHIO_FUNCTION_SYS_PLL_LOCK,
        PISTACHIO_FUNCTION_WIFI_PLL_LOCK,
        PISTACHIO_FUNCTION_BT_PLL_LOCK,
-       PISTACHIO_FUNCTION_RPU_V_PLL_LOCK,
-       PISTACHIO_FUNCTION_RPU_L_PLL_LOCK,
-       PISTACHIO_FUNCTION_AUDIO_PLL_LOCK,
        PISTACHIO_FUNCTION_DEBUG_RAW_CCA_IND,
        PISTACHIO_FUNCTION_DEBUG_ED_SEC20_CCA_IND,
        PISTACHIO_FUNCTION_DEBUG_ED_SEC40_CCA_IND,
@@ -620,12 +620,12 @@ static const struct pistachio_function pistachio_functions[] = {
        FUNCTION(dreq4),
        FUNCTION(dreq5),
        FUNCTION(mips_pll_lock),
+       FUNCTION(audio_pll_lock),
+       FUNCTION(rpu_v_pll_lock),
+       FUNCTION(rpu_l_pll_lock),
        FUNCTION(sys_pll_lock),
        FUNCTION(wifi_pll_lock),
        FUNCTION(bt_pll_lock),
-       FUNCTION(rpu_v_pll_lock),
-       FUNCTION(rpu_l_pll_lock),
-       FUNCTION(audio_pll_lock),
        FUNCTION(debug_raw_cca_ind),
        FUNCTION(debug_ed_sec20_cca_ind),
        FUNCTION(debug_ed_sec40_cca_ind),
index ef04b962c3d51992ba41080b893829d2d4102b56..23b6b8c29a99eb9a65b7c2bd11e02da7356afc97 100644 (file)
@@ -1273,9 +1273,9 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
 
                /* Parse pins in each row from LSB */
                while (mask) {
-                       bit_pos = ffs(mask);
+                       bit_pos = __ffs(mask);
                        pin_num_from_lsb = bit_pos / pcs->bits_per_pin;
-                       mask_pos = ((pcs->fmask) << (bit_pos - 1));
+                       mask_pos = ((pcs->fmask) << bit_pos);
                        val_pos = val & mask_pos;
                        submask = mask & mask_pos;
 
@@ -1847,7 +1847,7 @@ static int pcs_probe(struct platform_device *pdev)
        ret = of_property_read_u32(np, "pinctrl-single,function-mask",
                                   &pcs->fmask);
        if (!ret) {
-               pcs->fshift = ffs(pcs->fmask) - 1;
+               pcs->fshift = __ffs(pcs->fmask);
                pcs->fmax = pcs->fmask >> pcs->fshift;
        } else {
                /* If mask property doesn't exist, function mux is invalid. */
index 181ea98a63b7ab02d367581b4027997ea0f6a574..2b0d70217bbdcb9bbf02bd6746b056341502ffe4 100644 (file)
@@ -545,7 +545,9 @@ static int sh_pfc_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       pinctrl_provide_dummies();
+       /* Enable dummy states for those platforms without pinctrl support */
+       if (!of_have_populated_dt())
+               pinctrl_provide_dummies();
 
        ret = sh_pfc_init_ranges(pfc);
        if (ret < 0)
index 00265f0435a77d83998bd6db377a76a3c4a5ed3a..8b381d69df8632c806f45bde5a5d1e6645b35d40 100644 (file)
@@ -485,6 +485,7 @@ static const struct sunxi_pinctrl_desc sun8i_a33_pinctrl_data = {
        .pins = sun8i_a33_pins,
        .npins = ARRAY_SIZE(sun8i_a33_pins),
        .irq_banks = 2,
+       .irq_bank_base = 1,
 };
 
 static int sun8i_a33_pinctrl_probe(struct platform_device *pdev)
index dead97daca35fe2e59a0e81f7898b4e66f27b0cb..a4a5b504c532a2b898cc98df06c42677ba2b79a1 100644 (file)
@@ -578,7 +578,7 @@ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d)
 static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
 {
        struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       u32 reg = sunxi_irq_cfg_reg(d->hwirq);
+       u32 reg = sunxi_irq_cfg_reg(d->hwirq, pctl->desc->irq_bank_base);
        u8 index = sunxi_irq_cfg_offset(d->hwirq);
        unsigned long flags;
        u32 regval;
@@ -625,7 +625,8 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
 static void sunxi_pinctrl_irq_ack(struct irq_data *d)
 {
        struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       u32 status_reg = sunxi_irq_status_reg(d->hwirq);
+       u32 status_reg = sunxi_irq_status_reg(d->hwirq,
+                                             pctl->desc->irq_bank_base);
        u8 status_idx = sunxi_irq_status_offset(d->hwirq);
 
        /* Clear the IRQ */
@@ -635,7 +636,7 @@ static void sunxi_pinctrl_irq_ack(struct irq_data *d)
 static void sunxi_pinctrl_irq_mask(struct irq_data *d)
 {
        struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
+       u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base);
        u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
        unsigned long flags;
        u32 val;
@@ -652,7 +653,7 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d)
 static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
 {
        struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
+       u32 reg = sunxi_irq_ctrl_reg(d->hwirq, pctl->desc->irq_bank_base);
        u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
        unsigned long flags;
        u32 val;
@@ -744,7 +745,7 @@ static void sunxi_pinctrl_irq_handler(struct irq_desc *desc)
        if (bank == pctl->desc->irq_banks)
                return;
 
-       reg = sunxi_irq_status_reg_from_bank(bank);
+       reg = sunxi_irq_status_reg_from_bank(bank, pctl->desc->irq_bank_base);
        val = readl(pctl->membase + reg);
 
        if (val) {
@@ -1023,9 +1024,11 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
 
        for (i = 0; i < pctl->desc->irq_banks; i++) {
                /* Mask and clear all IRQs before registering a handler */
-               writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i));
+               writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i,
+                                               pctl->desc->irq_bank_base));
                writel(0xffffffff,
-                       pctl->membase + sunxi_irq_status_reg_from_bank(i));
+                      pctl->membase + sunxi_irq_status_reg_from_bank(i,
+                                               pctl->desc->irq_bank_base));
 
                irq_set_chained_handler_and_data(pctl->irq[i],
                                                 sunxi_pinctrl_irq_handler,
index e248e81a0f9e0f8446cbd634040c93632b5e1268..0afce1ab12d039515a1ea40f66bdb3806ca9f5ca 100644 (file)
@@ -97,6 +97,7 @@ struct sunxi_pinctrl_desc {
        int                             npins;
        unsigned                        pin_base;
        unsigned                        irq_banks;
+       unsigned                        irq_bank_base;
        bool                            irq_read_needs_mux;
 };
 
@@ -233,12 +234,12 @@ static inline u32 sunxi_pull_offset(u16 pin)
        return pin_num * PULL_PINS_BITS;
 }
 
-static inline u32 sunxi_irq_cfg_reg(u16 irq)
+static inline u32 sunxi_irq_cfg_reg(u16 irq, unsigned bank_base)
 {
        u8 bank = irq / IRQ_PER_BANK;
        u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04;
 
-       return IRQ_CFG_REG + bank * IRQ_MEM_SIZE + reg;
+       return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg;
 }
 
 static inline u32 sunxi_irq_cfg_offset(u16 irq)
@@ -247,16 +248,16 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq)
        return irq_num * IRQ_CFG_IRQ_BITS;
 }
 
-static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank)
+static inline u32 sunxi_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base)
 {
-       return IRQ_CTRL_REG + bank * IRQ_MEM_SIZE;
+       return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE;
 }
 
-static inline u32 sunxi_irq_ctrl_reg(u16 irq)
+static inline u32 sunxi_irq_ctrl_reg(u16 irq, unsigned bank_base)
 {
        u8 bank = irq / IRQ_PER_BANK;
 
-       return sunxi_irq_ctrl_reg_from_bank(bank);
+       return sunxi_irq_ctrl_reg_from_bank(bank, bank_base);
 }
 
 static inline u32 sunxi_irq_ctrl_offset(u16 irq)
@@ -265,16 +266,16 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
        return irq_num * IRQ_CTRL_IRQ_BITS;
 }
 
-static inline u32 sunxi_irq_status_reg_from_bank(u8 bank)
+static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base)
 {
-       return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE;
+       return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;
 }
 
-static inline u32 sunxi_irq_status_reg(u16 irq)
+static inline u32 sunxi_irq_status_reg(u16 irq, unsigned bank_base)
 {
        u8 bank = irq / IRQ_PER_BANK;
 
-       return sunxi_irq_status_reg_from_bank(bank);
+       return sunxi_irq_status_reg_from_bank(bank, bank_base);
 }
 
 static inline u32 sunxi_irq_status_offset(u16 irq)
index d78ee151c9e4a703bbeb071cda98032cd03dccee..be3bc2f4edd4279d04749aba6db4f93aedf06c4f 100644 (file)
@@ -864,6 +864,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
                },
        },
+       {
+               .ident = "Lenovo ideapad Y700-15ISK",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"),
+               },
+       },
+       {
+               .ident = "Lenovo ideapad Y700 Touch-15ISK",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"),
+               },
+       },
        {
                .ident = "Lenovo ideapad Y700-17ISK",
                .matches = {
index b0f62141ea4d975fe65cc26d892fd494190235bd..f774cb576ffa0631d2200007785161a457408083 100644 (file)
@@ -131,7 +131,7 @@ MODULE_LICENSE("GPL");
 /* Field definitions */
 #define HCI_ACCEL_MASK                 0x7fff
 #define HCI_HOTKEY_DISABLE             0x0b
-#define HCI_HOTKEY_ENABLE              0x01
+#define HCI_HOTKEY_ENABLE              0x09
 #define HCI_HOTKEY_SPECIAL_FUNCTIONS   0x10
 #define HCI_LCD_BRIGHTNESS_BITS                3
 #define HCI_LCD_BRIGHTNESS_SHIFT       (16-HCI_LCD_BRIGHTNESS_BITS)
index 423ce087cd9c881168bb6894c89041fc0cf522cc..5d5adee1688624ed4123ae9f6fbb821e6e337364 100644 (file)
@@ -274,8 +274,8 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        p->base = devm_ioremap_resource(&pdev->dev, res);
-       if (!p->base) {
-               ret = -ENOMEM;
+       if (IS_ERR(p->base)) {
+               ret = PTR_ERR(p->base);
                goto out_clk;
        }
 
index 73b7683355cd015791114249defc26fdf2b644cf..732ac71b82cdd5981454dec04da6ad2cad6c4cba 100644 (file)
@@ -132,24 +132,24 @@ static bool have_full_constraints(void)
        return has_full_constraints || of_have_populated_dt();
 }
 
+static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
+{
+       if (rdev && rdev->supply)
+               return rdev->supply->rdev;
+
+       return NULL;
+}
+
 /**
  * regulator_lock_supply - lock a regulator and its supplies
  * @rdev:         regulator source
  */
 static void regulator_lock_supply(struct regulator_dev *rdev)
 {
-       struct regulator *supply;
-       int i = 0;
-
-       while (1) {
-               mutex_lock_nested(&rdev->mutex, i++);
-               supply = rdev->supply;
-
-               if (!rdev->supply)
-                       return;
+       int i;
 
-               rdev = supply->rdev;
-       }
+       for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
+               mutex_lock_nested(&rdev->mutex, i);
 }
 
 /**
index 58f5d3b8e9818a224c58e1299fdb769f94fd4f98..27343e1c43ef8bee1b3e10dbaf79f293bd81b70f 100644 (file)
@@ -202,9 +202,10 @@ static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id,
                }
        }
 
-       if (i < s5m8767->num_regulators)
-               *enable_ctrl =
-               s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
+       if (i >= s5m8767->num_regulators)
+               return -EINVAL;
+
+       *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT;
 
        return 0;
 }
@@ -937,8 +938,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
                        else
                                regulators[id].vsel_mask = 0xff;
 
-                       s5m8767_get_register(s5m8767, id, &enable_reg,
+                       ret = s5m8767_get_register(s5m8767, id, &enable_reg,
                                             &enable_val);
+                       if (ret) {
+                               dev_err(s5m8767->dev, "error reading registers\n");
+                               return ret;
+                       }
                        regulators[id].enable_reg = enable_reg;
                        regulators[id].enable_mask = S5M8767_ENCTRL_MASK;
                        regulators[id].enable_val = enable_val;
index 05a51ef52703271dc195ec4fad27a498adcb5578..d5c1b057a739e65933d2cd2aa1f8733cc1cd00a9 100644 (file)
@@ -187,9 +187,9 @@ ds1685_rtc_end_data_access(struct ds1685_priv *rtc)
  * Only use this where you are certain another lock will not be held.
  */
 static inline void
-ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long *flags)
 {
-       spin_lock_irqsave(&rtc->lock, flags);
+       spin_lock_irqsave(&rtc->lock, *flags);
        ds1685_rtc_switch_to_bank1(rtc);
 }
 
@@ -1304,7 +1304,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
 {
        struct ds1685_priv *rtc = dev_get_drvdata(dev);
        u8 reg = 0, bit = 0, tmp;
-       unsigned long flags = 0;
+       unsigned long flags;
        long int val = 0;
        const struct ds1685_rtc_ctrl_regs *reg_info =
                ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
@@ -1325,7 +1325,7 @@ ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
        bit = reg_info->bit;
 
        /* Safe to spinlock during a write. */
-       ds1685_rtc_begin_ctrl_access(rtc, flags);
+       ds1685_rtc_begin_ctrl_access(rtc, &flags);
        tmp = rtc->read(rtc, reg);
        rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
        ds1685_rtc_end_ctrl_access(rtc, flags);
index 097325d96db566e08ec8b70aaa9d595f6a044235..b1b4746a0eab5af524791d0868d8132d8014be4b 100644 (file)
@@ -144,7 +144,7 @@ static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
         * it does not seem to carry it over a subsequent write/read.
         * So we'll limit ourself to 100 years, starting at 2000 for now.
         */
-       buf[6] = tm->tm_year - 100;
+       buf[6] = bin2bcd(tm->tm_year - 100);
 
        /*
         * CTL1 only contains TEST-mode bits apart from stop,
index 7184a0eda79384f8a59a5c8be8155018ba1a792e..725dccae24e7b2eabad90951449b9f3804f18ae9 100644 (file)
@@ -465,7 +465,7 @@ static int max77686_rtc_probe(struct platform_device *pdev)
 
        info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
                                         MAX77686_RTCIRQ_RTCA1);
-       if (!info->virq) {
+       if (info->virq <= 0) {
                ret = -ENXIO;
                goto err_rtc;
        }
index bd911bafb809a2ede1c46c3f2e2877ac7507fc50..17341feadad19f55ce126c4e3c2d2d2c8fe0429b 100644 (file)
@@ -65,7 +65,6 @@
 
 static const struct i2c_device_id rx8025_id[] = {
        { "rx8025", 0 },
-       { "rv8803", 1 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rx8025_id);
index f64c282275b3988a7a3b5a1a43af44f4d5c1f05e..e1b86bb0106233f19ec0eb29de11dceb38a31b6e 100644 (file)
@@ -272,12 +272,13 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
 }
 
 static const struct rtc_class_ops vr41xx_rtc_ops = {
-       .release        = vr41xx_rtc_release,
-       .ioctl          = vr41xx_rtc_ioctl,
-       .read_time      = vr41xx_rtc_read_time,
-       .set_time       = vr41xx_rtc_set_time,
-       .read_alarm     = vr41xx_rtc_read_alarm,
-       .set_alarm      = vr41xx_rtc_set_alarm,
+       .release                = vr41xx_rtc_release,
+       .ioctl                  = vr41xx_rtc_ioctl,
+       .read_time              = vr41xx_rtc_read_time,
+       .set_time               = vr41xx_rtc_set_time,
+       .read_alarm             = vr41xx_rtc_read_alarm,
+       .set_alarm              = vr41xx_rtc_set_alarm,
+       .alarm_irq_enable       = vr41xx_rtc_alarm_irq_enable,
 };
 
 static int rtc_probe(struct platform_device *pdev)
index 074878b55a0b7d9f371fe5bc57b2714e01074fdb..d044f3f273be29bde4dcb3cf2caef6c5ed35a487 100644 (file)
@@ -944,6 +944,7 @@ struct fib {
         */
        struct list_head        fiblink;
        void                    *data;
+       u32                     vector_no;
        struct hw_fib           *hw_fib_va;             /* Actual shared object */
        dma_addr_t              hw_fib_pa;              /* physical address of hw_fib*/
 };
@@ -2113,6 +2114,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
 int aac_acquire_irq(struct aac_dev *dev);
 void aac_free_irq(struct aac_dev *dev);
 const char *aac_driverinfo(struct Scsi_Host *);
+void aac_fib_vector_assign(struct aac_dev *dev);
 struct fib *aac_fib_alloc(struct aac_dev *dev);
 int aac_fib_setup(struct aac_dev *dev);
 void aac_fib_map_free(struct aac_dev *dev);
index a1f90fe849c95201f410972b34413f45e484802e..4cbf54928640cb2fcbdb095684db5b0e76c30a10 100644 (file)
@@ -83,13 +83,38 @@ static int fib_map_alloc(struct aac_dev *dev)
 
 void aac_fib_map_free(struct aac_dev *dev)
 {
-       pci_free_consistent(dev->pdev,
-         dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
-         dev->hw_fib_va, dev->hw_fib_pa);
+       if (dev->hw_fib_va && dev->max_fib_size) {
+               pci_free_consistent(dev->pdev,
+               (dev->max_fib_size *
+               (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
+               dev->hw_fib_va, dev->hw_fib_pa);
+       }
        dev->hw_fib_va = NULL;
        dev->hw_fib_pa = 0;
 }
 
+void aac_fib_vector_assign(struct aac_dev *dev)
+{
+       u32 i = 0;
+       u32 vector = 1;
+       struct fib *fibptr = NULL;
+
+       for (i = 0, fibptr = &dev->fibs[i];
+               i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+               i++, fibptr++) {
+               if ((dev->max_msix == 1) ||
+                 (i > ((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1)
+                       - dev->vector_cap))) {
+                       fibptr->vector_no = 0;
+               } else {
+                       fibptr->vector_no = vector;
+                       vector++;
+                       if (vector == dev->max_msix)
+                               vector = 1;
+               }
+       }
+}
+
 /**
  *     aac_fib_setup   -       setup the fibs
  *     @dev: Adapter to set up
@@ -151,6 +176,12 @@ int aac_fib_setup(struct aac_dev * dev)
                hw_fib_pa = hw_fib_pa +
                        dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
        }
+
+       /*
+        *Assign vector numbers to fibs
+        */
+       aac_fib_vector_assign(dev);
+
        /*
         *      Add the fib chain to the free list
         */
index 3b6e5c67e853d96aeafeee16859d19bfa3731a5b..aa6eccb8940bc7ac900a35e87c57aa0ea2226b2f 100644 (file)
@@ -1404,8 +1404,18 @@ static int aac_acquire_resources(struct aac_dev *dev)
 
        aac_adapter_enable_int(dev);
 
-       if (!dev->sync_mode)
+       /*max msix may change  after EEH
+        * Re-assign vectors to fibs
+        */
+       aac_fib_vector_assign(dev);
+
+       if (!dev->sync_mode) {
+               /* After EEH recovery or suspend resume, max_msix count
+                * may change, therfore updating in init as well.
+                */
                aac_adapter_start(dev);
+               dev->init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
+       }
        return 0;
 
 error_iounmap:
index 2aa34ea8ceb1e903781331acd3283ba264eadd53..bc0203f3d243e8e8926e1975408017d9dd5f5012 100644 (file)
@@ -156,8 +156,8 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
                                break;
                        if (dev->msi_enabled && dev->max_msix > 1)
                                atomic_dec(&dev->rrq_outstanding[vector_no]);
-                       aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
                        dev->host_rrq[index++] = 0;
+                       aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
                        if (index == (vector_no + 1) * dev->vector_cap)
                                index = vector_no * dev->vector_cap;
                        dev->host_rrq_idx[vector_no] = index;
@@ -452,36 +452,20 @@ static int aac_src_deliver_message(struct fib *fib)
 #endif
 
        u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
+       u16 vector_no;
 
        atomic_inc(&q->numpending);
 
        if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
            dev->max_msix > 1) {
-               u_int16_t vector_no, first_choice = 0xffff;
-
-               vector_no = dev->fibs_pushed_no % dev->max_msix;
-               do {
-                       vector_no += 1;
-                       if (vector_no == dev->max_msix)
-                               vector_no = 1;
-                       if (atomic_read(&dev->rrq_outstanding[vector_no]) <
-                           dev->vector_cap)
-                               break;
-                       if (0xffff == first_choice)
-                               first_choice = vector_no;
-                       else if (vector_no == first_choice)
-                               break;
-               } while (1);
-               if (vector_no == first_choice)
-                       vector_no = 0;
-               atomic_inc(&dev->rrq_outstanding[vector_no]);
-               if (dev->fibs_pushed_no == 0xffffffff)
-                       dev->fibs_pushed_no = 0;
-               else
-                       dev->fibs_pushed_no++;
+               vector_no = fib->vector_no;
                fib->hw_fib_va->header.Handle += (vector_no << 16);
+       } else {
+               vector_no = 0;
        }
 
+       atomic_inc(&dev->rrq_outstanding[vector_no]);
+
        if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
                /* Calculate the amount to the fibsize bits */
                fibsize = (hdr_size + 127) / 128 - 1;
index b846a4683562ca8ddd472becdb70a9a3d56387bf..fc6a83188c1e0fab6a2bb4583eda2a2d6771c619 100644 (file)
@@ -1336,6 +1336,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
        case AHC_DEV_Q_TAGGED:
                scsi_change_queue_depth(sdev,
                                dev->openings + dev->active);
+               break;
        default:
                /*
                 * We allow the OS to queue 2 untagged transactions to
index fe0c5143f8e68a6cb3e9618c98258c9e4118e1ae..758f76e88704c3d63af5b5be87eb20db1820eccb 100644 (file)
@@ -4470,6 +4470,7 @@ put_shost:
        scsi_host_put(phba->shost);
 free_kset:
        iscsi_boot_destroy_kset(phba->boot_kset);
+       phba->boot_kset = NULL;
        return -ENOMEM;
 }
 
index e5647d59224fca77a44b2ab8e3bf7662c457eb4c..0b331c9c0a8f8624ae5f1fc239836a8dc0fbccda 100644 (file)
@@ -13,13 +13,13 @@ menuconfig SCSI_DH
 
 config SCSI_DH_RDAC
        tristate "LSI RDAC Device Handler"
-       depends on SCSI_DH
+       depends on SCSI_DH && SCSI
        help
        If you have a LSI RDAC select y. Otherwise, say N.
 
 config SCSI_DH_HP_SW
        tristate "HP/COMPAQ MSA Device Handler"
-       depends on SCSI_DH
+       depends on SCSI_DH && SCSI
        help
        If you have a HP/COMPAQ MSA device that requires START_STOP to
        be sent to start it and cannot upgrade the firmware then select y.
@@ -27,13 +27,13 @@ config SCSI_DH_HP_SW
 
 config SCSI_DH_EMC
        tristate "EMC CLARiiON Device Handler"
-       depends on SCSI_DH
+       depends on SCSI_DH && SCSI
        help
        If you have a EMC CLARiiON select y. Otherwise, say N.
 
 config SCSI_DH_ALUA
        tristate "SPC-3 ALUA Device Handler"
-       depends on SCSI_DH
+       depends on SCSI_DH && SCSI
        help
          SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
          Access (ALUA).
index 536cd5a8042245f4ad46929a256098e047d745dd..43ac62623bf266578c575875e5802fc3613aed54 100644 (file)
@@ -4003,13 +4003,17 @@ static ssize_t ipr_store_update_fw(struct device *dev,
        struct ipr_sglist *sglist;
        char fname[100];
        char *src;
-       int len, result, dnld_size;
+       char *endline;
+       int result, dnld_size;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       len = snprintf(fname, 99, "%s", buf);
-       fname[len-1] = '\0';
+       snprintf(fname, sizeof(fname), "%s", buf);
+
+       endline = strchr(fname, '\n');
+       if (endline)
+               *endline = '\0';
 
        if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
                dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
index db9446c612dadf1ffebb3de4803eb4a59ec6442f..b0d92b84bcdc201b2d0ccec4338197ed6409c5e8 100644 (file)
@@ -2855,7 +2855,7 @@ lpfc_online(struct lpfc_hba *phba)
        }
 
        vports = lpfc_create_vport_work_array(phba);
-       if (vports != NULL)
+       if (vports != NULL) {
                for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        struct Scsi_Host *shost;
                        shost = lpfc_shost_from_vport(vports[i]);
@@ -2872,7 +2872,8 @@ lpfc_online(struct lpfc_hba *phba)
                        }
                        spin_unlock_irq(shost->host_lock);
                }
-               lpfc_destroy_vport_work_array(phba, vports);
+       }
+       lpfc_destroy_vport_work_array(phba, vports);
 
        lpfc_unblock_mgmt_io(phba);
        return 0;
index 97a1c1c33b05dd2ba7e2dfe4feb3469dce3b6199..00ce3e269a437389232ee3ffb43ee2e1ccbe53b3 100644 (file)
@@ -6282,12 +6282,13 @@ out:
        }
 
        for (i = 0; i < ioc->sge_count; i++) {
-               if (kbuff_arr[i])
+               if (kbuff_arr[i]) {
                        dma_free_coherent(&instance->pdev->dev,
                                          le32_to_cpu(kern_sge32[i].length),
                                          kbuff_arr[i],
                                          le32_to_cpu(kern_sge32[i].phys_addr));
                        kbuff_arr[i] = NULL;
+               }
        }
 
        megasas_return_cmd(instance, cmd);
index c126966130ab792b5dac44ab4a96f4c272debe66..ce79de822e461b37050ca6435bd91f5ed7bb55b7 100644 (file)
@@ -278,8 +278,16 @@ int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
                ucp[3] = 0;
                put_unaligned_be64(info, &ucp[4]);
        } else if ((buf[0] & 0x7f) == 0x70) {
-               buf[0] |= 0x80;
-               put_unaligned_be64(info, &buf[3]);
+               /*
+                * Only set the 'VALID' bit if we can represent the value
+                * correctly; otherwise just fill out the lower bytes and
+                * clear the 'VALID' flag.
+                */
+               if (info <= 0xffffffffUL)
+                       buf[0] |= 0x80;
+               else
+                       buf[0] &= 0x7f;
+               put_unaligned_be32((u32)info, &buf[3]);
        }
 
        return 0;
index bb669d32ccd0daee203a69840313fcb9cf343ee0..0d7c6e86f1492ebcce95d257f358969128db8154 100644 (file)
@@ -648,7 +648,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
         */
        if (sdkp->lbprz) {
                q->limits.discard_alignment = 0;
-               q->limits.discard_granularity = 1;
+               q->limits.discard_granularity = logical_block_size;
        } else {
                q->limits.discard_alignment = sdkp->unmap_alignment *
                        logical_block_size;
@@ -1275,18 +1275,19 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
        struct scsi_device *sdp = sdkp->device;
        struct Scsi_Host *host = sdp->host;
+       sector_t capacity = logical_to_sectors(sdp, sdkp->capacity);
        int diskinfo[4];
 
        /* default to most commonly used values */
-        diskinfo[0] = 0x40;    /* 1 << 6 */
-               diskinfo[1] = 0x20;     /* 1 << 5 */
-               diskinfo[2] = sdkp->capacity >> 11;
-       
+       diskinfo[0] = 0x40;     /* 1 << 6 */
+       diskinfo[1] = 0x20;     /* 1 << 5 */
+       diskinfo[2] = capacity >> 11;
+
        /* override with calculated, extended default, or driver values */
        if (host->hostt->bios_param)
-               host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);
+               host->hostt->bios_param(sdp, bdev, capacity, diskinfo);
        else
-               scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+               scsicam_bios_param(bdev, capacity, diskinfo);
 
        geo->heads = diskinfo[0];
        geo->sectors = diskinfo[1];
@@ -2337,14 +2338,6 @@ got_data:
        if (sdkp->capacity > 0xffffffff)
                sdp->use_16_for_rw = 1;
 
-       /* Rescale capacity to 512-byte units */
-       if (sector_size == 4096)
-               sdkp->capacity <<= 3;
-       else if (sector_size == 2048)
-               sdkp->capacity <<= 2;
-       else if (sector_size == 1024)
-               sdkp->capacity <<= 1;
-
        blk_queue_physical_block_size(sdp->request_queue,
                                      sdkp->physical_block_size);
        sdkp->device->sector_size = sector_size;
@@ -2812,11 +2805,6 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
        return 0;
 }
 
-static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks)
-{
-       return blocks << (ilog2(sdev->sector_size) - 9);
-}
-
 /**
  *     sd_revalidate_disk - called the first time a new disk is seen,
  *     performs disk spin up, read_capacity, etc.
@@ -2900,7 +2888,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
        /* Combine with controller limits */
        q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
 
-       set_capacity(disk, sdkp->capacity);
+       set_capacity(disk, logical_to_sectors(sdp, sdkp->capacity));
        sd_config_write_same(sdkp);
        kfree(buffer);
 
index 5f2a84aff29fb9cbd003e5bbe6996355a5c07075..654630bb7d0edeb48438654e47d8a60151d2c87b 100644 (file)
@@ -65,7 +65,7 @@ struct scsi_disk {
        struct device   dev;
        struct gendisk  *disk;
        atomic_t        openers;
-       sector_t        capacity;       /* size in 512-byte sectors */
+       sector_t        capacity;       /* size in logical blocks */
        u32             max_xfer_blocks;
        u32             opt_xfer_blocks;
        u32             max_ws_blocks;
@@ -146,6 +146,11 @@ static inline int scsi_medium_access_command(struct scsi_cmnd *scmd)
        return 0;
 }
 
+static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blocks)
+{
+       return blocks << (ilog2(sdev->sector_size) - 9);
+}
+
 /*
  * A DIF-capable target device can be formatted with different
  * protection schemes.  Currently 0 through 3 are defined:
index 5e820674432ca38c46ad154b831c8eb19e974d34..ae7d9bdf409c816d014ac2d668a1e449fce0c8e9 100644 (file)
@@ -652,7 +652,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
        else
                hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
        hp->dxfer_len = mxsize;
-       if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+       if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
+           (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
                hp->dxferp = (char __user *)buf + cmd_size;
        else
                hp->dxferp = NULL;
index 3fba42ad9fb8aee55d5015167a9cb9ad601fb1a7..0f636cc4c809f1126b7aa9b2023bafba10a121af 100644 (file)
@@ -889,8 +889,9 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
                do_work = true;
                process_err_fn = storvsc_remove_lun;
                break;
-       case (SRB_STATUS_ABORTED | SRB_STATUS_AUTOSENSE_VALID):
-               if ((asc == 0x2a) && (ascq == 0x9)) {
+       case SRB_STATUS_ABORTED:
+               if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
+                   (asc == 0x2a) && (ascq == 0x9)) {
                        do_work = true;
                        process_err_fn = storvsc_device_scan;
                        /*
index 94a80e631ff8c61eaf1e5fbd82f43bf381670761..bd1f1c4e5f8020750d623dd713eddeec4e941413 100644 (file)
@@ -596,6 +596,7 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
                if (error) {
                        dev_err(dev, "failed to handle node %s: %d\n",
                                node->name, error);
+                       of_node_put(node);
                        goto err_out;
                }
 
index f81822a2503f3cdc8dff556388909c6e229a4baf..c4fdafbce8883f2f7afad9e64917e51c01e9259a 100644 (file)
@@ -255,8 +255,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
         * memory coming from the heaps is ready for dma, ie if it has a
         * cached mapping that mapping has been invalidated
         */
-       for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
+       for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
                sg_dma_address(sg) = sg_phys(sg);
+               sg_dma_len(sg) = sg->length;
+       }
        mutex_lock(&dev->buffer_lock);
        ion_buffer_add(dev, buffer);
        mutex_unlock(&dev->buffer_lock);
index b8dcf5a26cc4ac1250bda0ded24d1ceff3c8cf24..58d46893e5ffdec7256bdae2e553560a7209e7c5 100644 (file)
@@ -285,8 +285,8 @@ static int __init ion_test_init(void)
 {
        ion_test_pdev = platform_device_register_simple("ion-test",
                                                        -1, NULL, 0);
-       if (!ion_test_pdev)
-               return -ENODEV;
+       if (IS_ERR(ion_test_pdev))
+               return PTR_ERR(ion_test_pdev);
 
        return platform_driver_probe(&ion_test_platform_driver, ion_test_probe);
 }
index 6cc304a4c59bfca17a6055d99631424ebeafa09f..27fbf1a810975e86faa7819f06ff717ae842d957 100644 (file)
@@ -246,24 +246,24 @@ static void ni_writel(struct comedi_device *dev, uint32_t data, int reg)
 {
        if (dev->mmio)
                writel(data, dev->mmio + reg);
-
-       outl(data, dev->iobase + reg);
+       else
+               outl(data, dev->iobase + reg);
 }
 
 static void ni_writew(struct comedi_device *dev, uint16_t data, int reg)
 {
        if (dev->mmio)
                writew(data, dev->mmio + reg);
-
-       outw(data, dev->iobase + reg);
+       else
+               outw(data, dev->iobase + reg);
 }
 
 static void ni_writeb(struct comedi_device *dev, uint8_t data, int reg)
 {
        if (dev->mmio)
                writeb(data, dev->mmio + reg);
-
-       outb(data, dev->iobase + reg);
+       else
+               outb(data, dev->iobase + reg);
 }
 
 static uint32_t ni_readl(struct comedi_device *dev, int reg)
index 437f723bb34d536600f8805100dcb4b455c01844..823e47910004139e0a62fe88de15a0be135b8930 100644 (file)
@@ -92,7 +92,7 @@ static int ni_tio_input_inttrig(struct comedi_device *dev,
        unsigned long flags;
        int ret = 0;
 
-       if (trig_num != cmd->start_src)
+       if (trig_num != cmd->start_arg)
                return -EINVAL;
 
        spin_lock_irqsave(&counter->lock, flags);
index 05de0dad8762eb4332e36ec100c072f4e6ce4ea3..4c6f1d7d2eaf21d17bffa1cc2f0f624052e16f22 100644 (file)
@@ -3,4 +3,4 @@ July, 2015
 - Remove unneeded file entries in sysfs
 - Remove software processing of IB protocol and place in library for use
   by qib, ipath (if still present), hfi1, and eventually soft-roce
-
+- Replace incorrect uAPI
index aae9826ec62bea8e86a6f1f7c4408ff574d72204..c851e51b1dc3b6d306ac4dde117e9f6fe07be73e 100644 (file)
@@ -62,6 +62,8 @@
 #include <linux/cred.h>
 #include <linux/uio.h>
 
+#include <rdma/ib.h>
+
 #include "hfi.h"
 #include "pio.h"
 #include "device.h"
@@ -214,6 +216,10 @@ static ssize_t hfi1_file_write(struct file *fp, const char __user *data,
        int uctxt_required = 1;
        int must_be_root = 0;
 
+       /* FIXME: This interface cannot continue out of staging */
+       if (WARN_ON_ONCE(!ib_safe_file_access(fp)))
+               return -EACCES;
+
        if (count < sizeof(cmd)) {
                ret = -EINVAL;
                goto bail;
index 94f4ffac723f4263f9fb5e6afc4e32dee6ac99e2..d151bc3d6971b0204613e64cdb136ad98615d3dd 100644 (file)
@@ -2618,8 +2618,6 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
 
        list_for_each_entry_safe(se_cmd, tmp_cmd,
                                &se_sess->sess_wait_list, se_cmd_list) {
-               list_del_init(&se_cmd->se_cmd_list);
-
                pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
                        " %d\n", se_cmd, se_cmd->t_state,
                        se_cmd->se_tfo->get_cmd_state(se_cmd));
index 05c66b796b2052f5d22bc4d9278133153601d477..b26e6f7a050c3d126422c5871350d46dd64f3f04 100644 (file)
@@ -454,6 +454,10 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
 {
        enum thermal_trip_type type;
 
+       /* Ignore disabled trip points */
+       if (test_bit(trip, &tz->trips_disabled))
+               return;
+
        tz->ops->get_trip_type(tz, trip, &type);
 
        if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
@@ -1845,6 +1849,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 {
        struct thermal_zone_device *tz;
        enum thermal_trip_type trip_type;
+       int trip_temp;
        int result;
        int count;
        int passive = 0;
@@ -1919,9 +1924,15 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
                goto unregister;
 
        for (count = 0; count < trips; count++) {
-               tz->ops->get_trip_type(tz, count, &trip_type);
+               if (tz->ops->get_trip_type(tz, count, &trip_type))
+                       set_bit(count, &tz->trips_disabled);
                if (trip_type == THERMAL_TRIP_PASSIVE)
                        passive = 1;
+               if (tz->ops->get_trip_temp(tz, count, &trip_temp))
+                       set_bit(count, &tz->trips_disabled);
+               /* Check for bogus trip points */
+               if (trip_temp == 0)
+                       set_bit(count, &tz->trips_disabled);
        }
 
        if (!passive) {
index 52d82d2ac726be56d5838b872b9049b3c7729188..56ccbcefdd850d435b6fe9b8e71e48a2df71d6e5 100644 (file)
@@ -713,22 +713,16 @@ static int size_fifo(struct uart_8250_port *up)
  */
 static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
 {
-       unsigned char old_dll, old_dlm, old_lcr;
-       unsigned int id;
+       unsigned char old_lcr;
+       unsigned int id, old_dl;
 
        old_lcr = serial_in(p, UART_LCR);
        serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A);
+       old_dl = serial_dl_read(p);
+       serial_dl_write(p, 0);
+       id = serial_dl_read(p);
+       serial_dl_write(p, old_dl);
 
-       old_dll = serial_in(p, UART_DLL);
-       old_dlm = serial_in(p, UART_DLM);
-
-       serial_out(p, UART_DLL, 0);
-       serial_out(p, UART_DLM, 0);
-
-       id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8;
-
-       serial_out(p, UART_DLL, old_dll);
-       serial_out(p, UART_DLM, old_dlm);
        serial_out(p, UART_LCR, old_lcr);
 
        return id;
index 51c7507b0444957bcbc9c2c832bd6048a5f3b596..63a06ab6ba038ad543de7755301180e961a3933a 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/major.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -116,8 +115,6 @@ struct sci_port {
        struct timer_list               rx_timer;
        unsigned int                    rx_timeout;
 #endif
-
-       struct notifier_block           freq_transition;
 };
 
 #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@@ -1606,29 +1603,6 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
        return ret;
 }
 
-/*
- * Here we define a transition notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
-                       unsigned long phase, void *p)
-{
-       struct sci_port *sci_port;
-       unsigned long flags;
-
-       sci_port = container_of(self, struct sci_port, freq_transition);
-
-       if (phase == CPUFREQ_POSTCHANGE) {
-               struct uart_port *port = &sci_port->port;
-
-               spin_lock_irqsave(&port->lock, flags);
-               port->uartclk = clk_get_rate(sci_port->iclk);
-               spin_unlock_irqrestore(&port->lock, flags);
-       }
-
-       return NOTIFY_OK;
-}
-
 static const struct sci_irq_desc {
        const char      *desc;
        irq_handler_t   handler;
@@ -2559,9 +2533,6 @@ static int sci_remove(struct platform_device *dev)
 {
        struct sci_port *port = platform_get_drvdata(dev);
 
-       cpufreq_unregister_notifier(&port->freq_transition,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-
        uart_remove_one_port(&sci_uart_driver, &port->port);
 
        sci_cleanup_single(port);
@@ -2714,16 +2685,6 @@ static int sci_probe(struct platform_device *dev)
        if (ret)
                return ret;
 
-       sp->freq_transition.notifier_call = sci_notifier;
-
-       ret = cpufreq_register_notifier(&sp->freq_transition,
-                                       CPUFREQ_TRANSITION_NOTIFIER);
-       if (unlikely(ret < 0)) {
-               uart_remove_one_port(&sci_uart_driver, &sp->port);
-               sci_cleanup_single(sp);
-               return ret;
-       }
-
 #ifdef CONFIG_SH_STANDARD_BIOS
        sh_bios_gdb_detach();
 #endif
index fa4e23930614a47ac14ece43e863286fadb91402..d37fdcc3143c0c097a53b35cc3b6b9edc81eaa78 100644 (file)
@@ -1114,6 +1114,9 @@ static int acm_probe(struct usb_interface *intf,
        if (quirks == NO_UNION_NORMAL) {
                data_interface = usb_ifnum_to_if(usb_dev, 1);
                control_interface = usb_ifnum_to_if(usb_dev, 0);
+               /* we would crash */
+               if (!data_interface || !control_interface)
+                       return -ENODEV;
                goto skip_normal_probe;
        }
 
index 56593a9a87268cc0f6d8181cb5f8021c252b457b..2057d91d83360ddb614ffaeeb174883c1759f7cf 100644 (file)
@@ -502,11 +502,15 @@ static int usb_unbind_interface(struct device *dev)
 int usb_driver_claim_interface(struct usb_driver *driver,
                                struct usb_interface *iface, void *priv)
 {
-       struct device *dev = &iface->dev;
+       struct device *dev;
        struct usb_device *udev;
        int retval = 0;
        int lpm_disable_error;
 
+       if (!iface)
+               return -ENODEV;
+
+       dev = &iface->dev;
        if (dev->driver)
                return -EBUSY;
 
index 9eb1cff28bd4b2499e4dfd9ed8b91e53901df184..b8b580e5ae6e369f2bf1033e3dc054817b51f125 100644 (file)
@@ -74,6 +74,15 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
                if (companion->bus != pdev->bus ||
                                PCI_SLOT(companion->devfn) != slot)
                        continue;
+
+               /*
+                * Companion device should be either UHCI,OHCI or EHCI host
+                * controller, otherwise skip.
+                */
+               if (companion->class != CL_UHCI && companion->class != CL_OHCI &&
+                               companion->class != CL_EHCI)
+                       continue;
+
                companion_hcd = pci_get_drvdata(companion);
                if (!companion_hcd || !companion_hcd->self.root_hub)
                        continue;
index 1560f3f3e75661d8d11a76d2e743b78f57290f96..84df093639acb18c37e7b8b45bb878d0aca2bf5a 100644 (file)
@@ -4277,7 +4277,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
 {
        struct usb_device       *hdev = hub->hdev;
        struct usb_hcd          *hcd = bus_to_hcd(hdev->bus);
-       int                     i, j, retval;
+       int                     retries, operations, retval, i;
        unsigned                delay = HUB_SHORT_RESET_TIME;
        enum usb_device_speed   oldspeed = udev->speed;
        const char              *speed;
@@ -4379,7 +4379,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
         * first 8 bytes of the device descriptor to get the ep0 maxpacket
         * value.
         */
-       for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
+       for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
                bool did_new_scheme = false;
 
                if (use_new_scheme(udev, retry_counter)) {
@@ -4406,7 +4406,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
                         * 255 is for WUSB devices, we actually need to use
                         * 512 (WUSB1.0[4.8.1]).
                         */
-                       for (j = 0; j < 3; ++j) {
+                       for (operations = 0; operations < 3; ++operations) {
                                buf->bMaxPacketSize0 = 0;
                                r = usb_control_msg(udev, usb_rcvaddr0pipe(),
                                        USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
@@ -4426,7 +4426,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
                                                r = -EPROTO;
                                        break;
                                }
-                               if (r == 0)
+                               /*
+                                * Some devices time out if they are powered on
+                                * when already connected. They need a second
+                                * reset. But only on the first attempt,
+                                * lest we get into a time out/reset loop
+                                */
+                               if (r == 0  || (r == -ETIMEDOUT && retries == 0))
                                        break;
                        }
                        udev->descriptor.bMaxPacketSize0 =
@@ -4458,7 +4464,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
                 * authorization will assign the final address.
                 */
                if (udev->wusb == 0) {
-                       for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
+                       for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
                                retval = hub_set_address(udev, devnum);
                                if (retval >= 0)
                                        break;
@@ -5386,6 +5392,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
        }
 
        bos = udev->bos;
+       udev->bos = NULL;
 
        for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 
@@ -5478,11 +5485,8 @@ done:
        usb_set_usb2_hardware_lpm(udev, 1);
        usb_unlocked_enable_lpm(udev);
        usb_enable_ltm(udev);
-       /* release the new BOS descriptor allocated  by hub_port_init() */
-       if (udev->bos != bos) {
-               usb_release_bos_descriptor(udev);
-               udev->bos = bos;
-       }
+       usb_release_bos_descriptor(udev);
+       udev->bos = bos;
        return 0;
 
 re_enumerate:
index cf43e9e18368dcd84668b9378b1036b17276b593..79d895c2dd715aaf1463ed05170ae6eec268eec7 100644 (file)
@@ -646,6 +646,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
                                                   work);
        int ret = io_data->req->status ? io_data->req->status :
                                         io_data->req->actual;
+       bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
 
        if (io_data->read && ret > 0) {
                use_mm(io_data->mm);
@@ -657,13 +658,11 @@ static void ffs_user_copy_worker(struct work_struct *work)
 
        io_data->kiocb->ki_complete(io_data->kiocb, ret, ret);
 
-       if (io_data->ffs->ffs_eventfd &&
-           !(io_data->kiocb->ki_flags & IOCB_EVENTFD))
+       if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
                eventfd_signal(io_data->ffs->ffs_eventfd, 1);
 
        usb_ep_free_request(io_data->ep, io_data->req);
 
-       io_data->kiocb->private = NULL;
        if (io_data->read)
                kfree(io_data->to_free);
        kfree(io_data->buf);
index c48cbe731356539abf7df8ac1c94a09701b546f7..d8dbd7e5194b19c7daee1ea44dff8a5de7a8e05b 100644 (file)
@@ -1875,6 +1875,12 @@ no_bw:
        kfree(xhci->rh_bw);
        kfree(xhci->ext_caps);
 
+       xhci->usb2_ports = NULL;
+       xhci->usb3_ports = NULL;
+       xhci->port_array = NULL;
+       xhci->rh_bw = NULL;
+       xhci->ext_caps = NULL;
+
        xhci->page_size = 0;
        xhci->page_shift = 0;
        xhci->bus_state[0].bus_suspended = 0;
index c2d65206ec6c20cfecec9a9b72d7a5de67598855..ea4fb4b0cd44da050192e23b5522e8e6f95295dd 100644 (file)
@@ -48,6 +48,7 @@
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI                0xa12f
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI       0x9d2f
 #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI             0x0aa8
+#define PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI             0x1aa8
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -156,7 +157,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
                 pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
                 pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
-                pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) {
+                pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI)) {
                xhci->quirks |= XHCI_PME_STUCK_QUIRK;
        }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
@@ -299,6 +301,7 @@ static void xhci_pci_remove(struct pci_dev *dev)
        struct xhci_hcd *xhci;
 
        xhci = hcd_to_xhci(pci_get_drvdata(dev));
+       xhci->xhc_state |= XHCI_STATE_REMOVING;
        if (xhci->shared_hcd) {
                usb_remove_hcd(xhci->shared_hcd);
                usb_put_hcd(xhci->shared_hcd);
index db0f0831b94fc2d0c86f270134058a78974cbbdd..2b63969c2bbf8e5f202cb99d3d5c13e5e6f0d502 100644 (file)
@@ -4008,7 +4008,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
        int reserved_trbs = xhci->cmd_ring_reserved_trbs;
        int ret;
 
-       if (xhci->xhc_state) {
+       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+               (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n");
                return -ESHUTDOWN;
        }
index 776d59c32bc5c4191f77829ecdb809f6b2d67b93..ec9e758d5fcd9413c0ca377cdb0a08e19a5404fa 100644 (file)
@@ -146,7 +146,8 @@ static int xhci_start(struct xhci_hcd *xhci)
                                "waited %u microseconds.\n",
                                XHCI_MAX_HALT_USEC);
        if (!ret)
-               xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);
+               /* clear state flags. Including dying, halted or removing */
+               xhci->xhc_state = 0;
 
        return ret;
 }
@@ -1103,8 +1104,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                /* Resume root hubs only when have pending events. */
                status = readl(&xhci->op_regs->status);
                if (status & STS_EINT) {
-                       usb_hcd_resume_root_hub(hcd);
                        usb_hcd_resume_root_hub(xhci->shared_hcd);
+                       usb_hcd_resume_root_hub(hcd);
                }
        }
 
@@ -1119,10 +1120,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 
        /* Re-enable port polling. */
        xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
-       set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
-       usb_hcd_poll_rh_status(hcd);
        set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
        usb_hcd_poll_rh_status(xhci->shared_hcd);
+       set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+       usb_hcd_poll_rh_status(hcd);
 
        return retval;
 }
@@ -2753,7 +2754,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
        if (ret <= 0)
                return ret;
        xhci = hcd_to_xhci(hcd);
-       if (xhci->xhc_state & XHCI_STATE_DYING)
+       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+               (xhci->xhc_state & XHCI_STATE_REMOVING))
                return -ENODEV;
 
        xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
@@ -3800,7 +3802,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
 
        mutex_lock(&xhci->mutex);
 
-       if (xhci->xhc_state)    /* dying or halted */
+       if (xhci->xhc_state)    /* dying, removing or halted */
                goto out;
 
        if (!udev->slot_id) {
index 0b9451250e33f5f82fd52f00cf05338849b81e7c..99ac2289dbf348aa2f60541121f1842a92ecc15b 100644 (file)
@@ -1596,6 +1596,7 @@ struct xhci_hcd {
  */
 #define XHCI_STATE_DYING       (1 << 0)
 #define XHCI_STATE_HALTED      (1 << 1)
+#define XHCI_STATE_REMOVING    (1 << 2)
        /* Statistics */
        int                     error_bitmask;
        unsigned int            quirks;
index c6bfd13f6c92ff416688659b54600026cf382de1..1950e87b4219047908dfdad73fe30650cad7b8ca 100644 (file)
@@ -787,6 +787,12 @@ static int iowarrior_probe(struct usb_interface *interface,
        iface_desc = interface->cur_altsetting;
        dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
 
+       if (iface_desc->desc.bNumEndpoints < 1) {
+               dev_err(&interface->dev, "Invalid number of endpoints\n");
+               retval = -EINVAL;
+               goto error;
+       }
+
        /* set up the endpoint information */
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
index c0f5c652d272c8959f5b3d59461e1af139d6f7fd..f1893e08e51a43649fe71bb2956cd884d4eca4fa 100644 (file)
@@ -190,7 +190,8 @@ static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type)
                goto __usbhs_pkt_handler_end;
        }
 
-       ret = func(pkt, &is_done);
+       if (likely(func))
+               ret = func(pkt, &is_done);
 
        if (is_done)
                __usbhsf_pkt_del(pkt);
@@ -889,6 +890,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
 
        pkt->trans = len;
 
+       usbhsf_tx_irq_ctrl(pipe, 0);
        INIT_WORK(&pkt->work, xfer_work);
        schedule_work(&pkt->work);
 
index 8f7a78e7097598a50e9d7ba3cc72831b41af25b8..fa14198daf77a7d4479566e4d2cfc1845a2c619a 100644 (file)
@@ -158,10 +158,14 @@ static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
        struct usbhs_pipe *pipe = pkt->pipe;
        struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
        struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
+       unsigned long flags;
 
        ureq->req.actual = pkt->actual;
 
-       usbhsg_queue_pop(uep, ureq, 0);
+       usbhs_lock(priv, flags);
+       if (uep)
+               __usbhsg_queue_pop(uep, ureq, 0);
+       usbhs_unlock(priv, flags);
 }
 
 static void usbhsg_queue_push(struct usbhsg_uep *uep,
index 7a76fe4c2f9ea9dc40804c04553c6476177943c0..a2b43a6e7fa76f78a8150aa9b69a65277d79da8e 100644 (file)
@@ -108,6 +108,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
        { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */
        { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
+       { USB_DEVICE(0x10C4, 0x82F4) }, /* Starizona MicroTouch */
        { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
        { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
@@ -117,6 +118,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
        { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
+       { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */
        { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
        { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
        { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
@@ -140,6 +142,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
        { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
        { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
+       { USB_DEVICE(0x12B8, 0xEC60) }, /* Link G4 ECU */
+       { USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */
        { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
        { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
        { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
@@ -164,6 +168,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
        { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
        { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
+       { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
        { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
        { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
        { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
index 01bf533928192d6f2f4b77f44995bd63fd6d1be2..244acb1299a95675fbf44b1668d1d112a6cd7a9d 100644 (file)
@@ -447,6 +447,11 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
        struct usb_serial *serial = port->serial;
        struct cypress_private *priv;
 
+       if (!port->interrupt_out_urb || !port->interrupt_in_urb) {
+               dev_err(&port->dev, "required endpoint is missing\n");
+               return -ENODEV;
+       }
+
        priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
@@ -606,12 +611,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
                cypress_set_termios(tty, port, &priv->tmp_termios);
 
        /* setup the port and start reading from the device */
-       if (!port->interrupt_in_urb) {
-               dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n",
-                       __func__);
-               return -1;
-       }
-
        usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
                usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
                port->interrupt_in_urb->transfer_buffer,
index 12b0e67473ba2509193bf06048b4c0ff627430d5..3df7b7ec178e87adad7ccb1dc4734e02d6a21d29 100644 (file)
@@ -1251,8 +1251,27 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
 
 static int digi_startup(struct usb_serial *serial)
 {
+       struct device *dev = &serial->interface->dev;
        struct digi_serial *serial_priv;
        int ret;
+       int i;
+
+       /* check whether the device has the expected number of endpoints */
+       if (serial->num_port_pointers < serial->type->num_ports + 1) {
+               dev_err(dev, "OOB endpoints missing\n");
+               return -ENODEV;
+       }
+
+       for (i = 0; i < serial->type->num_ports + 1 ; i++) {
+               if (!serial->port[i]->read_urb) {
+                       dev_err(dev, "bulk-in endpoint missing\n");
+                       return -ENODEV;
+               }
+               if (!serial->port[i]->write_urb) {
+                       dev_err(dev, "bulk-out endpoint missing\n");
+                       return -ENODEV;
+               }
+       }
 
        serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
        if (!serial_priv)
index 8c660ae401d8267f951516e33fe8188f0f23e060..b61f12160d37b9ed5bfcd2cfe4e57041d14f5034 100644 (file)
@@ -1004,6 +1004,10 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
+       /* ICP DAS I-756xU devices */
+       { USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
+       { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
+       { USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) },
        { }                                     /* Terminating entry */
 };
 
index a84df2513994a57377cc41105f3078e36d2351a2..c5d6c1e73e8e0450d46dc7140637146404f262bb 100644 (file)
 #define NOVITUS_VID                    0x1a28
 #define NOVITUS_BONO_E_PID             0x6010
 
+/*
+ * ICPDAS I-756*U devices
+ */
+#define ICPDAS_VID                     0x1b5c
+#define ICPDAS_I7560U_PID              0x0103
+#define ICPDAS_I7561U_PID              0x0104
+#define ICPDAS_I7563U_PID              0x0105
+
 /*
  * RT Systems programming cables for various ham radios
  */
index fd707d6a10e26359f4f96502e0bcbb1f1c79bbe1..89726f702202f4d4906ed9b16933998b72975294 100644 (file)
@@ -376,14 +376,21 @@ static void mct_u232_msr_to_state(struct usb_serial_port *port,
 
 static int mct_u232_port_probe(struct usb_serial_port *port)
 {
+       struct usb_serial *serial = port->serial;
        struct mct_u232_private *priv;
 
+       /* check first to simplify error handling */
+       if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) {
+               dev_err(&port->dev, "expected endpoint missing\n");
+               return -ENODEV;
+       }
+
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        /* Use second interrupt-in endpoint for reading. */
-       priv->read_urb = port->serial->port[1]->interrupt_in_urb;
+       priv->read_urb = serial->port[1]->interrupt_in_urb;
        priv->read_urb->context = port;
 
        spin_lock_init(&priv->lock);
index 348e19834b83e12e7aafafa9d46374822fe43f7f..c6f497f1652659dc59e700181f35d75aab6ceae1 100644 (file)
@@ -1818,6 +1818,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff),                     /* D-Link DWM-221 B1 */
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },                /* OLICARD300 - MT6225 */
index 5c66d3f7a6d070c54632751af97ef3c3d660744b..9baf081174cef86fd577b7da82b696942899cdc0 100644 (file)
@@ -2,7 +2,7 @@
  * USB Attached SCSI
  * Note that this is not the same as the USB Mass Storage driver
  *
- * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2014
+ * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016
  * Copyright Matthew Wilcox for Intel Corp, 2010
  * Copyright Sarah Sharp for Intel Corp, 2010
  *
@@ -757,6 +757,17 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
        return SUCCESS;
 }
 
+static int uas_target_alloc(struct scsi_target *starget)
+{
+       struct uas_dev_info *devinfo = (struct uas_dev_info *)
+                       dev_to_shost(starget->dev.parent)->hostdata;
+
+       if (devinfo->flags & US_FL_NO_REPORT_LUNS)
+               starget->no_report_luns = 1;
+
+       return 0;
+}
+
 static int uas_slave_alloc(struct scsi_device *sdev)
 {
        struct uas_dev_info *devinfo =
@@ -800,7 +811,6 @@ static int uas_slave_configure(struct scsi_device *sdev)
        if (devinfo->flags & US_FL_BROKEN_FUA)
                sdev->broken_fua = 1;
 
-       scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
        return 0;
 }
 
@@ -808,11 +818,12 @@ static struct scsi_host_template uas_host_template = {
        .module = THIS_MODULE,
        .name = "uas",
        .queuecommand = uas_queuecommand,
+       .target_alloc = uas_target_alloc,
        .slave_alloc = uas_slave_alloc,
        .slave_configure = uas_slave_configure,
        .eh_abort_handler = uas_eh_abort_handler,
        .eh_bus_reset_handler = uas_eh_bus_reset_handler,
-       .can_queue = 65536,     /* Is there a limit on the _host_ ? */
+       .can_queue = MAX_CMNDS,
        .this_id = -1,
        .sg_tablesize = SG_NONE,
        .skip_settle_delay = 1,
@@ -932,6 +943,12 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
        if (result)
                goto set_alt0;
 
+       /*
+        * 1 tag is reserved for untagged commands +
+        * 1 tag to avoid off by one errors in some bridge firmwares
+        */
+       shost->can_queue = devinfo->qdepth - 2;
+
        usb_set_intfdata(intf, shost);
        result = scsi_add_host(shost, &intf->dev);
        if (result)
index ccc113e83d88e2b1e69e207989a5d5b49d526ae2..53341a77d89f275b44f9baf44f6caa25d7675802 100644 (file)
@@ -64,6 +64,13 @@ UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: David Webb <djw@noc.ac.uk> */
+UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
+               "Seagate",
+               "Expansion Desk",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_LUNS),
+
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999,
                "Seagate",
index 43576ed31ccdc4bfcfcafba0f95e6006a6bd63b6..9de988a0f856d3d8e220b47e7fe1c8e93cd11c00 100644 (file)
@@ -482,7 +482,7 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
                        US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
                        US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
                        US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
-                       US_FL_MAX_SECTORS_240);
+                       US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS);
 
        p = quirks;
        while (*p) {
@@ -532,6 +532,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
                case 'i':
                        f |= US_FL_IGNORE_DEVICE;
                        break;
+               case 'j':
+                       f |= US_FL_NO_REPORT_LUNS;
+                       break;
                case 'l':
                        f |= US_FL_NOT_LOCKABLE;
                        break;
index facaaf003f19931b2f15603568bb565f3de40607..e40da7759a0e6cd3a55bccdf90bb10284376ab11 100644 (file)
@@ -741,6 +741,17 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
        if (!(size > 0))
                return 0;
 
+       if (size > urb->transfer_buffer_length) {
+               /* should not happen, probably malicious packet */
+               if (ud->side == USBIP_STUB) {
+                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+                       return 0;
+               } else {
+                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+                       return -EPIPE;
+               }
+       }
+
        ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
        if (ret != size) {
                dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
index e6d16d65e4e6529501f3c50e670712fb5db076cf..f07a0974fda287c2feae4296ef3fc4672fb64f43 100644 (file)
@@ -2249,7 +2249,6 @@ config XEN_FBDEV_FRONTEND
        select FB_SYS_IMAGEBLIT
        select FB_SYS_FOPS
        select FB_DEFERRED_IO
-       select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC
        select XEN_XENBUS_FRONTEND
        default y
        help
index 0081725c6b5be62f6c7939d5bc2b4022881f363e..d00510029c93310f7941edde945d5c20f12f118a 100644 (file)
@@ -209,8 +209,7 @@ static struct fb_videomode known_lcd_panels[] = {
                .lower_margin   = 2,
                .hsync_len      = 0,
                .vsync_len      = 0,
-               .sync           = FB_SYNC_CLK_INVERT |
-                       FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .sync           = FB_SYNC_CLK_INVERT,
        },
        /* Sharp LK043T1DG01 */
        [1] = {
@@ -224,7 +223,7 @@ static struct fb_videomode known_lcd_panels[] = {
                .lower_margin   = 2,
                .hsync_len      = 41,
                .vsync_len      = 10,
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .sync           = 0,
                .flag           = 0,
        },
        [2] = {
@@ -239,7 +238,7 @@ static struct fb_videomode known_lcd_panels[] = {
                .lower_margin   = 10,
                .hsync_len      = 10,
                .vsync_len      = 10,
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .sync           = 0,
                .flag           = 0,
        },
        [3] = {
index 8e5cf194cc0bd003888c1235b8d9bfc1cbc99e9c..4469202eaa8e06ecd0b8e3c626e69856ab98bc3b 100644 (file)
@@ -17,6 +17,7 @@
  *
  */
 
+#include <linux/delay.h>
 #define VIRTIO_PCI_NO_LEGACY
 #include "virtio_pci_common.h"
 
@@ -271,9 +272,13 @@ static void vp_reset(struct virtio_device *vdev)
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        /* 0 status means a reset. */
        vp_iowrite8(0, &vp_dev->common->device_status);
-       /* Flush out the status write, and flush in device writes,
-        * including MSI-X interrupts, if any. */
-       vp_ioread8(&vp_dev->common->device_status);
+       /* After writing 0 to device_status, the driver MUST wait for a read of
+        * device_status to return 0 before reinitializing the device.
+        * This will flush out the status write, and flush in device writes,
+        * including MSI-X interrupts, if any.
+        */
+       while (vp_ioread8(&vp_dev->common->device_status))
+               msleep(1);
        /* Flush pending VQ/configuration callbacks. */
        vp_synchronize_vectors(vdev);
 }
index 71e78ef4b736a1b035e69f5cef063b3a528aaebc..3a75f3b53452cdb51f49882a26480cbcf8673fb9 100644 (file)
@@ -237,7 +237,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
                        return -EINVAL;
                /* Fall through */
        case WDIOC_GETTIMEOUT:
-               return copy_to_user(argp, &timeout, sizeof(int));
+               return copy_to_user(argp, &timeout, sizeof(int)) ? -EFAULT : 0;
        default:
                return -ENOTTY;
        }
index 12eab503efd1bb8793fff55eca83649e1f564426..364bc44610c155db1b0217da931c47dd2b97a4e7 100644 (file)
@@ -152,6 +152,8 @@ static DECLARE_WAIT_QUEUE_HEAD(balloon_wq);
 static void balloon_process(struct work_struct *work);
 static DECLARE_DELAYED_WORK(balloon_worker, balloon_process);
 
+static void release_memory_resource(struct resource *resource);
+
 /* When ballooning out (allocating memory to return to Xen) we don't really
    want the kernel to try too hard since that can trigger the oom killer. */
 #define GFP_BALLOON \
@@ -268,6 +270,20 @@ static struct resource *additional_memory_resource(phys_addr_t size)
                return NULL;
        }
 
+#ifdef CONFIG_SPARSEMEM
+       {
+               unsigned long limit = 1UL << (MAX_PHYSMEM_BITS - PAGE_SHIFT);
+               unsigned long pfn = res->start >> PAGE_SHIFT;
+
+               if (pfn > limit) {
+                       pr_err("New System RAM resource outside addressable RAM (%lu > %lu)\n",
+                              pfn, limit);
+                       release_memory_resource(res);
+                       return NULL;
+               }
+       }
+#endif
+
        return res;
 }
 
index 524c22146429d7c87acc8682976031c2f8a727d6..44367783f07a867d87c30c81060b508f4b75657d 100644 (file)
@@ -484,9 +484,19 @@ static void eoi_pirq(struct irq_data *data)
        struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) };
        int rc = 0;
 
-       irq_move_irq(data);
+       if (!VALID_EVTCHN(evtchn))
+               return;
 
-       if (VALID_EVTCHN(evtchn))
+       if (unlikely(irqd_is_setaffinity_pending(data))) {
+               int masked = test_and_set_mask(evtchn);
+
+               clear_evtchn(evtchn);
+
+               irq_move_masked_irq(data);
+
+               if (!masked)
+                       unmask_evtchn(evtchn);
+       } else
                clear_evtchn(evtchn);
 
        if (pirq_needs_eoi(data->irq)) {
@@ -1357,9 +1367,19 @@ static void ack_dynirq(struct irq_data *data)
 {
        int evtchn = evtchn_from_irq(data->irq);
 
-       irq_move_irq(data);
+       if (!VALID_EVTCHN(evtchn))
+               return;
 
-       if (VALID_EVTCHN(evtchn))
+       if (unlikely(irqd_is_setaffinity_pending(data))) {
+               int masked = test_and_set_mask(evtchn);
+
+               clear_evtchn(evtchn);
+
+               irq_move_masked_irq(data);
+
+               if (!masked)
+                       unmask_evtchn(evtchn);
+       } else
                clear_evtchn(evtchn);
 }
 
index 38272ad245516c272ab571bed1a5c962f4a0e808..f4edd6df3df235c55aef1329cb8e17b5ae8cf9f7 100644 (file)
@@ -316,7 +316,6 @@ static int evtchn_resize_ring(struct per_user_data *u)
 {
        unsigned int new_size;
        evtchn_port_t *new_ring, *old_ring;
-       unsigned int p, c;
 
        /*
         * Ensure the ring is large enough to capture all possible
@@ -346,20 +345,17 @@ static int evtchn_resize_ring(struct per_user_data *u)
        /*
         * Copy the old ring contents to the new ring.
         *
-        * If the ring contents crosses the end of the current ring,
-        * it needs to be copied in two chunks.
+        * To take care of wrapping, a full ring, and the new index
+        * pointing into the second half, simply copy the old contents
+        * twice.
         *
         * +---------+    +------------------+
-        * |34567  12| -> |       1234567    |
-        * +-----p-c-+    +------------------+
+        * |34567  12| -> |34567  1234567  12|
+        * +-----p-c-+    +-------c------p---+
         */
-       p = evtchn_ring_offset(u, u->ring_prod);
-       c = evtchn_ring_offset(u, u->ring_cons);
-       if (p < c) {
-               memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring));
-               memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring));
-       } else
-               memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring));
+       memcpy(new_ring, old_ring, u->ring_size * sizeof(*u->ring));
+       memcpy(new_ring + u->ring_size, old_ring,
+              u->ring_size * sizeof(*u->ring));
 
        u->ring = new_ring;
        u->ring_size = new_size;
index 0f09526aa7d9d2017bb229eb4310f777c4b3b578..5e5db3687e348a9cfa54e588670637a62081ee9d 100644 (file)
@@ -1885,7 +1885,7 @@ static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end)
  */
 int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *dentry = file_dentry(file);
        struct inode *inode = d_inode(dentry);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
index 323e12cc9d2f522388fe929ed66d4dd946b5881d..0e044d7ee721ec1708def2298fa47f6a359764d6 100644 (file)
@@ -4406,6 +4406,127 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+/*
+ * When we are logging a new inode X, check if it doesn't have a reference that
+ * matches the reference from some other inode Y created in a past transaction
+ * and that was renamed in the current transaction. If we don't do this, then at
+ * log replay time we can lose inode Y (and all its files if it's a directory):
+ *
+ * mkdir /mnt/x
+ * echo "hello world" > /mnt/x/foobar
+ * sync
+ * mv /mnt/x /mnt/y
+ * mkdir /mnt/x                 # or touch /mnt/x
+ * xfs_io -c fsync /mnt/x
+ * <power fail>
+ * mount fs, trigger log replay
+ *
+ * After the log replay procedure, we would lose the first directory and all its
+ * files (file foobar).
+ * For the case where inode Y is not a directory we simply end up losing it:
+ *
+ * echo "123" > /mnt/foo
+ * sync
+ * mv /mnt/foo /mnt/bar
+ * echo "abc" > /mnt/foo
+ * xfs_io -c fsync /mnt/foo
+ * <power fail>
+ *
+ * We also need this for cases where a snapshot entry is replaced by some other
+ * entry (file or directory) otherwise we end up with an unreplayable log due to
+ * attempts to delete the snapshot entry (entry of type BTRFS_ROOT_ITEM_KEY) as
+ * if it were a regular entry:
+ *
+ * mkdir /mnt/x
+ * btrfs subvolume snapshot /mnt /mnt/x/snap
+ * btrfs subvolume delete /mnt/x/snap
+ * rmdir /mnt/x
+ * mkdir /mnt/x
+ * fsync /mnt/x or fsync some new file inside it
+ * <power fail>
+ *
+ * The snapshot delete, rmdir of x, mkdir of a new x and the fsync all happen in
+ * the same transaction.
+ */
+static int btrfs_check_ref_name_override(struct extent_buffer *eb,
+                                        const int slot,
+                                        const struct btrfs_key *key,
+                                        struct inode *inode)
+{
+       int ret;
+       struct btrfs_path *search_path;
+       char *name = NULL;
+       u32 name_len = 0;
+       u32 item_size = btrfs_item_size_nr(eb, slot);
+       u32 cur_offset = 0;
+       unsigned long ptr = btrfs_item_ptr_offset(eb, slot);
+
+       search_path = btrfs_alloc_path();
+       if (!search_path)
+               return -ENOMEM;
+       search_path->search_commit_root = 1;
+       search_path->skip_locking = 1;
+
+       while (cur_offset < item_size) {
+               u64 parent;
+               u32 this_name_len;
+               u32 this_len;
+               unsigned long name_ptr;
+               struct btrfs_dir_item *di;
+
+               if (key->type == BTRFS_INODE_REF_KEY) {
+                       struct btrfs_inode_ref *iref;
+
+                       iref = (struct btrfs_inode_ref *)(ptr + cur_offset);
+                       parent = key->offset;
+                       this_name_len = btrfs_inode_ref_name_len(eb, iref);
+                       name_ptr = (unsigned long)(iref + 1);
+                       this_len = sizeof(*iref) + this_name_len;
+               } else {
+                       struct btrfs_inode_extref *extref;
+
+                       extref = (struct btrfs_inode_extref *)(ptr +
+                                                              cur_offset);
+                       parent = btrfs_inode_extref_parent(eb, extref);
+                       this_name_len = btrfs_inode_extref_name_len(eb, extref);
+                       name_ptr = (unsigned long)&extref->name;
+                       this_len = sizeof(*extref) + this_name_len;
+               }
+
+               if (this_name_len > name_len) {
+                       char *new_name;
+
+                       new_name = krealloc(name, this_name_len, GFP_NOFS);
+                       if (!new_name) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+                       name_len = this_name_len;
+                       name = new_name;
+               }
+
+               read_extent_buffer(eb, name, name_ptr, this_name_len);
+               di = btrfs_lookup_dir_item(NULL, BTRFS_I(inode)->root,
+                                          search_path, parent,
+                                          name, this_name_len, 0);
+               if (di && !IS_ERR(di)) {
+                       ret = 1;
+                       goto out;
+               } else if (IS_ERR(di)) {
+                       ret = PTR_ERR(di);
+                       goto out;
+               }
+               btrfs_release_path(search_path);
+
+               cur_offset += this_len;
+       }
+       ret = 0;
+out:
+       btrfs_free_path(search_path);
+       kfree(name);
+       return ret;
+}
+
 /* log a single inode in the tree log.
  * At least one parent directory for this inode must exist in the tree
  * or be logged already.
@@ -4578,6 +4699,22 @@ again:
                if (min_key.type == BTRFS_INODE_ITEM_KEY)
                        need_log_inode_item = false;
 
+               if ((min_key.type == BTRFS_INODE_REF_KEY ||
+                    min_key.type == BTRFS_INODE_EXTREF_KEY) &&
+                   BTRFS_I(inode)->generation == trans->transid) {
+                       ret = btrfs_check_ref_name_override(path->nodes[0],
+                                                           path->slots[0],
+                                                           &min_key, inode);
+                       if (ret < 0) {
+                               err = ret;
+                               goto out_unlock;
+                       } else if (ret > 0) {
+                               err = 1;
+                               btrfs_set_log_full_commit(root->fs_info, trans);
+                               goto out_unlock;
+                       }
+               }
+
                /* Skip xattrs, we log them later with btrfs_log_all_xattrs() */
                if (min_key.type == BTRFS_XATTR_ITEM_KEY) {
                        if (ins_nr == 0)
index 1777331eee767fa323cb864fb95131983eaad588..dfc87c5f5a54febea6f6e36bd3636965f9fa6396 100644 (file)
@@ -32,6 +32,9 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
 #include <linux/compat.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/path.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -627,6 +630,8 @@ void do_coredump(const siginfo_t *siginfo)
                }
        } else {
                struct inode *inode;
+               int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
+                                O_LARGEFILE | O_EXCL;
 
                if (cprm.limit < binfmt->min_coredump)
                        goto fail_unlock;
@@ -665,10 +670,27 @@ void do_coredump(const siginfo_t *siginfo)
                 * what matters is that at least one of the two processes
                 * writes its coredump successfully, not which one.
                 */
-               cprm.file = filp_open(cn.corename,
-                                O_CREAT | 2 | O_NOFOLLOW |
-                                O_LARGEFILE | O_EXCL,
-                                0600);
+               if (need_suid_safe) {
+                       /*
+                        * Using user namespaces, normal user tasks can change
+                        * their current->fs->root to point to arbitrary
+                        * directories. Since the intention of the "only dump
+                        * with a fully qualified path" rule is to control where
+                        * coredumps may be placed using root privileges,
+                        * current->fs->root must not be used. Instead, use the
+                        * root directory of init_task.
+                        */
+                       struct path root;
+
+                       task_lock(&init_task);
+                       get_fs_root(init_task.fs, &root);
+                       task_unlock(&init_task);
+                       cprm.file = file_open_root(root.dentry, root.mnt,
+                               cn.corename, open_flags, 0600);
+                       path_put(&root);
+               } else {
+                       cprm.file = filp_open(cn.corename, open_flags, 0600);
+               }
                if (IS_ERR(cprm.file))
                        goto fail_unlock;
 
index 24190e8b78604e02b4b512c5b52722c65b36e189..240935d77844dfdd38c676a5034e4dd1b0449638 100644 (file)
@@ -1666,7 +1666,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
                                DCACHE_OP_REVALIDATE    |
                                DCACHE_OP_WEAK_REVALIDATE       |
                                DCACHE_OP_DELETE        |
-                               DCACHE_OP_SELECT_INODE));
+                               DCACHE_OP_SELECT_INODE  |
+                               DCACHE_OP_REAL));
        dentry->d_op = op;
        if (!op)
                return;
@@ -1684,6 +1685,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
                dentry->d_flags |= DCACHE_OP_PRUNE;
        if (op->d_select_inode)
                dentry->d_flags |= DCACHE_OP_SELECT_INODE;
+       if (op->d_real)
+               dentry->d_flags |= DCACHE_OP_REAL;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
index b7fcc0de0b2f2771aff08a130eb20564adb3cbd4..0f5d05bf213140ccc10106bbc0ad3894d2bb9538 100644 (file)
@@ -457,7 +457,7 @@ struct dentry *debugfs_create_automount(const char *name,
        if (unlikely(!inode))
                return failed_creating(dentry);
 
-       inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
+       make_empty_dir_inode(inode);
        inode->i_flags |= S_AUTOMOUNT;
        inode->i_private = data;
        dentry->d_fsdata = (void *)f;
index 5cf6d8be48dd029aca370e2cc4addefa6b514683..daad932eeb38ae730c9d41e4e04a1e537fd99748 100644 (file)
@@ -849,6 +849,29 @@ do {                                                                              \
 
 #include "extents_status.h"
 
+/*
+ * Lock subclasses for i_data_sem in the ext4_inode_info structure.
+ *
+ * These are needed to avoid lockdep false positives when we need to
+ * allocate blocks to the quota inode during ext4_map_blocks(), while
+ * holding i_data_sem for a normal (non-quota) inode.  Since we don't
+ * do quota tracking for the quota inode, this avoids deadlock (as
+ * well as infinite recursion, since it isn't turtles all the way
+ * down...)
+ *
+ *  I_DATA_SEM_NORMAL - Used for most inodes
+ *  I_DATA_SEM_OTHER  - Used by move_inode.c for the second normal inode
+ *                       where the second inode has larger inode number
+ *                       than the first
+ *  I_DATA_SEM_QUOTA  - Used for quota inodes only
+ */
+enum {
+       I_DATA_SEM_NORMAL = 0,
+       I_DATA_SEM_OTHER,
+       I_DATA_SEM_QUOTA,
+};
+
+
 /*
  * fourth extended file system inode data in memory
  */
@@ -910,6 +933,15 @@ struct ext4_inode_info {
         * by other means, so we have i_data_sem.
         */
        struct rw_semaphore i_data_sem;
+       /*
+        * i_mmap_sem is for serializing page faults with truncate / punch hole
+        * operations. We have to make sure that new page cannot be faulted in
+        * a section of the inode that is being punched. We cannot easily use
+        * i_data_sem for this since we need protection for the whole punch
+        * operation and i_data_sem ranks below transaction start so we have
+        * to occasionally drop it.
+        */
+       struct rw_semaphore i_mmap_sem;
        struct inode vfs_inode;
        struct jbd2_inode *jinode;
 
@@ -2485,6 +2517,7 @@ extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
 extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
                             loff_t lstart, loff_t lend);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
+extern int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t *ext4_get_reserved_space(struct inode *inode);
 extern void ext4_da_update_reserve_space(struct inode *inode,
                                        int used, int quota_claim);
@@ -2849,6 +2882,9 @@ static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
        return changed;
 }
 
+int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
+                                     loff_t len);
+
 struct ext4_group_info {
        unsigned long   bb_state;
        struct rb_root  bb_free_root;
index 551353b1b17ab930ead8eff62ee3a699b4cfe10f..3578b25fccfd8eef98062e22ee037037a9c8ca38 100644 (file)
@@ -4685,10 +4685,6 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
        if (len <= EXT_UNWRITTEN_MAX_LEN)
                flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
-       ext4_inode_block_unlocked_dio(inode);
-       inode_dio_wait(inode);
-
        /*
         * credits to insert 1 extent into extent tree
         */
@@ -4752,8 +4748,6 @@ retry:
                goto retry;
        }
 
-       ext4_inode_resume_unlocked_dio(inode);
-
        return ret > 0 ? ret2 : ret;
 }
 
@@ -4770,7 +4764,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        int partial_begin, partial_end;
        loff_t start, end;
        ext4_lblk_t lblk;
-       struct address_space *mapping = inode->i_mapping;
        unsigned int blkbits = inode->i_blkbits;
 
        trace_ext4_zero_range(inode, offset, len, mode);
@@ -4785,17 +4778,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                        return ret;
        }
 
-       /*
-        * Write out all dirty pages to avoid race conditions
-        * Then release them.
-        */
-       if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
-               ret = filemap_write_and_wait_range(mapping, offset,
-                                                  offset + len - 1);
-               if (ret)
-                       return ret;
-       }
-
        /*
         * Round up offset. This is not fallocate, we neet to zero out
         * blocks, so convert interior block aligned part of the range to
@@ -4839,6 +4821,10 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        if (mode & FALLOC_FL_KEEP_SIZE)
                flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
 
+       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       ext4_inode_block_unlocked_dio(inode);
+       inode_dio_wait(inode);
+
        /* Preallocate the range including the unaligned edges */
        if (partial_begin || partial_end) {
                ret = ext4_alloc_file_blocks(file,
@@ -4847,7 +4833,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                                 round_down(offset, 1 << blkbits)) >> blkbits,
                                new_size, flags, mode);
                if (ret)
-                       goto out_mutex;
+                       goto out_dio;
 
        }
 
@@ -4856,16 +4842,23 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
                          EXT4_EX_NOCACHE);
 
-               /* Now release the pages and zero block aligned part of pages*/
+               /*
+                * Prevent page faults from reinstantiating pages we have
+                * released from page cache.
+                */
+               down_write(&EXT4_I(inode)->i_mmap_sem);
+               ret = ext4_update_disksize_before_punch(inode, offset, len);
+               if (ret) {
+                       up_write(&EXT4_I(inode)->i_mmap_sem);
+                       goto out_dio;
+               }
+               /* Now release the pages and zero block aligned part of pages */
                truncate_pagecache_range(inode, start, end - 1);
                inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 
-               /* Wait all existing dio workers, newcomers will block on i_mutex */
-               ext4_inode_block_unlocked_dio(inode);
-               inode_dio_wait(inode);
-
                ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
                                             flags, mode);
+               up_write(&EXT4_I(inode)->i_mmap_sem);
                if (ret)
                        goto out_dio;
        }
@@ -4998,8 +4991,13 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
                        goto out;
        }
 
+       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       ext4_inode_block_unlocked_dio(inode);
+       inode_dio_wait(inode);
+
        ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
                                     flags, mode);
+       ext4_inode_resume_unlocked_dio(inode);
        if (ret)
                goto out;
 
@@ -5494,21 +5492,7 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
                        return ret;
        }
 
-       /*
-        * Need to round down offset to be aligned with page size boundary
-        * for page size > block size.
-        */
-       ioffset = round_down(offset, PAGE_SIZE);
-
-       /* Write out all dirty pages */
-       ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
-                                          LLONG_MAX);
-       if (ret)
-               return ret;
-
-       /* Take mutex lock */
        mutex_lock(&inode->i_mutex);
-
        /*
         * There is no need to overlap collapse range with EOF, in which case
         * it is effectively a truncate operation
@@ -5524,17 +5508,43 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
                goto out_mutex;
        }
 
-       truncate_pagecache(inode, ioffset);
-
        /* Wait for existing dio to complete */
        ext4_inode_block_unlocked_dio(inode);
        inode_dio_wait(inode);
 
+       /*
+        * Prevent page faults from reinstantiating pages we have released from
+        * page cache.
+        */
+       down_write(&EXT4_I(inode)->i_mmap_sem);
+       /*
+        * Need to round down offset to be aligned with page size boundary
+        * for page size > block size.
+        */
+       ioffset = round_down(offset, PAGE_SIZE);
+       /*
+        * Write tail of the last page before removed range since it will get
+        * removed from the page cache below.
+        */
+       ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, offset);
+       if (ret)
+               goto out_mmap;
+       /*
+        * Write data that will be shifted to preserve them when discarding
+        * page cache below. We are also protected from pages becoming dirty
+        * by i_mmap_sem.
+        */
+       ret = filemap_write_and_wait_range(inode->i_mapping, offset + len,
+                                          LLONG_MAX);
+       if (ret)
+               goto out_mmap;
+       truncate_pagecache(inode, ioffset);
+
        credits = ext4_writepage_trans_blocks(inode);
        handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
-               goto out_dio;
+               goto out_mmap;
        }
 
        down_write(&EXT4_I(inode)->i_data_sem);
@@ -5573,7 +5583,8 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
 
 out_stop:
        ext4_journal_stop(handle);
-out_dio:
+out_mmap:
+       up_write(&EXT4_I(inode)->i_mmap_sem);
        ext4_inode_resume_unlocked_dio(inode);
 out_mutex:
        mutex_unlock(&inode->i_mutex);
@@ -5627,21 +5638,7 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                        return ret;
        }
 
-       /*
-        * Need to round down to align start offset to page size boundary
-        * for page size > block size.
-        */
-       ioffset = round_down(offset, PAGE_SIZE);
-
-       /* Write out all dirty pages */
-       ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
-                       LLONG_MAX);
-       if (ret)
-               return ret;
-
-       /* Take mutex lock */
        mutex_lock(&inode->i_mutex);
-
        /* Currently just for extent based files */
        if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
                ret = -EOPNOTSUPP;
@@ -5660,17 +5657,32 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                goto out_mutex;
        }
 
-       truncate_pagecache(inode, ioffset);
-
        /* Wait for existing dio to complete */
        ext4_inode_block_unlocked_dio(inode);
        inode_dio_wait(inode);
 
+       /*
+        * Prevent page faults from reinstantiating pages we have released from
+        * page cache.
+        */
+       down_write(&EXT4_I(inode)->i_mmap_sem);
+       /*
+        * Need to round down to align start offset to page size boundary
+        * for page size > block size.
+        */
+       ioffset = round_down(offset, PAGE_SIZE);
+       /* Write out all dirty pages */
+       ret = filemap_write_and_wait_range(inode->i_mapping, ioffset,
+                       LLONG_MAX);
+       if (ret)
+               goto out_mmap;
+       truncate_pagecache(inode, ioffset);
+
        credits = ext4_writepage_trans_blocks(inode);
        handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
-               goto out_dio;
+               goto out_mmap;
        }
 
        /* Expand file to avoid data loss if there is error while shifting */
@@ -5741,7 +5753,8 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
 
 out_stop:
        ext4_journal_stop(handle);
-out_dio:
+out_mmap:
+       up_write(&EXT4_I(inode)->i_mmap_sem);
        ext4_inode_resume_unlocked_dio(inode);
 out_mutex:
        mutex_unlock(&inode->i_mutex);
index 113837e7ba98d5cf866ee365a40a89d7fc781a71..0d24ebcd7c9e535dc3126d5c10b18c745aef8a2e 100644 (file)
@@ -209,15 +209,18 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        int result;
        handle_t *handle = NULL;
-       struct super_block *sb = file_inode(vma->vm_file)->i_sb;
+       struct inode *inode = file_inode(vma->vm_file);
+       struct super_block *sb = inode->i_sb;
        bool write = vmf->flags & FAULT_FLAG_WRITE;
 
        if (write) {
                sb_start_pagefault(sb);
                file_update_time(vma->vm_file);
+               down_read(&EXT4_I(inode)->i_mmap_sem);
                handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
                                                EXT4_DATA_TRANS_BLOCKS(sb));
-       }
+       } else
+               down_read(&EXT4_I(inode)->i_mmap_sem);
 
        if (IS_ERR(handle))
                result = VM_FAULT_SIGBUS;
@@ -228,8 +231,10 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (write) {
                if (!IS_ERR(handle))
                        ext4_journal_stop(handle);
+               up_read(&EXT4_I(inode)->i_mmap_sem);
                sb_end_pagefault(sb);
-       }
+       } else
+               up_read(&EXT4_I(inode)->i_mmap_sem);
 
        return result;
 }
@@ -246,10 +251,12 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
        if (write) {
                sb_start_pagefault(sb);
                file_update_time(vma->vm_file);
+               down_read(&EXT4_I(inode)->i_mmap_sem);
                handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE,
                                ext4_chunk_trans_blocks(inode,
                                                        PMD_SIZE / PAGE_SIZE));
-       }
+       } else
+               down_read(&EXT4_I(inode)->i_mmap_sem);
 
        if (IS_ERR(handle))
                result = VM_FAULT_SIGBUS;
@@ -260,30 +267,71 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
        if (write) {
                if (!IS_ERR(handle))
                        ext4_journal_stop(handle);
+               up_read(&EXT4_I(inode)->i_mmap_sem);
                sb_end_pagefault(sb);
-       }
+       } else
+               up_read(&EXT4_I(inode)->i_mmap_sem);
 
        return result;
 }
 
 static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-       return dax_mkwrite(vma, vmf, ext4_get_block_dax,
-                               ext4_end_io_unwritten);
+       int err;
+       struct inode *inode = file_inode(vma->vm_file);
+
+       sb_start_pagefault(inode->i_sb);
+       file_update_time(vma->vm_file);
+       down_read(&EXT4_I(inode)->i_mmap_sem);
+       err = __dax_mkwrite(vma, vmf, ext4_get_block_dax,
+                           ext4_end_io_unwritten);
+       up_read(&EXT4_I(inode)->i_mmap_sem);
+       sb_end_pagefault(inode->i_sb);
+
+       return err;
+}
+
+/*
+ * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_mkwrite()
+ * handler we check for races agaist truncate. Note that since we cycle through
+ * i_mmap_sem, we are sure that also any hole punching that began before we
+ * were called is finished by now and so if it included part of the file we
+ * are working on, our pte will get unmapped and the check for pte_same() in
+ * wp_pfn_shared() fails. Thus fault gets retried and things work out as
+ * desired.
+ */
+static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma,
+                               struct vm_fault *vmf)
+{
+       struct inode *inode = file_inode(vma->vm_file);
+       struct super_block *sb = inode->i_sb;
+       int ret = VM_FAULT_NOPAGE;
+       loff_t size;
+
+       sb_start_pagefault(sb);
+       file_update_time(vma->vm_file);
+       down_read(&EXT4_I(inode)->i_mmap_sem);
+       size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (vmf->pgoff >= size)
+               ret = VM_FAULT_SIGBUS;
+       up_read(&EXT4_I(inode)->i_mmap_sem);
+       sb_end_pagefault(sb);
+
+       return ret;
 }
 
 static const struct vm_operations_struct ext4_dax_vm_ops = {
        .fault          = ext4_dax_fault,
        .pmd_fault      = ext4_dax_pmd_fault,
        .page_mkwrite   = ext4_dax_mkwrite,
-       .pfn_mkwrite    = dax_pfn_mkwrite,
+       .pfn_mkwrite    = ext4_dax_pfn_mkwrite,
 };
 #else
 #define ext4_dax_vm_ops        ext4_file_vm_ops
 #endif
 
 static const struct vm_operations_struct ext4_file_vm_ops = {
-       .fault          = filemap_fault,
+       .fault          = ext4_filemap_fault,
        .map_pages      = filemap_map_pages,
        .page_mkwrite   = ext4_page_mkwrite,
 };
index 06bda0361e7ce80dcecdf2245b4922e0af8cffd3..e31d762eedce14e19a9d4f1c5e7d72756cd55147 100644 (file)
@@ -3586,6 +3586,35 @@ int ext4_can_truncate(struct inode *inode)
        return 0;
 }
 
+/*
+ * We have to make sure i_disksize gets properly updated before we truncate
+ * page cache due to hole punching or zero range. Otherwise i_disksize update
+ * can get lost as it may have been postponed to submission of writeback but
+ * that will never happen after we truncate page cache.
+ */
+int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
+                                     loff_t len)
+{
+       handle_t *handle;
+       loff_t size = i_size_read(inode);
+
+       WARN_ON(!mutex_is_locked(&inode->i_mutex));
+       if (offset > size || offset + len < size)
+               return 0;
+
+       if (EXT4_I(inode)->i_disksize >= size)
+               return 0;
+
+       handle = ext4_journal_start(inode, EXT4_HT_MISC, 1);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+       ext4_update_i_disksize(inode, size);
+       ext4_mark_inode_dirty(handle, inode);
+       ext4_journal_stop(handle);
+
+       return 0;
+}
+
 /*
  * ext4_punch_hole: punches a hole in a file by releaseing the blocks
  * associated with the given offset and length
@@ -3651,17 +3680,26 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 
        }
 
+       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       ext4_inode_block_unlocked_dio(inode);
+       inode_dio_wait(inode);
+
+       /*
+        * Prevent page faults from reinstantiating pages we have released from
+        * page cache.
+        */
+       down_write(&EXT4_I(inode)->i_mmap_sem);
        first_block_offset = round_up(offset, sb->s_blocksize);
        last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
 
        /* Now release the pages and zero block aligned part of pages*/
-       if (last_block_offset > first_block_offset)
+       if (last_block_offset > first_block_offset) {
+               ret = ext4_update_disksize_before_punch(inode, offset, length);
+               if (ret)
+                       goto out_dio;
                truncate_pagecache_range(inode, first_block_offset,
                                         last_block_offset);
-
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
-       ext4_inode_block_unlocked_dio(inode);
-       inode_dio_wait(inode);
+       }
 
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                credits = ext4_writepage_trans_blocks(inode);
@@ -3708,16 +3746,12 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
 
-       /* Now release the pages again to reduce race window */
-       if (last_block_offset > first_block_offset)
-               truncate_pagecache_range(inode, first_block_offset,
-                                        last_block_offset);
-
        inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
 out_stop:
        ext4_journal_stop(handle);
 out_dio:
+       up_write(&EXT4_I(inode)->i_mmap_sem);
        ext4_inode_resume_unlocked_dio(inode);
 out_mutex:
        mutex_unlock(&inode->i_mutex);
@@ -4851,6 +4885,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                        } else
                                ext4_wait_for_tail_page_commit(inode);
                }
+               down_write(&EXT4_I(inode)->i_mmap_sem);
                /*
                 * Truncate pagecache after we've waited for commit
                 * in data=journal mode to make pages freeable.
@@ -4858,6 +4893,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                truncate_pagecache(inode, inode->i_size);
                if (shrink)
                        ext4_truncate(inode);
+               up_write(&EXT4_I(inode)->i_mmap_sem);
        }
 
        if (!rc) {
@@ -5109,6 +5145,8 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
        might_sleep();
        trace_ext4_mark_inode_dirty(inode, _RET_IP_);
        err = ext4_reserve_inode_write(handle, inode, &iloc);
+       if (err)
+               return err;
        if (ext4_handle_valid(handle) &&
            EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
            !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) {
@@ -5139,9 +5177,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
                        }
                }
        }
-       if (!err)
-               err = ext4_mark_iloc_dirty(handle, inode, &iloc);
-       return err;
+       return ext4_mark_iloc_dirty(handle, inode, &iloc);
 }
 
 /*
@@ -5306,6 +5342,8 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        sb_start_pagefault(inode->i_sb);
        file_update_time(vma->vm_file);
+
+       down_read(&EXT4_I(inode)->i_mmap_sem);
        /* Delalloc case is easy... */
        if (test_opt(inode->i_sb, DELALLOC) &&
            !ext4_should_journal_data(inode) &&
@@ -5375,6 +5413,19 @@ retry_alloc:
 out_ret:
        ret = block_page_mkwrite_return(ret);
 out:
+       up_read(&EXT4_I(inode)->i_mmap_sem);
        sb_end_pagefault(inode->i_sb);
        return ret;
 }
+
+int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct inode *inode = file_inode(vma->vm_file);
+       int err;
+
+       down_read(&EXT4_I(inode)->i_mmap_sem);
+       err = filemap_fault(vma, vmf);
+       up_read(&EXT4_I(inode)->i_mmap_sem);
+
+       return err;
+}
index e032a0423e351cabfd6fe6156cdfc9c53ebff216..9bdbf98240a0ab6eb4f5004a7408332b20d0cc4d 100644 (file)
@@ -60,10 +60,10 @@ ext4_double_down_write_data_sem(struct inode *first, struct inode *second)
 {
        if (first < second) {
                down_write(&EXT4_I(first)->i_data_sem);
-               down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING);
+               down_write_nested(&EXT4_I(second)->i_data_sem, I_DATA_SEM_OTHER);
        } else {
                down_write(&EXT4_I(second)->i_data_sem);
-               down_write_nested(&EXT4_I(first)->i_data_sem, SINGLE_DEPTH_NESTING);
+               down_write_nested(&EXT4_I(first)->i_data_sem, I_DATA_SEM_OTHER);
 
        }
 }
@@ -483,6 +483,13 @@ mext_check_arguments(struct inode *orig_inode,
                return -EBUSY;
        }
 
+       if (IS_NOQUOTA(orig_inode) || IS_NOQUOTA(donor_inode)) {
+               ext4_debug("ext4 move extent: The argument files should "
+                       "not be quota files [ino:orig %lu, donor %lu]\n",
+                       orig_inode->i_ino, donor_inode->i_ino);
+               return -EBUSY;
+       }
+
        /* Ext4 move extent supports only extent based file */
        if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) {
                ext4_debug("ext4 move extent: orig file is not extents "
index c9ab67da6e5abbe871ce4bc7760c007e07f2b479..852c26806af275a1f3894c0a990c341540f23c06 100644 (file)
@@ -958,6 +958,7 @@ static void init_once(void *foo)
        INIT_LIST_HEAD(&ei->i_orphan);
        init_rwsem(&ei->xattr_sem);
        init_rwsem(&ei->i_data_sem);
+       init_rwsem(&ei->i_mmap_sem);
        inode_init_once(&ei->vfs_inode);
 }
 
@@ -1292,9 +1293,9 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
                return -1;
        }
        if (ext4_has_feature_quota(sb)) {
-               ext4_msg(sb, KERN_ERR, "Cannot set journaled quota options "
-                        "when QUOTA feature is enabled");
-               return -1;
+               ext4_msg(sb, KERN_INFO, "Journaled quota options "
+                        "ignored when QUOTA feature is enabled");
+               return 1;
        }
        qname = match_strdup(args);
        if (!qname) {
@@ -1657,10 +1658,10 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                        return -1;
                }
                if (ext4_has_feature_quota(sb)) {
-                       ext4_msg(sb, KERN_ERR,
-                                "Cannot set journaled quota options "
+                       ext4_msg(sb, KERN_INFO,
+                                "Quota format mount options ignored "
                                 "when QUOTA feature is enabled");
-                       return -1;
+                       return 1;
                }
                sbi->s_jquota_fmt = m->mount_opt;
 #endif
@@ -1721,11 +1722,11 @@ static int parse_options(char *options, struct super_block *sb,
 #ifdef CONFIG_QUOTA
        if (ext4_has_feature_quota(sb) &&
            (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
-               ext4_msg(sb, KERN_ERR, "Cannot set quota options when QUOTA "
-                        "feature is enabled");
-               return 0;
-       }
-       if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+               ext4_msg(sb, KERN_INFO, "Quota feature enabled, usrquota and grpquota "
+                        "mount options ignored.");
+               clear_opt(sb, USRQUOTA);
+               clear_opt(sb, GRPQUOTA);
+       } else if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
                if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
                        clear_opt(sb, USRQUOTA);
 
@@ -4936,6 +4937,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
                                        EXT4_SB(sb)->s_jquota_fmt, type);
 }
 
+static void lockdep_set_quota_inode(struct inode *inode, int subclass)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+
+       /* The first argument of lockdep_set_subclass has to be
+        * *exactly* the same as the argument to init_rwsem() --- in
+        * this case, in init_once() --- or lockdep gets unhappy
+        * because the name of the lock is set using the
+        * stringification of the argument to init_rwsem().
+        */
+       (void) ei;      /* shut up clang warning if !CONFIG_LOCKDEP */
+       lockdep_set_subclass(&ei->i_data_sem, subclass);
+}
+
 /*
  * Standard function to be called on quota_on
  */
@@ -4975,8 +4990,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                if (err)
                        return err;
        }
-
-       return dquot_quota_on(sb, type, format_id, path);
+       lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA);
+       err = dquot_quota_on(sb, type, format_id, path);
+       if (err)
+               lockdep_set_quota_inode(path->dentry->d_inode,
+                                            I_DATA_SEM_NORMAL);
+       return err;
 }
 
 static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
@@ -5002,8 +5021,11 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
 
        /* Don't account quota for quota files to avoid recursion */
        qf_inode->i_flags |= S_NOQUOTA;
+       lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA);
        err = dquot_enable(qf_inode, type, format_id, flags);
        iput(qf_inode);
+       if (err)
+               lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL);
 
        return err;
 }
index 011ba6670d990285f6f61b56ea3fb8b421b70e59..c70d06a383e28819cc556f1027ea118272e5f738 100644 (file)
  */
 static inline void ext4_truncate_failed_write(struct inode *inode)
 {
+       down_write(&EXT4_I(inode)->i_mmap_sem);
        truncate_inode_pages(inode->i_mapping, inode->i_size);
        ext4_truncate(inode);
+       up_write(&EXT4_I(inode)->i_mmap_sem);
 }
 
 /*
index d59712dfa3e701e86ff53609308e813cf8acf69e..ca3c3dd017897936d114e0adb76ec120794f1cfc 100644 (file)
@@ -228,7 +228,7 @@ long do_handle_open(int mountdirfd,
                path_put(&path);
                return fd;
        }
-       file = file_open_root(path.dentry, path.mnt, "", open_flag);
+       file = file_open_root(path.dentry, path.mnt, "", open_flag, 0);
        if (IS_ERR(file)) {
                put_unused_fd(fd);
                retval =  PTR_ERR(file);
index bf8c78920bee5ba306372032596e77abb0e588ea..de11206dda636029cb47fadc3e9c46b2075ce835 100644 (file)
@@ -281,13 +281,15 @@ locked_inode_to_wb_and_lock_list(struct inode *inode)
                wb_get(wb);
                spin_unlock(&inode->i_lock);
                spin_lock(&wb->list_lock);
-               wb_put(wb);             /* not gonna deref it anymore */
 
                /* i_wb may have changed inbetween, can't use inode_to_wb() */
-               if (likely(wb == inode->i_wb))
-                       return wb;      /* @inode already has ref */
+               if (likely(wb == inode->i_wb)) {
+                       wb_put(wb);     /* @inode already has ref */
+                       return wb;
+               }
 
                spin_unlock(&wb->list_lock);
+               wb_put(wb);
                cpu_relax();
                spin_lock(&inode->i_lock);
        }
@@ -1339,10 +1341,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
  * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode()
  * and does more profound writeback list handling in writeback_sb_inodes().
  */
-static int
-writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
-                      struct writeback_control *wbc)
+static int writeback_single_inode(struct inode *inode,
+                                 struct writeback_control *wbc)
 {
+       struct bdi_writeback *wb;
        int ret = 0;
 
        spin_lock(&inode->i_lock);
@@ -1380,7 +1382,8 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
        ret = __writeback_single_inode(inode, wbc);
 
        wbc_detach_inode(wbc);
-       spin_lock(&wb->list_lock);
+
+       wb = inode_to_wb_and_lock_list(inode);
        spin_lock(&inode->i_lock);
        /*
         * If inode is clean, remove it from writeback lists. Otherwise don't
@@ -1455,6 +1458,7 @@ static long writeback_sb_inodes(struct super_block *sb,
 
        while (!list_empty(&wb->b_io)) {
                struct inode *inode = wb_inode(wb->b_io.prev);
+               struct bdi_writeback *tmp_wb;
 
                if (inode->i_sb != sb) {
                        if (work->sb) {
@@ -1545,15 +1549,23 @@ static long writeback_sb_inodes(struct super_block *sb,
                        cond_resched();
                }
 
-
-               spin_lock(&wb->list_lock);
+               /*
+                * Requeue @inode if still dirty.  Be careful as @inode may
+                * have been switched to another wb in the meantime.
+                */
+               tmp_wb = inode_to_wb_and_lock_list(inode);
                spin_lock(&inode->i_lock);
                if (!(inode->i_state & I_DIRTY_ALL))
                        wrote++;
-               requeue_inode(inode, wb, &wbc);
+               requeue_inode(inode, tmp_wb, &wbc);
                inode_sync_complete(inode);
                spin_unlock(&inode->i_lock);
 
+               if (unlikely(tmp_wb != wb)) {
+                       spin_unlock(&tmp_wb->list_lock);
+                       spin_lock(&wb->list_lock);
+               }
+
                /*
                 * bail out to wb_writeback() often enough to check
                 * background threshold and other termination conditions.
@@ -2340,7 +2352,6 @@ EXPORT_SYMBOL(sync_inodes_sb);
  */
 int write_inode_now(struct inode *inode, int sync)
 {
-       struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
        struct writeback_control wbc = {
                .nr_to_write = LONG_MAX,
                .sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE,
@@ -2352,7 +2363,7 @@ int write_inode_now(struct inode *inode, int sync)
                wbc.nr_to_write = 0;
 
        might_sleep();
-       return writeback_single_inode(inode, wb, &wbc);
+       return writeback_single_inode(inode, &wbc);
 }
 EXPORT_SYMBOL(write_inode_now);
 
@@ -2369,7 +2380,7 @@ EXPORT_SYMBOL(write_inode_now);
  */
 int sync_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       return writeback_single_inode(inode, &inode_to_bdi(inode)->wb, wbc);
+       return writeback_single_inode(inode, wbc);
 }
 EXPORT_SYMBOL(sync_inode);
 
index 8e3ee1936c7e38ba381b33c26b2f1847422a613f..c5b6b71654893b2bb7fe0276a40ac57ddb3350a0 100644 (file)
@@ -90,7 +90,7 @@ static struct list_head *cuse_conntbl_head(dev_t devt)
 
 static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 {
-       struct fuse_io_priv io = { .async = 0, .file = kiocb->ki_filp };
+       struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb->ki_filp);
        loff_t pos = 0;
 
        return fuse_direct_io(&io, to, &pos, FUSE_DIO_CUSE);
@@ -98,7 +98,7 @@ static ssize_t cuse_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 
 static ssize_t cuse_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 {
-       struct fuse_io_priv io = { .async = 0, .file = kiocb->ki_filp };
+       struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(kiocb->ki_filp);
        loff_t pos = 0;
        /*
         * No locking or generic_write_checks(), the server is
index 570ca4053c805eb76acd76a44161f8349a9a6325..c2e340d6ec6e8fc179721f2c61483f2aa1034b70 100644 (file)
@@ -528,6 +528,11 @@ static void fuse_release_user_pages(struct fuse_req *req, int write)
        }
 }
 
+static void fuse_io_release(struct kref *kref)
+{
+       kfree(container_of(kref, struct fuse_io_priv, refcnt));
+}
+
 static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io)
 {
        if (io->err)
@@ -585,8 +590,9 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
                }
 
                io->iocb->ki_complete(io->iocb, res, 0);
-               kfree(io);
        }
+
+       kref_put(&io->refcnt, fuse_io_release);
 }
 
 static void fuse_aio_complete_req(struct fuse_conn *fc, struct fuse_req *req)
@@ -613,6 +619,7 @@ static size_t fuse_async_req_send(struct fuse_conn *fc, struct fuse_req *req,
                size_t num_bytes, struct fuse_io_priv *io)
 {
        spin_lock(&io->lock);
+       kref_get(&io->refcnt);
        io->size += num_bytes;
        io->reqs++;
        spin_unlock(&io->lock);
@@ -691,7 +698,7 @@ static void fuse_short_read(struct fuse_req *req, struct inode *inode,
 
 static int fuse_do_readpage(struct file *file, struct page *page)
 {
-       struct fuse_io_priv io = { .async = 0, .file = file };
+       struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file);
        struct inode *inode = page->mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_req *req;
@@ -984,7 +991,7 @@ static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
        size_t res;
        unsigned offset;
        unsigned i;
-       struct fuse_io_priv io = { .async = 0, .file = file };
+       struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file);
 
        for (i = 0; i < req->num_pages; i++)
                fuse_wait_on_page_writeback(inode, req->pages[i]->index);
@@ -1398,7 +1405,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
 
 static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
-       struct fuse_io_priv io = { .async = 0, .file = iocb->ki_filp };
+       struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb->ki_filp);
        return __fuse_direct_read(&io, to, &iocb->ki_pos);
 }
 
@@ -1406,7 +1413,7 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
-       struct fuse_io_priv io = { .async = 0, .file = file };
+       struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(file);
        ssize_t res;
 
        if (is_bad_inode(inode))
@@ -2786,6 +2793,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
        loff_t i_size;
        size_t count = iov_iter_count(iter);
        struct fuse_io_priv *io;
+       bool is_sync = is_sync_kiocb(iocb);
 
        pos = offset;
        inode = file->f_mapping->host;
@@ -2806,6 +2814,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
        if (!io)
                return -ENOMEM;
        spin_lock_init(&io->lock);
+       kref_init(&io->refcnt);
        io->reqs = 1;
        io->bytes = -1;
        io->size = 0;
@@ -2825,12 +2834,18 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
         * to wait on real async I/O requests, so we must submit this request
         * synchronously.
         */
-       if (!is_sync_kiocb(iocb) && (offset + count > i_size) &&
+       if (!is_sync && (offset + count > i_size) &&
            iov_iter_rw(iter) == WRITE)
                io->async = false;
 
-       if (io->async && is_sync_kiocb(iocb))
+       if (io->async && is_sync) {
+               /*
+                * Additional reference to keep io around after
+                * calling fuse_aio_complete()
+                */
+               kref_get(&io->refcnt);
                io->done = &wait;
+       }
 
        if (iov_iter_rw(iter) == WRITE) {
                ret = fuse_direct_io(io, iter, &pos, FUSE_DIO_WRITE);
@@ -2843,14 +2858,14 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
                fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
 
                /* we have a non-extending, async request, so return */
-               if (!is_sync_kiocb(iocb))
+               if (!is_sync)
                        return -EIOCBQUEUED;
 
                wait_for_completion(&wait);
                ret = fuse_get_res_by_io(io);
        }
 
-       kfree(io);
+       kref_put(&io->refcnt, fuse_io_release);
 
        if (iov_iter_rw(iter) == WRITE) {
                if (ret > 0)
index 405113101db8d868fcb40c34199978be576d0961..604cd42dafef2a41941febd3681699f35cdb5e52 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/rbtree.h>
 #include <linux/poll.h>
 #include <linux/workqueue.h>
+#include <linux/kref.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -243,6 +244,7 @@ struct fuse_args {
 
 /** The request IO state (for asynchronous processing) */
 struct fuse_io_priv {
+       struct kref refcnt;
        int async;
        spinlock_t lock;
        unsigned reqs;
@@ -256,6 +258,13 @@ struct fuse_io_priv {
        struct completion *done;
 };
 
+#define FUSE_IO_PRIV_SYNC(f) \
+{                                      \
+       .refcnt = { ATOMIC_INIT(1) },   \
+       .async = 0,                     \
+       .file = f,                      \
+}
+
 /**
  * Request flags
  *
index 81e622681c82273aa050eb85cdb057b1fea0e79e..624a57a9c4aab23c4b9261ad30fd11ed7cd3e994 100644 (file)
@@ -1408,11 +1408,12 @@ out:
 /**
  * jbd2_mark_journal_empty() - Mark on disk journal as empty.
  * @journal: The journal to update.
+ * @write_op: With which operation should we write the journal sb
  *
  * Update a journal's dynamic superblock fields to show that journal is empty.
  * Write updated superblock to disk waiting for IO to complete.
  */
-static void jbd2_mark_journal_empty(journal_t *journal)
+static void jbd2_mark_journal_empty(journal_t *journal, int write_op)
 {
        journal_superblock_t *sb = journal->j_superblock;
 
@@ -1430,7 +1431,7 @@ static void jbd2_mark_journal_empty(journal_t *journal)
        sb->s_start    = cpu_to_be32(0);
        read_unlock(&journal->j_state_lock);
 
-       jbd2_write_superblock(journal, WRITE_FUA);
+       jbd2_write_superblock(journal, write_op);
 
        /* Log is no longer empty */
        write_lock(&journal->j_state_lock);
@@ -1716,7 +1717,13 @@ int jbd2_journal_destroy(journal_t *journal)
        if (journal->j_sb_buffer) {
                if (!is_journal_aborted(journal)) {
                        mutex_lock(&journal->j_checkpoint_mutex);
-                       jbd2_mark_journal_empty(journal);
+
+                       write_lock(&journal->j_state_lock);
+                       journal->j_tail_sequence =
+                               ++journal->j_transaction_sequence;
+                       write_unlock(&journal->j_state_lock);
+
+                       jbd2_mark_journal_empty(journal, WRITE_FLUSH_FUA);
                        mutex_unlock(&journal->j_checkpoint_mutex);
                } else
                        err = -EIO;
@@ -1975,7 +1982,7 @@ int jbd2_journal_flush(journal_t *journal)
         * the magic code for a fully-recovered superblock.  Any future
         * commits of data to the journal will restore the current
         * s_start value. */
-       jbd2_mark_journal_empty(journal);
+       jbd2_mark_journal_empty(journal, WRITE_FUA);
        mutex_unlock(&journal->j_checkpoint_mutex);
        write_lock(&journal->j_state_lock);
        J_ASSERT(!journal->j_running_transaction);
@@ -2021,7 +2028,7 @@ int jbd2_journal_wipe(journal_t *journal, int write)
        if (write) {
                /* Lock to make assertions happy... */
                mutex_lock(&journal->j_checkpoint_mutex);
-               jbd2_mark_journal_empty(journal);
+               jbd2_mark_journal_empty(journal, WRITE_FUA);
                mutex_unlock(&journal->j_checkpoint_mutex);
        }
 
index ce5a21861074293ca0968b04d1d13e4406ca93bd..5fc2162afb67207118872e2f0c560fb20381e7ec 100644 (file)
@@ -377,7 +377,7 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
  again:
        timestamp = jiffies;
        gencount = nfs_inc_attr_generation_counter();
-       error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages,
+       error = NFS_PROTO(inode)->readdir(file_dentry(file), cred, entry->cookie, pages,
                                          NFS_SERVER(inode)->dtsize, desc->plus);
        if (error < 0) {
                /* We requested READDIRPLUS, but the server doesn't grok it */
@@ -560,7 +560,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
                count++;
 
                if (desc->plus != 0)
-                       nfs_prime_dcache(desc->file->f_path.dentry, entry);
+                       nfs_prime_dcache(file_dentry(desc->file), entry);
 
                status = nfs_readdir_add_to_array(entry, page);
                if (status != 0)
@@ -864,7 +864,7 @@ static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
  */
 static int nfs_readdir(struct file *file, struct dir_context *ctx)
 {
-       struct dentry   *dentry = file->f_path.dentry;
+       struct dentry   *dentry = file_dentry(file);
        struct inode    *inode = d_inode(dentry);
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
index 3e2071a177fd029e043b34018b7628d8c6b03309..f714b98cfd744d435238b02713df053a77ee0d34 100644 (file)
@@ -927,7 +927,7 @@ int nfs_open(struct inode *inode, struct file *filp)
 {
        struct nfs_open_context *ctx;
 
-       ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
+       ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
        nfs_file_set_open_context(filp, ctx);
index db9b5fea5b3ef12f6eacf36cd2154c2db7d4d9f2..679e003818b1bb8612d8496c589f76570a34b606 100644 (file)
@@ -26,7 +26,7 @@ static int
 nfs4_file_open(struct inode *inode, struct file *filp)
 {
        struct nfs_open_context *ctx;
-       struct dentry *dentry = filp->f_path.dentry;
+       struct dentry *dentry = file_dentry(filp);
        struct dentry *parent = NULL;
        struct inode *dir;
        unsigned openflags = filp->f_flags;
@@ -57,7 +57,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        parent = dget_parent(dentry);
        dir = d_inode(parent);
 
-       ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
+       ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode);
        err = PTR_ERR(ctx);
        if (IS_ERR(ctx))
                goto out;
index a9f096c7e99f5dd36b40fac5bad04300e3b7f4e8..7d5351cd67fb09ff5aeb775f2e71f119f51f1800 100644 (file)
@@ -877,6 +877,7 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                    &exp, &dentry);
        if (err)
                return err;
+       fh_unlock(&cstate->current_fh);
        if (d_really_is_negative(dentry)) {
                exp_put(exp);
                err = nfserr_noent;
index 51c9e9ca39a4d7c5e0537a2cafed4ec9caeb789d..12935209deca4410b3e2d261d8127b0847c0b709 100644 (file)
@@ -1072,8 +1072,9 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename
 
        READ_BUF(4);
        rename->rn_snamelen = be32_to_cpup(p++);
-       READ_BUF(rename->rn_snamelen + 4);
+       READ_BUF(rename->rn_snamelen);
        SAVEMEM(rename->rn_sname, rename->rn_snamelen);
+       READ_BUF(4);
        rename->rn_tnamelen = be32_to_cpup(p++);
        READ_BUF(rename->rn_tnamelen);
        SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
@@ -1155,13 +1156,14 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
        READ_BUF(8);
        setclientid->se_callback_prog = be32_to_cpup(p++);
        setclientid->se_callback_netid_len = be32_to_cpup(p++);
-
-       READ_BUF(setclientid->se_callback_netid_len + 4);
+       READ_BUF(setclientid->se_callback_netid_len);
        SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
+       READ_BUF(4);
        setclientid->se_callback_addr_len = be32_to_cpup(p++);
 
-       READ_BUF(setclientid->se_callback_addr_len + 4);
+       READ_BUF(setclientid->se_callback_addr_len);
        SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
+       READ_BUF(4);
        setclientid->se_callback_ident = be32_to_cpup(p++);
 
        DECODE_TAIL;
@@ -1815,8 +1817,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
 
        READ_BUF(4);
        argp->taglen = be32_to_cpup(p++);
-       READ_BUF(argp->taglen + 8);
+       READ_BUF(argp->taglen);
        SAVEMEM(argp->tag, argp->taglen);
+       READ_BUF(8);
        argp->minorversion = be32_to_cpup(p++);
        argp->opcnt = be32_to_cpup(p++);
        max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
index e36d63ff17830bf321a1809d1b81a87827290037..f90931335c6b28af89cc0537b8d3fec48a089300 100644 (file)
@@ -262,6 +262,7 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
                                  struct dlm_lock *lock, int flags, int type)
 {
        enum dlm_status status;
+       u8 old_owner = res->owner;
 
        mlog(0, "type=%d, convert_type=%d, busy=%d\n", lock->ml.type,
             lock->ml.convert_type, res->state & DLM_LOCK_RES_IN_PROGRESS);
@@ -287,6 +288,19 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
                status = DLM_DENIED;
                goto bail;
        }
+
+       if (lock->ml.type == type && lock->ml.convert_type == LKM_IVMODE) {
+               mlog(0, "last convert request returned DLM_RECOVERING, but "
+                    "owner has already queued and sent ast to me. res %.*s, "
+                    "(cookie=%u:%llu, type=%d, conv=%d)\n",
+                    res->lockname.len, res->lockname.name,
+                    dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
+                    dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
+                    lock->ml.type, lock->ml.convert_type);
+               status = DLM_NORMAL;
+               goto bail;
+       }
+
        res->state |= DLM_LOCK_RES_IN_PROGRESS;
        /* move lock to local convert queue */
        /* do not alter lock refcount.  switching lists. */
@@ -316,11 +330,19 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
        spin_lock(&res->spinlock);
        res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
        lock->convert_pending = 0;
-       /* if it failed, move it back to granted queue */
+       /* if it failed, move it back to granted queue.
+        * if master returns DLM_NORMAL and then down before sending ast,
+        * it may have already been moved to granted queue, reset to
+        * DLM_RECOVERING and retry convert */
        if (status != DLM_NORMAL) {
                if (status != DLM_NOTQUEUED)
                        dlm_error(status);
                dlm_revert_pending_convert(res, lock);
+       } else if ((res->state & DLM_LOCK_RES_RECOVERING) ||
+                       (old_owner != res->owner)) {
+               mlog(0, "res %.*s is in recovering or has been recovered.\n",
+                               res->lockname.len, res->lockname.name);
+               status = DLM_RECOVERING;
        }
 bail:
        spin_unlock(&res->spinlock);
index 42f0cae93a0a134fbf1d43623bf7fdde6d8f3a26..4a338803e7e9280ce6cab1c0dd95ffacbff5ae3b 100644 (file)
@@ -2064,7 +2064,6 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm,
                        dlm_lock_get(lock);
                        if (lock->convert_pending) {
                                /* move converting lock back to granted */
-                               BUG_ON(i != DLM_CONVERTING_LIST);
                                mlog(0, "node died with convert pending "
                                     "on %.*s. move back to granted list.\n",
                                     res->lockname.len, res->lockname.name);
index b6f1e96a7c0b331b3e5a5d9bb4c014c5c9edc54b..6a24f988d253dcf883e6fff1b851d33ebcd6ab50 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -995,14 +995,12 @@ struct file *filp_open(const char *filename, int flags, umode_t mode)
 EXPORT_SYMBOL(filp_open);
 
 struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
-                           const char *filename, int flags)
+                           const char *filename, int flags, umode_t mode)
 {
        struct open_flags op;
-       int err = build_open_flags(flags, 0, &op);
+       int err = build_open_flags(flags, mode, &op);
        if (err)
                return ERR_PTR(err);
-       if (flags & O_CREAT)
-               return ERR_PTR(-EINVAL);
        return do_file_open_root(dentry, mnt, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);
index 000b2ed05c29e39a1af646655919f58d0b404c81..a1acc6004a91ddf3a175bdc3d94e57f5c4384484 100644 (file)
@@ -276,6 +276,37 @@ static void ovl_dentry_release(struct dentry *dentry)
        }
 }
 
+static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
+{
+       struct dentry *real;
+
+       if (d_is_dir(dentry)) {
+               if (!inode || inode == d_inode(dentry))
+                       return dentry;
+               goto bug;
+       }
+
+       real = ovl_dentry_upper(dentry);
+       if (real && (!inode || inode == d_inode(real)))
+               return real;
+
+       real = ovl_dentry_lower(dentry);
+       if (!real)
+               goto bug;
+
+       if (!inode || inode == d_inode(real))
+               return real;
+
+       /* Handle recursion */
+       if (real->d_flags & DCACHE_OP_REAL)
+               return real->d_op->d_real(real, inode);
+
+bug:
+       WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry,
+            inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
+       return dentry;
+}
+
 static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct ovl_entry *oe = dentry->d_fsdata;
@@ -320,11 +351,13 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
 static const struct dentry_operations ovl_dentry_operations = {
        .d_release = ovl_dentry_release,
        .d_select_inode = ovl_d_select_inode,
+       .d_real = ovl_d_real,
 };
 
 static const struct dentry_operations ovl_reval_dentry_operations = {
        .d_release = ovl_dentry_release,
        .d_select_inode = ovl_d_select_inode,
+       .d_real = ovl_d_real,
        .d_revalidate = ovl_dentry_revalidate,
        .d_weak_revalidate = ovl_dentry_weak_revalidate,
 };
index 6367e1e435c64144a1d9adb94e9c1cfd1f157dfe..99899705b1055411723c3e5919ecbc1f50139e14 100644 (file)
@@ -198,10 +198,15 @@ static struct mount *next_group(struct mount *m, struct mount *origin)
 
 /* all accesses are serialized by namespace_sem */
 static struct user_namespace *user_ns;
-static struct mount *last_dest, *last_source, *dest_master;
+static struct mount *last_dest, *first_source, *last_source, *dest_master;
 static struct mountpoint *mp;
 static struct hlist_head *list;
 
+static inline bool peers(struct mount *m1, struct mount *m2)
+{
+       return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id;
+}
+
 static int propagate_one(struct mount *m)
 {
        struct mount *child;
@@ -212,24 +217,26 @@ static int propagate_one(struct mount *m)
        /* skip if mountpoint isn't covered by it */
        if (!is_subdir(mp->m_dentry, m->mnt.mnt_root))
                return 0;
-       if (m->mnt_group_id == last_dest->mnt_group_id) {
+       if (peers(m, last_dest)) {
                type = CL_MAKE_SHARED;
        } else {
                struct mount *n, *p;
+               bool done;
                for (n = m; ; n = p) {
                        p = n->mnt_master;
-                       if (p == dest_master || IS_MNT_MARKED(p)) {
-                               while (last_dest->mnt_master != p) {
-                                       last_source = last_source->mnt_master;
-                                       last_dest = last_source->mnt_parent;
-                               }
-                               if (n->mnt_group_id != last_dest->mnt_group_id) {
-                                       last_source = last_source->mnt_master;
-                                       last_dest = last_source->mnt_parent;
-                               }
+                       if (p == dest_master || IS_MNT_MARKED(p))
                                break;
-                       }
                }
+               do {
+                       struct mount *parent = last_source->mnt_parent;
+                       if (last_source == first_source)
+                               break;
+                       done = parent->mnt_master == p;
+                       if (done && peers(n, parent))
+                               break;
+                       last_source = last_source->mnt_master;
+               } while (!done);
+
                type = CL_SLAVE;
                /* beginning of peer group among the slaves? */
                if (IS_MNT_SHARED(m))
@@ -281,6 +288,7 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
         */
        user_ns = current->nsproxy->mnt_ns->user_ns;
        last_dest = dest_mnt;
+       first_source = source_mnt;
        last_source = source_mnt;
        mp = dest_mp;
        list = tree_list;
index 57df8a52e780c90d1fa433cf00146d03e174f09d..23d60b1995fb29e89cf37c93464ca0274cb8cf59 100644 (file)
@@ -954,7 +954,8 @@ static ssize_t environ_read(struct file *file, char __user *buf,
        int ret = 0;
        struct mm_struct *mm = file->private_data;
 
-       if (!mm)
+       /* Ensure the process spawned far enough to have an environment. */
+       if (!mm || !mm->env_end)
                return 0;
 
        page = (char *)__get_free_page(GFP_TEMPORARY);
index 67aa7e63a5c169a0634ff94c3012be3aa4a9691f..3e97da37b67c1d18522de52a616c0c76c1efc25e 100644 (file)
@@ -1497,6 +1497,32 @@ static struct page *can_gather_numa_stats(pte_t pte, struct vm_area_struct *vma,
        return page;
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static struct page *can_gather_numa_stats_pmd(pmd_t pmd,
+                                             struct vm_area_struct *vma,
+                                             unsigned long addr)
+{
+       struct page *page;
+       int nid;
+
+       if (!pmd_present(pmd))
+               return NULL;
+
+       page = vm_normal_page_pmd(vma, addr, pmd);
+       if (!page)
+               return NULL;
+
+       if (PageReserved(page))
+               return NULL;
+
+       nid = page_to_nid(page);
+       if (!node_isset(nid, node_states[N_MEMORY]))
+               return NULL;
+
+       return page;
+}
+#endif
+
 static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
                unsigned long end, struct mm_walk *walk)
 {
@@ -1506,13 +1532,13 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
        pte_t *orig_pte;
        pte_t *pte;
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
        if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
-               pte_t huge_pte = *(pte_t *)pmd;
                struct page *page;
 
-               page = can_gather_numa_stats(huge_pte, vma, addr);
+               page = can_gather_numa_stats_pmd(*pmd, vma, addr);
                if (page)
-                       gather_stats(page, md, pte_dirty(huge_pte),
+                       gather_stats(page, md, pmd_dirty(*pmd),
                                     HPAGE_PMD_SIZE/PAGE_SIZE);
                spin_unlock(ptl);
                return 0;
@@ -1520,6 +1546,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
 
        if (pmd_trans_unstable(pmd))
                return 0;
+#endif
        orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
        do {
                struct page *page = can_gather_numa_stats(*pte, vma, addr);
index 8ebd9a3340852823b17f61af59f4dd6a65f1b35f..87645955990d15a9df03df7b0c4b4b82100f1543 100644 (file)
@@ -197,6 +197,8 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
        if (sb->s_op->show_devname) {
                seq_puts(m, "device ");
                err = sb->s_op->show_devname(m, mnt_path.dentry);
+               if (err)
+                       goto out;
        } else {
                if (r->mnt_devname) {
                        seq_puts(m, "device ");
index ef0d64b2a6d947a0879a36fe4599f70d8cb925e5..353ff31dcee17a19af0ffdc67c25dde9f0eaa1d9 100644 (file)
@@ -1398,7 +1398,7 @@ static int dquot_active(const struct inode *inode)
 static int __dquot_initialize(struct inode *inode, int type)
 {
        int cnt, init_needed = 0;
-       struct dquot **dquots, *got[MAXQUOTAS];
+       struct dquot **dquots, *got[MAXQUOTAS] = {};
        struct super_block *sb = inode->i_sb;
        qsize_t rsv;
        int ret = 0;
@@ -1415,7 +1415,6 @@ static int __dquot_initialize(struct inode *inode, int type)
                int rc;
                struct dquot *dquot;
 
-               got[cnt] = NULL;
                if (type != -1 && cnt != type)
                        continue;
                /*
index 4cf700d50b4037e6c334b0647cdb81b816f9ef65..0f77e9682857a5b513b67b790af078f0b6fc9b28 100644 (file)
@@ -185,6 +185,9 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
        unsigned int spd_pages = spd->nr_pages;
        int ret, do_wakeup, page_nr;
 
+       if (!spd_pages)
+               return 0;
+
        ret = 0;
        do_wakeup = 0;
        page_nr = 0;
index 0ef7c2ed3f8a8e30e260485ee130d1a3b008ea07..4fa14820e2e22b687ef852b81e1d6b9f9028caf3 100644 (file)
@@ -202,8 +202,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
                                        sbp->namelen,
                                        sbp->valuelen,
                                        &sbp->name[sbp->namelen]);
-               if (error)
+               if (error) {
+                       kmem_free(sbuf);
                        return error;
+               }
                if (context->seen_enough)
                        break;
                cursor->offset++;
@@ -454,14 +456,13 @@ xfs_attr3_leaf_list_int(
                                args.rmtblkcnt = xfs_attr3_rmt_blocks(
                                                        args.dp->i_mount, valuelen);
                                retval = xfs_attr_rmtval_get(&args);
-                               if (retval)
-                                       return retval;
-                               retval = context->put_listent(context,
-                                               entry->flags,
-                                               name_rmt->name,
-                                               (int)name_rmt->namelen,
-                                               valuelen,
-                                               args.value);
+                               if (!retval)
+                                       retval = context->put_listent(context,
+                                                       entry->flags,
+                                                       name_rmt->name,
+                                                       (int)name_rmt->namelen,
+                                                       valuelen,
+                                                       args.value);
                                kmem_free(args.value);
                        } else {
                                retval = context->put_listent(context,
index c30266e9480650aa51b3f05b3d59ceedd5062e04..8ef0ccbf8167857c1c16c8235b745b1a8f37b3b0 100644 (file)
@@ -29,16 +29,16 @@ do {                                        \
  * @nr: the bit to set
  * @addr: the address to start counting from
  *
- * This operation is like clear_bit_unlock, however it is not atomic.
- * It does provide release barrier semantics so it can be used to unlock
- * a bit lock, however it would only be used if no other CPU can modify
- * any bits in the memory until the lock is released (a good example is
- * if the bit lock itself protects access to the other bits in the word).
+ * A weaker form of clear_bit_unlock() as used by __bit_lock_unlock(). If all
+ * the bits in the word are protected by this lock some archs can use weaker
+ * ops to safely unlock.
+ *
+ * See for example x86's implementation.
  */
 #define __clear_bit_unlock(nr, addr)   \
 do {                                   \
-       smp_mb();                       \
-       __clear_bit(nr, addr);          \
+       smp_mb__before_atomic();        \
+       clear_bit(nr, addr);            \
 } while (0)
 
 #endif /* _ASM_GENERIC_BITOPS_LOCK_H_ */
index 1cbb8338edf391bd83c4d1b0bc0dff2cbbe56e75..827e4d3bbc7a46ef59222651a8020234addc82cb 100644 (file)
@@ -70,12 +70,12 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
 #endif
 
 /* Return a pointer with offset calculated */
-#define __set_fixmap_offset(idx, phys, flags)                \
-({                                                           \
-       unsigned long addr;                                   \
-       __set_fixmap(idx, phys, flags);                       \
-       addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \
-       addr;                                                 \
+#define __set_fixmap_offset(idx, phys, flags)                          \
+({                                                                     \
+       unsigned long ________addr;                                     \
+       __set_fixmap(idx, phys, flags);                                 \
+       ________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1));   \
+       ________addr;                                                   \
 })
 
 #define set_fixmap_offset(idx, phys) \
index e56272c919b5a688e1739cdefaa08c121e26f5a8..bf2d34c9d804334cd0c634bf4d8ed921c08cfd7a 100644 (file)
@@ -108,11 +108,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
        u32 val;
 
        preempt_disable();
-       if (unlikely(get_user(val, uaddr) != 0))
+       if (unlikely(get_user(val, uaddr) != 0)) {
+               preempt_enable();
                return -EFAULT;
+       }
 
-       if (val == oldval && unlikely(put_user(newval, uaddr) != 0))
+       if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
+               preempt_enable();
                return -EFAULT;
+       }
 
        *uval = val;
        preempt_enable();
index 461a0558bca4d8d16e81b88e0286e3fa6251ab79..cebecff536a3a6aec1b06c69e32d8bb4ec2f4f29 100644 (file)
@@ -39,6 +39,8 @@ static inline bool drm_arch_can_wc_memory(void)
 {
 #if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
        return false;
+#elif defined(CONFIG_MIPS) && defined(CONFIG_CPU_LOONGSON3)
+       return false;
 #else
        return true;
 #endif
index a702c042b7162673a4f8092c78df740654d2fc4a..788c7c49a673cab6beab1f19fac0cc60fed795de 100644 (file)
@@ -216,6 +216,9 @@ struct css_set {
        /* all css_task_iters currently walking this cset */
        struct list_head task_iters;
 
+       /* dead and being drained, ignore for migration */
+       bool dead;
+
        /* For RCU-protected deletion */
        struct rcu_head rcu_head;
 };
@@ -432,6 +435,7 @@ struct cgroup_subsys {
        int (*can_attach)(struct cgroup_taskset *tset);
        void (*cancel_attach)(struct cgroup_taskset *tset);
        void (*attach)(struct cgroup_taskset *tset);
+       void (*post_attach)(void);
        int (*can_fork)(struct task_struct *task, void **priv_p);
        void (*cancel_fork)(struct task_struct *task, void *priv);
        void (*fork)(struct task_struct *task, void *priv);
index 22ab246feed34c104038d3f94e1401ea9a587f8f..eeae401a2412e5e8d32381805be1c13798b7a8fb 100644 (file)
 #define unreachable() __builtin_unreachable()
 
 /* Mark a function definition as prohibited from being cloned. */
-#define __noclone      __attribute__((__noclone__))
+#define __noclone      __attribute__((__noclone__, __optimize__("no-tracer")))
 
 #endif /* GCC_VERSION >= 40500 */
 
index fea160ee5803fd121d0493f622e240b4c35da480..85a868ccb4931d374a1ee9fb4e4036bb84399561 100644 (file)
@@ -137,8 +137,6 @@ static inline void set_mems_allowed(nodemask_t nodemask)
        task_unlock(current);
 }
 
-extern void cpuset_post_attach_flush(void);
-
 #else /* !CONFIG_CPUSETS */
 
 static inline bool cpusets_enabled(void) { return false; }
@@ -245,10 +243,6 @@ static inline bool read_mems_allowed_retry(unsigned int seq)
        return false;
 }
 
-static inline void cpuset_post_attach_flush(void)
-{
-}
-
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
index e7041ec48af8557c26dc3113fc7c9b853668e897..e4221f7c5b53a82492a2a03ac5d47bcd93d3ee5e 100644 (file)
@@ -162,6 +162,7 @@ struct dentry_operations {
        int (*d_manage)(struct dentry *, bool);
        struct inode *(*d_select_inode)(struct dentry *, unsigned);
        void (*d_canonical_path)(const struct dentry *, struct path *);
+       struct dentry *(*d_real)(struct dentry *, struct inode *);
 } ____cacheline_aligned;
 
 /*
@@ -228,6 +229,7 @@ struct dentry_operations {
 #define DCACHE_MAY_FREE                        0x00800000
 #define DCACHE_FALLTHRU                        0x01000000 /* Fall through to lower layer */
 #define DCACHE_OP_SELECT_INODE         0x02000000 /* Unioned entry: dcache op selects inode */
+#define DCACHE_OP_REAL                 0x08000000
 
 extern seqlock_t rename_lock;
 
@@ -583,4 +585,12 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper)
        return upper;
 }
 
+static inline struct dentry *d_real(struct dentry *dentry)
+{
+       if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
+               return dentry->d_op->d_real(dentry, NULL);
+       else
+               return dentry;
+}
+
 #endif /* __LINUX_DCACHE_H */
index ec1c61c87d8974897af2be54af23588f14746777..899ab9f8549e2bd489f36db0c47c855e5c92e19d 100644 (file)
@@ -124,6 +124,8 @@ struct dm_dev {
        char name[16];
 };
 
+dev_t dm_get_dev_t(const char *path);
+
 /*
  * Constructors should call these functions to ensure destination devices
  * are opened/closed correctly.
index 47be3ad7d3e5bad63b48a8fa344dbea65c0a97dd..333d0ca6940f0214f37b69377716d58852240a3c 100644 (file)
@@ -299,7 +299,7 @@ typedef struct {
        void *open_protocol_information;
        void *protocols_per_handle;
        void *locate_handle_buffer;
-       void *locate_protocol;
+       efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **);
        void *install_multiple_protocol_interfaces;
        void *uninstall_multiple_protocol_interfaces;
        void *calculate_crc32;
@@ -599,6 +599,10 @@ void efi_native_runtime_setup(void);
 #define EFI_PROPERTIES_TABLE_GUID \
     EFI_GUID(  0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 )
 
+#define EFI_RNG_PROTOCOL_GUID \
+       EFI_GUID(0x3152bca5, 0xeade, 0x433d, \
+                0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44)
+
 typedef struct {
        efi_guid_t guid;
        u64 table;
index 5972ffe5719a4e14012328035450759c12f43bec..5110d42118665cdab0f3bb377298b40d7c48febb 100644 (file)
@@ -446,8 +446,12 @@ int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog,
 void bpf_prog_destroy(struct bpf_prog *fp);
 
 int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
+                      bool locked);
 int sk_attach_bpf(u32 ufd, struct sock *sk);
 int sk_detach_filter(struct sock *sk);
+int __sk_detach_filter(struct sock *sk, bool locked);
+
 int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,
                  unsigned int len);
 
index 3aa51425416148f5bec14b6faf4e6f4e81370a22..ab3d8d9bb3efc0061fb2168b069b47947ee38109 100644 (file)
@@ -1207,6 +1207,16 @@ static inline struct inode *file_inode(const struct file *f)
        return f->f_inode;
 }
 
+static inline struct dentry *file_dentry(const struct file *file)
+{
+       struct dentry *dentry = file->f_path.dentry;
+
+       if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
+               return dentry->d_op->d_real(dentry, file_inode(file));
+       else
+               return dentry;
+}
+
 static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
 {
        return locks_lock_inode_wait(file_inode(filp), fl);
@@ -2217,7 +2227,7 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags,
 extern struct file *file_open_name(struct filename *, int, umode_t);
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
-                                  const char *, int);
+                                  const char *, int, umode_t);
 extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 
index 1afde47e1528c36ad8613c2e56fb23d1f614e476..79c52fa81cac9ea2dd3a1bea6e1093cd81fdb79c 100644 (file)
 #error Wordsize not 32 or 64
 #endif
 
+/*
+ * The above primes are actively bad for hashing, since they are
+ * too sparse. The 32-bit one is mostly ok, the 64-bit one causes
+ * real problems. Besides, the "prime" part is pointless for the
+ * multiplicative hash.
+ *
+ * Although a random odd number will do, it turns out that the golden
+ * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
+ * properties.
+ *
+ * These are the negative, (1 - phi) = (phi^2) = (3 - sqrt(5))/2.
+ * (See Knuth vol 3, section 6.4, exercise 9.)
+ */
+#define GOLDEN_RATIO_32 0x61C88647
+#define GOLDEN_RATIO_64 0x61C8864680B583EBull
+
 static __always_inline u64 hash_64(u64 val, unsigned int bits)
 {
        u64 hash = val;
 
-#if defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64
-       hash = hash * GOLDEN_RATIO_PRIME_64;
+#if BITS_PER_LONG == 64
+       hash = hash * GOLDEN_RATIO_64;
 #else
        /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
        u64 n = hash;
index 685c262e0be848ca049ee041d00d389d3cc327fe..b0eb06423d5eccba6cb850078af6ffc60d97c382 100644 (file)
@@ -96,9 +96,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
                                struct address_space *mapping,
                                pgoff_t idx, unsigned long address);
 
-#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
 pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
-#endif
 
 extern int hugepages_treat_as_movable;
 extern int sysctl_hugetlb_shm_group;
index a338a688ee4a4237eb938ff71627bbd5aafa442a..dcb89e3515db93d0359b726d60eccca918a0a707 100644 (file)
@@ -46,10 +46,6 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC       BIT(9)
 #define BR_PROXYARP_WIFI       BIT(10)
 
-/* values as per ieee8021QBridgeFdbAgingTime */
-#define BR_MIN_AGEING_TIME     (10 * HZ)
-#define BR_MAX_AGEING_TIME     (1000000 * HZ)
-
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
index 1eaf3d81f5c171379f6359bd93e121669e96025f..2955e672391d5e41f35b1e56bdf1517ecd076e30 100644 (file)
@@ -607,7 +607,7 @@ do {                                                        \
 
 #define do_trace_printk(fmt, args...)                                  \
 do {                                                                   \
-       static const char *trace_printk_fmt                             \
+       static const char *trace_printk_fmt __used                      \
                __attribute__((section("__trace_printk_fmt"))) =        \
                __builtin_constant_p(fmt) ? fmt : NULL;                 \
                                                                        \
@@ -651,7 +651,7 @@ int __trace_printk(unsigned long ip, const char *fmt, ...);
  */
 
 #define trace_puts(str) ({                                             \
-       static const char *trace_printk_fmt                             \
+       static const char *trace_printk_fmt __used                      \
                __attribute__((section("__trace_printk_fmt"))) =        \
                __builtin_constant_p(str) ? str : NULL;                 \
                                                                        \
@@ -673,7 +673,7 @@ extern void trace_dump_stack(int skip);
 #define ftrace_vprintk(fmt, vargs)                                     \
 do {                                                                   \
        if (__builtin_constant_p(fmt)) {                                \
-               static const char *trace_printk_fmt                     \
+               static const char *trace_printk_fmt __used              \
                  __attribute__((section("__trace_printk_fmt"))) =      \
                        __builtin_constant_p(fmt) ? fmt : NULL;         \
                                                                        \
index 0b473cbfa7ef10c875c1eed802c2a7dd74f415d4..a91b67b18a7308b2b25eb5abe7abf2c01ccbb5f5 100644 (file)
@@ -334,6 +334,17 @@ enum {
        MLX5_CAP_OFF_CMDIF_CSUM         = 46,
 };
 
+enum {
+       /*
+        * Max wqe size for rdma read is 512 bytes, so this
+        * limits our max_sge_rd as the wqe needs to fit:
+        * - ctrl segment (16 bytes)
+        * - rdma segment (16 bytes)
+        * - scatter elements (16 bytes each)
+        */
+       MLX5_MAX_SGE_RD = (512 - 16 - 16) / 16
+};
+
 struct mlx5_inbox_hdr {
        __be16          opcode;
        u8              rsvd[4];
index f4c35e8125d15c0ac9f6bab1950d84f3d5e3dd65..fb987b2e5abd4df71ba6789a48298620201f60b3 100644 (file)
@@ -1096,6 +1096,8 @@ struct zap_details {
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
                pte_t pte);
+struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
+                               pmd_t pmd);
 
 int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
                unsigned long size);
index 3143c847bddbca47bed1a324bf85e58283e966a5..04c068e55353297fafc059e3dc3abcf5c0b1eab3 100644 (file)
@@ -265,6 +265,7 @@ struct header_ops {
        void    (*cache_update)(struct hh_cache *hh,
                                const struct net_device *dev,
                                const unsigned char *haddr);
+       bool    (*validate)(const char *ll_header, unsigned int len);
 };
 
 /* These flag bits are private to the generic network queueing
@@ -1398,8 +1399,7 @@ enum netdev_priv_flags {
  *     @dma:           DMA channel
  *     @mtu:           Interface MTU value
  *     @type:          Interface hardware type
- *     @hard_header_len: Hardware header length, which means that this is the
- *                       minimum size of a packet.
+ *     @hard_header_len: Maximum hardware header length.
  *
  *     @needed_headroom: Extra headroom the hardware may need, but not in all
  *                       cases can this be guaranteed
@@ -2493,6 +2493,24 @@ static inline int dev_parse_header(const struct sk_buff *skb,
        return dev->header_ops->parse(skb, haddr);
 }
 
+/* ll_header must have at least hard_header_len allocated */
+static inline bool dev_validate_header(const struct net_device *dev,
+                                      char *ll_header, int len)
+{
+       if (likely(len >= dev->hard_header_len))
+               return true;
+
+       if (capable(CAP_SYS_RAWIO)) {
+               memset(ll_header + len, 0, dev->hard_header_len - len);
+               return true;
+       }
+
+       if (dev->header_ops && dev->header_ops->validate)
+               return dev->header_ops->validate(ll_header, len);
+
+       return false;
+}
+
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
 int register_gifconf(unsigned int family, gifconf_func_t *gifconf);
 static inline int unregister_gifconf(unsigned int family)
index 6ae25aae88fd1254f40227341ca20b73a2e08ce2..e89c7ee7e8036b55abd63a687fbd91e858006554 100644 (file)
@@ -359,6 +359,7 @@ struct pci_dev {
        unsigned int    io_window_1k:1; /* Intel P2P bridge 1K I/O windows */
        unsigned int    irq_managed:1;
        unsigned int    has_secondary_link:1;
+       unsigned int    non_compliant_bars:1;   /* broken BARs; ignore them */
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */
 
@@ -988,23 +989,6 @@ static inline int pci_is_managed(struct pci_dev *pdev)
        return pdev->is_managed;
 }
 
-static inline void pci_set_managed_irq(struct pci_dev *pdev, unsigned int irq)
-{
-       pdev->irq = irq;
-       pdev->irq_managed = 1;
-}
-
-static inline void pci_reset_managed_irq(struct pci_dev *pdev)
-{
-       pdev->irq = 0;
-       pdev->irq_managed = 0;
-}
-
-static inline bool pci_has_managed_irq(struct pci_dev *pdev)
-{
-       return pdev->irq_managed && pdev->irq > 0;
-}
-
 void pci_disable_device(struct pci_dev *dev);
 
 extern unsigned int pcibios_max_latency;
index 5e0bc779e6c531b6141a4c0c8dca9d14c977a8e7..33f88b4479e49fa0a024df8830361ce900f386b1 100644 (file)
@@ -39,6 +39,10 @@ struct samsung_i2s {
  */
 struct s3c_audio_pdata {
        int (*cfg_gpio)(struct platform_device *);
+       void *dma_playback;
+       void *dma_capture;
+       void *dma_play_sec;
+       void *dma_capture_mic;
        union {
                struct samsung_i2s i2s;
        } type;
index 9a2e50337af9fd233656b8fb6f06a91c10b2e7bf..cccaf4a29e9f02c9a60b65f73a523a69efa5af3a 100644 (file)
@@ -34,6 +34,8 @@ bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp);
 
 int dev_pm_opp_get_opp_count(struct device *dev);
 unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev);
+unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev);
+unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev);
 struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev);
 
 struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
@@ -55,6 +57,14 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq);
 int dev_pm_opp_disable(struct device *dev, unsigned long freq);
 
 struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev);
+int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
+                               unsigned int count);
+void dev_pm_opp_put_supported_hw(struct device *dev);
+int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
+void dev_pm_opp_put_prop_name(struct device *dev);
+int dev_pm_opp_set_regulator(struct device *dev, const char *name);
+void dev_pm_opp_put_regulator(struct device *dev);
+int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
 #else
 static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
 {
@@ -81,6 +91,16 @@ static inline unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
        return 0;
 }
 
+static inline unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
+{
+       return 0;
+}
+
+static inline unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
+{
+       return 0;
+}
+
 static inline struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev)
 {
        return NULL;
@@ -129,6 +149,35 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(
 {
        return ERR_PTR(-EINVAL);
 }
+
+static inline int dev_pm_opp_set_supported_hw(struct device *dev,
+                                             const u32 *versions,
+                                             unsigned int count)
+{
+       return -EINVAL;
+}
+
+static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
+
+static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+{
+       return -EINVAL;
+}
+
+static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
+
+static inline int dev_pm_opp_set_regulator(struct device *dev, const char *name)
+{
+       return -EINVAL;
+}
+
+static inline void dev_pm_opp_put_regulator(struct device *dev) {}
+
+static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
+{
+       return -EINVAL;
+}
+
 #endif         /* CONFIG_PM_OPP */
 
 #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
index 75f136a22a5ebf378b3e0ddec8493effc8b72d36..4fde61804191e0e546cf6a702b56148496683851 100644 (file)
@@ -1908,6 +1908,30 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
        skb->tail += len;
 }
 
+/**
+ *     skb_tailroom_reserve - adjust reserved_tailroom
+ *     @skb: buffer to alter
+ *     @mtu: maximum amount of headlen permitted
+ *     @needed_tailroom: minimum amount of reserved_tailroom
+ *
+ *     Set reserved_tailroom so that headlen can be as large as possible but
+ *     not larger than mtu and tailroom cannot be smaller than
+ *     needed_tailroom.
+ *     The required headroom should already have been reserved before using
+ *     this function.
+ */
+static inline void skb_tailroom_reserve(struct sk_buff *skb, unsigned int mtu,
+                                       unsigned int needed_tailroom)
+{
+       SKB_LINEAR_ASSERT(skb);
+       if (mtu < skb_tailroom(skb) - needed_tailroom)
+               /* use at most mtu */
+               skb->reserved_tailroom = skb_tailroom(skb) - mtu;
+       else
+               /* use up to all available space */
+               skb->reserved_tailroom = needed_tailroom;
+}
+
 #define ENCAP_TYPE_ETHER       0
 #define ENCAP_TYPE_IPPROTO     1
 
@@ -2724,6 +2748,23 @@ static inline void skb_postpull_rcsum(struct sk_buff *skb,
 
 unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len);
 
+static inline void skb_postpush_rcsum(struct sk_buff *skb,
+                                     const void *start, unsigned int len)
+{
+       /* For performing the reverse operation to skb_postpull_rcsum(),
+        * we can instead of ...
+        *
+        *   skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
+        *
+        * ... just use this equivalent version here to save a few
+        * instructions. Feeding csum of 0 in csum_partial() and later
+        * on adding skb->csum is equivalent to feed skb->csum in the
+        * first place.
+        */
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
+               skb->csum = csum_partial(start, len, skb->csum);
+}
+
 /**
  *     pskb_trim_rcsum - trim received skb and update checksum
  *     @skb: buffer to trim
index 1423eaff9ac3635c7d43ea6190606ec208a3a541..328d6c0a907397960a15b6bd70fac769ee23bb93 100644 (file)
@@ -157,6 +157,7 @@ struct thermal_attr {
  * @trip_hyst_attrs:   attributes for trip points for sysfs: trip hysteresis
  * @devdata:   private pointer for device private data
  * @trips:     number of trip points the thermal zone supports
+ * @trips_disabled;    bitmap for disabled trips
  * @passive_delay:     number of milliseconds to wait between polls when
  *                     performing passive cooling.
  * @polling_delay:     number of milliseconds to wait between polls when
@@ -192,6 +193,7 @@ struct thermal_zone_device {
        struct thermal_attr *trip_hyst_attrs;
        void *devdata;
        int trips;
+       unsigned long trips_disabled;   /* bitmap for disabled trips */
        int passive_delay;
        int polling_delay;
        int temperature;
index 6b6e811f45752f627eaa9c4a96a60ef6504c7064..3bf03b6b52e9b41b30c7b188b3e6c6af9b772d78 100644 (file)
@@ -594,7 +594,7 @@ static inline int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p,
                count = ld->ops->receive_buf2(ld->tty, p, f, count);
        else {
                count = min_t(int, count, ld->tty->receive_room);
-               if (count)
+               if (count && ld->ops->receive_buf)
                        ld->ops->receive_buf(ld->tty, p, f, count);
        }
        return count;
index 7f5f78bd15ad448414fa8c06fb61fa25fb152b5f..245f57dbbb614e818d2f067f1f5c431d7e9f193b 100644 (file)
@@ -79,6 +79,8 @@
                /* Cannot handle MI_REPORT_SUPPORTED_OPERATION_CODES */ \
        US_FLAG(MAX_SECTORS_240,        0x08000000)             \
                /* Sets max_sectors to 240 */                   \
+       US_FLAG(NO_REPORT_LUNS, 0x10000000)                     \
+               /* Cannot handle REPORT_LUNS */                 \
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
index 647ebfe5174f623b27723924a521cc3f483329dd..d4227a8a2a23c1894f4e64b52140e82d895ea434 100644 (file)
@@ -363,6 +363,7 @@ struct vb2_ops {
 };
 
 struct vb2_buf_ops {
+       int (*verify_planes_array)(struct vb2_buffer *vb, const void *pb);
        int (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
        int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb,
                                struct vb2_plane *planes);
index c1740a2794a37bce9dc9d48739a766a93ff4f743..93abe5f6188d29f852fba3ca97925acebf4b0f9c 100644 (file)
@@ -214,6 +214,7 @@ struct bonding {
         * ALB mode (6) - to sync the use and modifications of its hash table
         */
        spinlock_t mode_lock;
+       spinlock_t stats_lock;
        u8       send_peer_notif;
        u8       igmp_retrans;
 #ifdef CONFIG_PROC_FS
index 0816c872b68911077bd51bc41dee0e32e1c3213d..a6cc576fd467f879054c344c24dede5010c72992 100644 (file)
@@ -1588,6 +1588,23 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
 }
 #endif /* CONFIG_IP_VS_NFCT */
 
+/* Really using conntrack? */
+static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
+                                            struct sk_buff *skb)
+{
+#ifdef CONFIG_IP_VS_NFCT
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct;
+
+       if (!(cp->flags & IP_VS_CONN_F_NFCT))
+               return false;
+       ct = nf_ct_get(skb, &ctinfo);
+       if (ct && !nf_ct_is_untracked(ct))
+               return true;
+#endif
+       return false;
+}
+
 static inline int
 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
 {
index cf8f9e700e48939b7633a97df7f815486e0fb8a8..a6b93706b0fc96494d7de3d7408c26fb57436a02 100644 (file)
@@ -34,6 +34,7 @@
 #define _RDMA_IB_H
 
 #include <linux/types.h>
+#include <linux/sched.h>
 
 struct ib_addr {
        union {
@@ -86,4 +87,19 @@ struct sockaddr_ib {
        __u64                   sib_scope_id;
 };
 
+/*
+ * The IB interfaces that use write() as bi-directional ioctl() are
+ * fundamentally unsafe, since there are lots of ways to trigger "write()"
+ * calls from various contexts with elevated privileges. That includes the
+ * traditional suid executable error message writes, but also various kernel
+ * interfaces that can write to file descriptors.
+ *
+ * This function provides protection for the legacy API by restricting the
+ * calling context.
+ */
+static inline bool ib_safe_file_access(struct file *filp)
+{
+       return filp->f_cred == current_cred() && segment_eq(get_fs(), USER_DS);
+}
+
 #endif /* _RDMA_IB_H */
index c039f1d68a0929bfac96031d8eaa489be19edba9..086168e18ca83e462dcf088316d8f6c436cde42f 100644 (file)
 
 #define V4L2_DV_BT_CEA_3840X2160P24 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                297000000, 1276, 88, 296, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, \
                V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
 
 #define V4L2_DV_BT_CEA_3840X2160P25 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                297000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_3840X2160P30 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                297000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, \
                V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
 
 #define V4L2_DV_BT_CEA_3840X2160P50 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                594000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_3840X2160P60 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                594000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, \
                V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
 
 #define V4L2_DV_BT_CEA_4096X2160P24 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                297000000, 1020, 88, 296, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, \
                V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
 
 #define V4L2_DV_BT_CEA_4096X2160P25 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                297000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_4096X2160P30 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                297000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, \
                V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
 
 #define V4L2_DV_BT_CEA_4096X2160P50 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                594000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \
 }
 
 #define V4L2_DV_BT_CEA_4096X2160P60 { \
        .type = V4L2_DV_BT_656_1120, \
-       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+       V4L2_INIT_BT_TIMINGS(4096, 2160, 0, \
+               V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
                594000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \
                V4L2_DV_BT_STD_CEA861, \
                V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \
index 96294ac937552178531266cb16ce04185e47c99a..9dc46cb8a0fd79be7f4bdae7ae8f5f4dbdcdb7f4 100644 (file)
@@ -15,9 +15,9 @@
  */
 
 #define xen_pfn_to_page(xen_pfn)       \
-       ((pfn_to_page(((unsigned long)(xen_pfn) << XEN_PAGE_SHIFT) >> PAGE_SHIFT)))
+       (pfn_to_page((unsigned long)(xen_pfn) >> (PAGE_SHIFT - XEN_PAGE_SHIFT)))
 #define page_to_xen_pfn(page)          \
-       (((page_to_pfn(page)) << PAGE_SHIFT) >> XEN_PAGE_SHIFT)
+       ((page_to_pfn(page)) << (PAGE_SHIFT - XEN_PAGE_SHIFT))
 
 #define XEN_PFN_PER_PAGE       (PAGE_SIZE / XEN_PAGE_SIZE)
 
index 4504ca66118da0c0735bdb56d9204ba6cb79994b..50da680c479f030588314ed664c8d57200c28990 100644 (file)
@@ -166,7 +166,7 @@ static u64 bpf_get_current_comm(u64 r1, u64 size, u64 r3, u64 r4, u64 r5)
        if (!task)
                return -EINVAL;
 
-       memcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
+       strlcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
        return 0;
 }
 
index b6a443e156b8ec545a7a16e113c4ae4964aa1281..47851dbc893d1ee1e952bf6ef37792c59f1af77b 100644 (file)
@@ -2498,6 +2498,14 @@ static void cgroup_migrate_add_src(struct css_set *src_cset,
        lockdep_assert_held(&cgroup_mutex);
        lockdep_assert_held(&css_set_lock);
 
+       /*
+        * If ->dead, @src_set is associated with one or more dead cgroups
+        * and doesn't contain any migratable tasks.  Ignore it early so
+        * that the rest of migration path doesn't get confused by it.
+        */
+       if (src_cset->dead)
+               return;
+
        src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
 
        if (!list_empty(&src_cset->mg_preload_node))
@@ -2768,9 +2776,10 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
                                    size_t nbytes, loff_t off, bool threadgroup)
 {
        struct task_struct *tsk;
+       struct cgroup_subsys *ss;
        struct cgroup *cgrp;
        pid_t pid;
-       int ret;
+       int ssid, ret;
 
        if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
                return -EINVAL;
@@ -2818,8 +2827,10 @@ out_unlock_rcu:
        rcu_read_unlock();
 out_unlock_threadgroup:
        percpu_up_write(&cgroup_threadgroup_rwsem);
+       for_each_subsys(ss, ssid)
+               if (ss->post_attach)
+                       ss->post_attach();
        cgroup_kn_unlock(of->kn);
-       cpuset_post_attach_flush();
        return ret ?: nbytes;
 }
 
@@ -4736,14 +4747,15 @@ static void css_free_work_fn(struct work_struct *work)
 
        if (ss) {
                /* css free path */
+               struct cgroup_subsys_state *parent = css->parent;
                int id = css->id;
 
-               if (css->parent)
-                       css_put(css->parent);
-
                ss->css_free(css);
                cgroup_idr_remove(&ss->css_idr, id);
                cgroup_put(cgrp);
+
+               if (parent)
+                       css_put(parent);
        } else {
                /* cgroup free path */
                atomic_dec(&cgrp->root->nr_cgrps);
@@ -5186,6 +5198,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
        __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
 {
        struct cgroup_subsys_state *css;
+       struct cgrp_cset_link *link;
        int ssid;
 
        lockdep_assert_held(&cgroup_mutex);
@@ -5206,11 +5219,18 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
                return -EBUSY;
 
        /*
-        * Mark @cgrp dead.  This prevents further task migration and child
-        * creation by disabling cgroup_lock_live_group().
+        * Mark @cgrp and the associated csets dead.  The former prevents
+        * further task migration and child creation by disabling
+        * cgroup_lock_live_group().  The latter makes the csets ignored by
+        * the migration path.
         */
        cgrp->self.flags &= ~CSS_ONLINE;
 
+       spin_lock_bh(&css_set_lock);
+       list_for_each_entry(link, &cgrp->cset_links, cset_link)
+               link->cset->dead = true;
+       spin_unlock_bh(&css_set_lock);
+
        /* initiate massacre of all css's */
        for_each_css(css, ssid, cgrp)
                kill_css(css);
index 2ade632197d5159efb21b5b45b2de41417901a0c..11eaf14b52c2919b63131485d33dd2e7203aca58 100644 (file)
@@ -57,7 +57,6 @@
 #include <asm/uaccess.h>
 #include <linux/atomic.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
 #include <linux/cgroup.h>
 #include <linux/wait.h>
 
@@ -1015,7 +1014,7 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
        }
 }
 
-void cpuset_post_attach_flush(void)
+static void cpuset_post_attach(void)
 {
        flush_workqueue(cpuset_migrate_mm_wq);
 }
@@ -2083,6 +2082,7 @@ struct cgroup_subsys cpuset_cgrp_subsys = {
        .can_attach     = cpuset_can_attach,
        .cancel_attach  = cpuset_cancel_attach,
        .attach         = cpuset_attach,
+       .post_attach    = cpuset_post_attach,
        .bind           = cpuset_bind,
        .legacy_cftypes = files,
        .early_init     = 1,
index 1087bbeb152b101f5f20d61bac075a0f88f28944..1e889a078dbc0db447f2cf0bde8353412951d63c 100644 (file)
@@ -1580,14 +1580,14 @@ event_sched_out(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
+       event->tstamp_stopped = tstamp;
+       event->pmu->del(event, 0);
+       event->oncpu = -1;
        event->state = PERF_EVENT_STATE_INACTIVE;
        if (event->pending_disable) {
                event->pending_disable = 0;
                event->state = PERF_EVENT_STATE_OFF;
        }
-       event->tstamp_stopped = tstamp;
-       event->pmu->del(event, 0);
-       event->oncpu = -1;
 
        if (!is_software_event(event))
                cpuctx->active_oncpu--;
@@ -7979,6 +7979,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
                }
        }
 
+       /* symmetric to unaccount_event() in _free_event() */
+       account_event(event);
+
        return event;
 
 err_per_task:
@@ -8342,8 +8345,6 @@ SYSCALL_DEFINE5(perf_event_open,
                }
        }
 
-       account_event(event);
-
        /*
         * Special case software events and allow them to be part of
         * any hardware group.
@@ -8582,7 +8583,12 @@ err_context:
        perf_unpin_context(ctx);
        put_ctx(ctx);
 err_alloc:
-       free_event(event);
+       /*
+        * If event_file is set, the fput() above will have called ->release()
+        * and that will take care of freeing the event.
+        */
+       if (!event_file)
+               free_event(event);
 err_cpus:
        put_online_cpus();
 err_task:
@@ -8626,8 +8632,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
        /* Mark owner so we could distinguish it from user events. */
        event->owner = EVENT_OWNER_KERNEL;
 
-       account_event(event);
-
        ctx = find_get_context(event->pmu, task, event);
        if (IS_ERR(ctx)) {
                err = PTR_ERR(ctx);
index 461c72b2dac2c4d316e66b38b5b7d73d980ab347..9d8163afd87ca7605ef85d2ca64d3c4521838fae 100644 (file)
@@ -1244,10 +1244,20 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this,
        if (unlikely(should_fail_futex(true)))
                ret = -EFAULT;
 
-       if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
+       if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) {
                ret = -EFAULT;
-       else if (curval != uval)
-               ret = -EINVAL;
+       } else if (curval != uval) {
+               /*
+                * If a unconditional UNLOCK_PI operation (user space did not
+                * try the TID->0 transition) raced with a waiter setting the
+                * FUTEX_WAITERS flag between get_user() and locking the hash
+                * bucket lock, retry the operation.
+                */
+               if ((FUTEX_TID_MASK & curval) == uval)
+                       ret = -EAGAIN;
+               else
+                       ret = -EINVAL;
+       }
        if (ret) {
                raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
                return ret;
@@ -1474,8 +1484,8 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
        if (likely(&hb1->chain != &hb2->chain)) {
                plist_del(&q->list, &hb1->chain);
                hb_waiters_dec(hb1);
-               plist_add(&q->list, &hb2->chain);
                hb_waiters_inc(hb2);
+               plist_add(&q->list, &hb2->chain);
                q->lock_ptr = &hb2->lock;
        }
        get_futex_key_refs(key2);
@@ -2537,6 +2547,15 @@ retry:
                 */
                if (ret == -EFAULT)
                        goto pi_faulted;
+               /*
+                * A unconditional UNLOCK_PI op raced against a waiter
+                * setting the FUTEX_WAITERS bit. Try again.
+                */
+               if (ret == -EAGAIN) {
+                       spin_unlock(&hb->lock);
+                       put_futex_key(&key);
+                       goto retry;
+               }
                /*
                 * wake_futex_pi has detected invalid state. Tell user
                 * space.
index 5b9102a47ea5209dd887b6dfbca16215b2bad922..c835270f0c2f93c24f623e9ea2ba2e94eebb006a 100644 (file)
@@ -67,7 +67,13 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
        node->locked = 0;
        node->next   = NULL;
 
-       prev = xchg_acquire(lock, node);
+       /*
+        * We rely on the full barrier with global transitivity implied by the
+        * below xchg() to order the initialization stores above against any
+        * observation of @node. And to provide the ACQUIRE ordering associated
+        * with a LOCK primitive.
+        */
+       prev = xchg(lock, node);
        if (likely(prev == NULL)) {
                /*
                 * Lock acquired, don't need to set node->locked to 1. Threads
index b7342a24f559211934fb90db21a4a06d5479b21a..b7dd5718836e2b76c0c0700251bae66364e72da8 100644 (file)
@@ -339,6 +339,7 @@ int hibernation_snapshot(int platform_mode)
        pm_message_t msg;
        int error;
 
+       pm_suspend_clear_flags();
        error = platform_begin(platform_mode);
        if (error)
                goto Close;
index 6d56ca1975221faeab7d974b333b82b2a1a442ec..ff6b870315b79fb4ae86fac0e4a978f5ab1e3642 100644 (file)
@@ -5525,6 +5525,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
 
        case CPU_UP_PREPARE:
                rq->calc_load_update = calc_load_update;
+               account_reset_rq(rq);
                break;
 
        case CPU_ONLINE:
@@ -7702,7 +7703,7 @@ void set_curr_task(int cpu, struct task_struct *p)
 /* task_group_lock serializes the addition/removal of task groups */
 static DEFINE_SPINLOCK(task_group_lock);
 
-static void free_sched_group(struct task_group *tg)
+static void sched_free_group(struct task_group *tg)
 {
        free_fair_sched_group(tg);
        free_rt_sched_group(tg);
@@ -7728,7 +7729,7 @@ struct task_group *sched_create_group(struct task_group *parent)
        return tg;
 
 err:
-       free_sched_group(tg);
+       sched_free_group(tg);
        return ERR_PTR(-ENOMEM);
 }
 
@@ -7748,17 +7749,16 @@ void sched_online_group(struct task_group *tg, struct task_group *parent)
 }
 
 /* rcu callback to free various structures associated with a task group */
-static void free_sched_group_rcu(struct rcu_head *rhp)
+static void sched_free_group_rcu(struct rcu_head *rhp)
 {
        /* now it should be safe to free those cfs_rqs */
-       free_sched_group(container_of(rhp, struct task_group, rcu));
+       sched_free_group(container_of(rhp, struct task_group, rcu));
 }
 
-/* Destroy runqueue etc associated with a task group */
 void sched_destroy_group(struct task_group *tg)
 {
        /* wait for possible concurrent references to cfs_rqs complete */
-       call_rcu(&tg->rcu, free_sched_group_rcu);
+       call_rcu(&tg->rcu, sched_free_group_rcu);
 }
 
 void sched_offline_group(struct task_group *tg)
@@ -8219,31 +8219,26 @@ cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
        if (IS_ERR(tg))
                return ERR_PTR(-ENOMEM);
 
+       sched_online_group(tg, parent);
+
        return &tg->css;
 }
 
-static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
+static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
 {
        struct task_group *tg = css_tg(css);
-       struct task_group *parent = css_tg(css->parent);
 
-       if (parent)
-               sched_online_group(tg, parent);
-       return 0;
+       sched_offline_group(tg);
 }
 
 static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
 {
        struct task_group *tg = css_tg(css);
 
-       sched_destroy_group(tg);
-}
-
-static void cpu_cgroup_css_offline(struct cgroup_subsys_state *css)
-{
-       struct task_group *tg = css_tg(css);
-
-       sched_offline_group(tg);
+       /*
+        * Relies on the RCU grace period between css_released() and this.
+        */
+       sched_free_group(tg);
 }
 
 static void cpu_cgroup_fork(struct task_struct *task, void *private)
@@ -8603,9 +8598,8 @@ static struct cftype cpu_files[] = {
 
 struct cgroup_subsys cpu_cgrp_subsys = {
        .css_alloc      = cpu_cgroup_css_alloc,
+       .css_released   = cpu_cgroup_css_released,
        .css_free       = cpu_cgroup_css_free,
-       .css_online     = cpu_cgroup_css_online,
-       .css_offline    = cpu_cgroup_css_offline,
        .fork           = cpu_cgroup_fork,
        .can_attach     = cpu_cgroup_can_attach,
        .attach         = cpu_cgroup_attach,
index 05de80b48586e9fa3241c708c7e6fd7c9b6fb24a..f74ea89e77a8e5aa5faf8abf6c2f1132a92de397 100644 (file)
@@ -259,21 +259,21 @@ static __always_inline bool steal_account_process_tick(void)
 #ifdef CONFIG_PARAVIRT
        if (static_key_false(&paravirt_steal_enabled)) {
                u64 steal;
-               cputime_t steal_ct;
+               unsigned long steal_jiffies;
 
                steal = paravirt_steal_clock(smp_processor_id());
                steal -= this_rq()->prev_steal_time;
 
                /*
-                * cputime_t may be less precise than nsecs (eg: if it's
-                * based on jiffies). Lets cast the result to cputime
+                * steal is in nsecs but our caller is expecting steal
+                * time in jiffies. Lets cast the result to jiffies
                 * granularity and account the rest on the next rounds.
                 */
-               steal_ct = nsecs_to_cputime(steal);
-               this_rq()->prev_steal_time += cputime_to_nsecs(steal_ct);
+               steal_jiffies = nsecs_to_jiffies(steal);
+               this_rq()->prev_steal_time += jiffies_to_nsecs(steal_jiffies);
 
-               account_steal_time(steal_ct);
-               return steal_ct;
+               account_steal_time(jiffies_to_cputime(steal_jiffies));
+               return steal_jiffies;
        }
 #endif
        return false;
index b242775bf670e116233862c590915e06132485ca..0517abd7dd73b95f152f339b684328165d76f59f 100644 (file)
@@ -1770,3 +1770,16 @@ static inline u64 irq_time_read(int cpu)
 }
 #endif /* CONFIG_64BIT */
 #endif /* CONFIG_IRQ_TIME_ACCOUNTING */
+
+static inline void account_reset_rq(struct rq *rq)
+{
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+       rq->prev_irq_time = 0;
+#endif
+#ifdef CONFIG_PARAVIRT
+       rq->prev_steal_time = 0;
+#endif
+#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
+       rq->prev_steal_time_rq = 0;
+#endif
+}
index 7e7746a42a623e66034b73c1e78f017d469b9f53..10a1d7dc931358caf4fddda72b5dcda857dd8a98 100644 (file)
@@ -1321,7 +1321,7 @@ static ssize_t binary_sysctl(const int *name, int nlen,
        }
 
        mnt = task_active_pid_ns(current)->proc_mnt;
-       file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
+       file = file_open_root(mnt->mnt_root, mnt, pathname, flags, 0);
        result = PTR_ERR(file);
        if (IS_ERR(file))
                goto out_putname;
index 1e488a1be4c342e0b57c046c9cc20c9b983a1c02..dd4d86ae8e213aafe5814aa00ffbab01c3cdd1c8 100644 (file)
@@ -5038,7 +5038,10 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
 
        spd.nr_pages = i;
 
-       ret = splice_to_pipe(pipe, &spd);
+       if (i)
+               ret = splice_to_pipe(pipe, &spd);
+       else
+               ret = 0;
 out:
        splice_shrink_spd(&spd);
        return ret;
index d202d991edae5e433f3f0b8ccb864222a65a2b40..996f0fd343125117ade2c8161d2aff04e62ebc65 100644 (file)
@@ -2107,8 +2107,13 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
        trace_create_file("filter", 0644, file->dir, file,
                          &ftrace_event_filter_fops);
 
-       trace_create_file("trigger", 0644, file->dir, file,
-                         &event_trigger_fops);
+       /*
+        * Only event directories that can be enabled should have
+        * triggers.
+        */
+       if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
+               trace_create_file("trigger", 0644, file->dir, file,
+                                 &event_trigger_fops);
 
        trace_create_file("format", 0444, file->dir, call,
                          &ftrace_event_format_fops);
index e4e56589ec1d392c1734ddff45e87b6fc2dde2fb..be3222b7d72ee5cdf280092035f56eb2403b23ce 100644 (file)
@@ -109,8 +109,12 @@ static int func_prolog_dec(struct trace_array *tr,
                return 0;
 
        local_save_flags(*flags);
-       /* slight chance to get a false positive on tracing_cpu */
-       if (!irqs_disabled_flags(*flags))
+       /*
+        * Slight chance to get a false positive on tracing_cpu,
+        * although I'm starting to think there isn't a chance.
+        * Leave this for now just to be paranoid.
+        */
+       if (!irqs_disabled_flags(*flags) && !preempt_count())
                return 0;
 
        *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
index 060df67dbdd1d038dba8ec35909890f3e892b6d7..f96f0383f6c6bfe40cba9226b97f8885723a4d9d 100644 (file)
@@ -296,6 +296,9 @@ static int t_show(struct seq_file *m, void *v)
        const char *str = *fmt;
        int i;
 
+       if (!*fmt)
+               return 0;
+
        seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
 
        /*
index e864906af3fc7a733831542c52547acf7a4821d7..1f1b05f5a94b8edaf014495a985168b39d73877f 100644 (file)
@@ -1020,6 +1020,9 @@ static int proc_watchdog_common(int which, struct ctl_table *table, int write,
                 * both lockup detectors are disabled if proc_watchdog_update()
                 * returns an error.
                 */
+               if (old == new)
+                       goto out;
+
                err = proc_watchdog_update();
        }
 out:
@@ -1064,7 +1067,7 @@ int proc_soft_watchdog(struct ctl_table *table, int write,
 int proc_watchdog_thresh(struct ctl_table *table, int write,
                         void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       int err, old;
+       int err, old, new;
 
        get_online_cpus();
        mutex_lock(&watchdog_proc_mutex);
@@ -1084,6 +1087,10 @@ int proc_watchdog_thresh(struct ctl_table *table, int write,
        /*
         * Update the sample period. Restore on failure.
         */
+       new = ACCESS_ONCE(watchdog_thresh);
+       if (old == new)
+               goto out;
+
        set_sample_period();
        err = proc_watchdog_update();
        if (err) {
index 450c21fd0e6e4289bcf1d2d3b6ba78d68d992df5..0ec05948a97bb3bc4b84b271e0fd18821adff54c 100644 (file)
@@ -649,6 +649,35 @@ static void set_work_pool_and_clear_pending(struct work_struct *work,
         */
        smp_wmb();
        set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0);
+       /*
+        * The following mb guarantees that previous clear of a PENDING bit
+        * will not be reordered with any speculative LOADS or STORES from
+        * work->current_func, which is executed afterwards.  This possible
+        * reordering can lead to a missed execution on attempt to qeueue
+        * the same @work.  E.g. consider this case:
+        *
+        *   CPU#0                         CPU#1
+        *   ----------------------------  --------------------------------
+        *
+        * 1  STORE event_indicated
+        * 2  queue_work_on() {
+        * 3    test_and_set_bit(PENDING)
+        * 4 }                             set_..._and_clear_pending() {
+        * 5                                 set_work_data() # clear bit
+        * 6                                 smp_mb()
+        * 7                               work->current_func() {
+        * 8                                  LOAD event_indicated
+        *                                 }
+        *
+        * Without an explicit full barrier speculative LOAD on line 8 can
+        * be executed before CPU#0 does STORE on line 1.  If that happens,
+        * CPU#0 observes the PENDING bit is still set and new execution of
+        * a @work is not queued in a hope, that CPU#1 will eventually
+        * finish the queued @work.  Meanwhile CPU#1 does not see
+        * event_indicated is set, because speculative LOAD was executed
+        * before actual STORE.
+        */
+       smp_mb();
 }
 
 static void clear_work_data(struct work_struct *work)
index 03dd576e67730fb2870c44512f55c1c0c39b77f3..59fd7c0b119cbc3e0b61137732f76cc3759fb7c7 100644 (file)
@@ -524,7 +524,9 @@ static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit,
                        free_slot = i;
                        continue;
                }
-               if (ops->compare_object(assoc_array_ptr_to_leaf(ptr), index_key)) {
+               if (assoc_array_ptr_is_leaf(ptr) &&
+                   ops->compare_object(assoc_array_ptr_to_leaf(ptr),
+                                       index_key)) {
                        pr_devel("replace in slot %d\n", i);
                        edit->leaf_p = &node->slots[i];
                        edit->dead_leaf = node->slots[i];
index 4cac81ec225e09af4cfd69c36d63a574a8418110..0be02ad561e9e346c01a65434873f9960472047a 100644 (file)
 #include <linux/sort.h>
 #include <asm/uaccess.h>
 
+#ifndef ARCH_HAS_RELATIVE_EXTABLE
+#define ex_to_insn(x)  ((x)->insn)
+#else
+static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
+{
+       return (unsigned long)&x->insn + x->insn;
+}
+#endif
+
 #ifndef ARCH_HAS_SORT_EXTABLE
+#ifndef ARCH_HAS_RELATIVE_EXTABLE
+#define swap_ex                NULL
+#else
+static void swap_ex(void *a, void *b, int size)
+{
+       struct exception_table_entry *x = a, *y = b, tmp;
+       int delta = b - a;
+
+       tmp = *x;
+       x->insn = y->insn + delta;
+       y->insn = tmp.insn - delta;
+
+#ifdef swap_ex_entry_fixup
+       swap_ex_entry_fixup(x, y, tmp, delta);
+#else
+       x->fixup = y->fixup + delta;
+       y->fixup = tmp.fixup - delta;
+#endif
+}
+#endif /* ARCH_HAS_RELATIVE_EXTABLE */
+
 /*
  * The exception table needs to be sorted so that the binary
  * search that we use to find entries in it works properly.
@@ -26,9 +56,9 @@ static int cmp_ex(const void *a, const void *b)
        const struct exception_table_entry *x = a, *y = b;
 
        /* avoid overflow */
-       if (x->insn > y->insn)
+       if (ex_to_insn(x) > ex_to_insn(y))
                return 1;
-       if (x->insn < y->insn)
+       if (ex_to_insn(x) < ex_to_insn(y))
                return -1;
        return 0;
 }
@@ -37,7 +67,7 @@ void sort_extable(struct exception_table_entry *start,
                  struct exception_table_entry *finish)
 {
        sort(start, finish - start, sizeof(struct exception_table_entry),
-            cmp_ex, NULL);
+            cmp_ex, swap_ex);
 }
 
 #ifdef CONFIG_MODULES
@@ -48,13 +78,15 @@ void sort_extable(struct exception_table_entry *start,
 void trim_init_extable(struct module *m)
 {
        /*trim the beginning*/
-       while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+       while (m->num_exentries &&
+              within_module_init(ex_to_insn(&m->extable[0]), m)) {
                m->extable++;
                m->num_exentries--;
        }
        /*trim the end*/
        while (m->num_exentries &&
-               within_module_init(m->extable[m->num_exentries-1].insn, m))
+              within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]),
+                                 m))
                m->num_exentries--;
 }
 #endif /* CONFIG_MODULES */
@@ -81,13 +113,13 @@ search_extable(const struct exception_table_entry *first,
                 * careful, the distance between value and insn
                 * can be larger than MAX_LONG:
                 */
-               if (mid->insn < value)
+               if (ex_to_insn(mid) < value)
                        first = mid + 1;
-               else if (mid->insn > value)
+               else if (ex_to_insn(mid) > value)
                        last = mid - 1;
                else
                        return mid;
-        }
-        return NULL;
+       }
+       return NULL;
 }
 #endif
index abcecdc2d0f23a8ac9884db5297d7b46dfbcea1b..0710a62ad2f6e135cc1c331a8a82d188a17b53cb 100644 (file)
@@ -11,8 +11,7 @@
 /*
  * Detects 64 bits mode
  */
-#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) \
-       || defined(__ppc64__) || defined(__LP64__))
+#if defined(CONFIG_64BIT)
 #define LZ4_ARCH64 1
 #else
 #define LZ4_ARCH64 0
@@ -35,6 +34,10 @@ typedef struct _U64_S { u64 v; } U64_S;
 
 #define PUT4(s, d) (A32(d) = A32(s))
 #define PUT8(s, d) (A64(d) = A64(s))
+
+#define LZ4_READ_LITTLEENDIAN_16(d, s, p)      \
+       (d = s - A16(p))
+
 #define LZ4_WRITE_LITTLEENDIAN_16(p, v)        \
        do {    \
                A16(p) = v; \
@@ -51,10 +54,13 @@ typedef struct _U64_S { u64 v; } U64_S;
 #define PUT8(s, d) \
        put_unaligned(get_unaligned((const u64 *) s), (u64 *) d)
 
-#define LZ4_WRITE_LITTLEENDIAN_16(p, v)        \
-       do {    \
-               put_unaligned(v, (u16 *)(p)); \
-               p += 2; \
+#define LZ4_READ_LITTLEENDIAN_16(d, s, p)      \
+       (d = s - get_unaligned_le16(p))
+
+#define LZ4_WRITE_LITTLEENDIAN_16(p, v)                        \
+       do {                                            \
+               put_unaligned_le16(v, (u16 *)(p));      \
+               p += 2;                                 \
        } while (0)
 #endif
 
@@ -140,9 +146,6 @@ typedef struct _U64_S { u64 v; } U64_S;
 
 #endif
 
-#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
-       (d = s - get_unaligned_le16(p))
-
 #define LZ4_WILDCOPY(s, d, e)          \
        do {                            \
                LZ4_COPYPACKET(s, d);   \
index 3db76b8c11158f5ce2b3884898e3d2abfbd6d91a..e00ff00e861cea3654dc6483e03a7bf21485b88e 100644 (file)
@@ -128,6 +128,23 @@ leave:
 }
 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
 
+static int count_lzeros(MPI a)
+{
+       mpi_limb_t alimb;
+       int i, lzeros = 0;
+
+       for (i = a->nlimbs - 1; i >= 0; i--) {
+               alimb = a->d[i];
+               if (alimb == 0) {
+                       lzeros += sizeof(mpi_limb_t);
+               } else {
+                       lzeros += count_leading_zeros(alimb) / 8;
+                       break;
+               }
+       }
+       return lzeros;
+}
+
 /**
  * mpi_read_buffer() - read MPI to a bufer provided by user (msb first)
  *
@@ -146,7 +163,7 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
        uint8_t *p;
        mpi_limb_t alimb;
        unsigned int n = mpi_get_size(a);
-       int i, lzeros = 0;
+       int i, lzeros;
 
        if (buf_len < n || !buf || !nbytes)
                return -EINVAL;
@@ -154,14 +171,7 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
        if (sign)
                *sign = a->sign;
 
-       p = (void *)&a->d[a->nlimbs] - 1;
-
-       for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) {
-               if (!*p)
-                       lzeros++;
-               else
-                       break;
-       }
+       lzeros = count_lzeros(a);
 
        p = buf;
        *nbytes = n - lzeros;
@@ -343,7 +353,7 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
        u8 *p, *p2;
        mpi_limb_t alimb, alimb2;
        unsigned int n = mpi_get_size(a);
-       int i, x, y = 0, lzeros = 0, buf_len;
+       int i, x, y = 0, lzeros, buf_len;
 
        if (!nbytes || *nbytes < n)
                return -EINVAL;
@@ -351,14 +361,7 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
        if (sign)
                *sign = a->sign;
 
-       p = (void *)&a->d[a->nlimbs] - 1;
-
-       for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) {
-               if (!*p)
-                       lzeros++;
-               else
-                       break;
-       }
+       lzeros = count_lzeros(a);
 
        *nbytes = n - lzeros;
        buf_len = sgl->length;
index 98866a770770c8bba0acf7bdbacea4699d9f14bf..25b5cbfb7615bd63da19677c877b9e49c3f519e3 100644 (file)
@@ -327,36 +327,67 @@ out:
 }
 
 #define string_get_size_maxbuf 16
-#define test_string_get_size_one(size, blk_size, units, exp_result)            \
+#define test_string_get_size_one(size, blk_size, exp_result10, exp_result2)    \
        do {                                                                   \
-               BUILD_BUG_ON(sizeof(exp_result) >= string_get_size_maxbuf);    \
-               __test_string_get_size((size), (blk_size), (units),            \
-                                      (exp_result));                          \
+               BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf);  \
+               BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf);   \
+               __test_string_get_size((size), (blk_size), (exp_result10),     \
+                                      (exp_result2));                         \
        } while (0)
 
 
-static __init void __test_string_get_size(const u64 size, const u64 blk_size,
-                                         const enum string_size_units units,
-                                         const char *exp_result)
+static __init void test_string_get_size_check(const char *units,
+                                             const char *exp,
+                                             char *res,
+                                             const u64 size,
+                                             const u64 blk_size)
 {
-       char buf[string_get_size_maxbuf];
-
-       string_get_size(size, blk_size, units, buf, sizeof(buf));
-       if (!memcmp(buf, exp_result, strlen(exp_result) + 1))
+       if (!memcmp(res, exp, strlen(exp) + 1))
                return;
 
-       buf[sizeof(buf) - 1] = '\0';
-       pr_warn("Test 'test_string_get_size_one' failed!\n");
-       pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %d\n",
+       res[string_get_size_maxbuf - 1] = '\0';
+
+       pr_warn("Test 'test_string_get_size' failed!\n");
+       pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
                size, blk_size, units);
-       pr_warn("expected: '%s', got '%s'\n", exp_result, buf);
+       pr_warn("expected: '%s', got '%s'\n", exp, res);
+}
+
+static __init void __test_string_get_size(const u64 size, const u64 blk_size,
+                                         const char *exp_result10,
+                                         const char *exp_result2)
+{
+       char buf10[string_get_size_maxbuf];
+       char buf2[string_get_size_maxbuf];
+
+       string_get_size(size, blk_size, STRING_UNITS_10, buf10, sizeof(buf10));
+       string_get_size(size, blk_size, STRING_UNITS_2, buf2, sizeof(buf2));
+
+       test_string_get_size_check("STRING_UNITS_10", exp_result10, buf10,
+                                  size, blk_size);
+
+       test_string_get_size_check("STRING_UNITS_2", exp_result2, buf2,
+                                  size, blk_size);
 }
 
 static __init void test_string_get_size(void)
 {
-       test_string_get_size_one(16384, 512, STRING_UNITS_2, "8.00 MiB");
-       test_string_get_size_one(8192, 4096, STRING_UNITS_10, "32.7 MB");
-       test_string_get_size_one(1, 512, STRING_UNITS_10, "512 B");
+       /* small values */
+       test_string_get_size_one(0, 512, "0 B", "0 B");
+       test_string_get_size_one(1, 512, "512 B", "512 B");
+       test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
+
+       /* normal values */
+       test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
+       test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
+       test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
+
+       /* weird block sizes */
+       test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
+
+       /* huge values */
+       test_string_get_size_one(U64_MAX, 4096, "75.6 ZB", "64.0 ZiB");
+       test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB");
 }
 
 static int __init test_string_helpers_init(void)
index de3e1e71cd9f265d9df971e98ed931fbdc8611a8..7881e072dc33b0b36e5b46dc5d2a9206a2573c7f 100644 (file)
@@ -880,16 +880,8 @@ isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn,
                pfn = isolate_migratepages_block(cc, pfn, block_end_pfn,
                                                        ISOLATE_UNEVICTABLE);
 
-               /*
-                * In case of fatal failure, release everything that might
-                * have been isolated in the previous iteration, and signal
-                * the failure back to caller.
-                */
-               if (!pfn) {
-                       putback_movable_pages(&cc->migratepages);
-                       cc->nr_migratepages = 0;
+               if (!pfn)
                        break;
-               }
 
                if (cc->nr_migratepages == COMPACT_CLUSTER_MAX)
                        break;
index 62fe06bb7d04bacccc8c2213a6a65134fa274010..530e6427f823cd3e3f063eaeced81ebdad32c694 100644 (file)
@@ -2134,10 +2134,9 @@ int khugepaged_enter_vma_merge(struct vm_area_struct *vma,
                 * page fault if needed.
                 */
                return 0;
-       if (vma->vm_ops)
+       if (vma->vm_ops || (vm_flags & VM_NO_THP))
                /* khugepaged not yet working on file or special mappings */
                return 0;
-       VM_BUG_ON_VMA(vm_flags & VM_NO_THP, vma);
        hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
        hend = vma->vm_end & HPAGE_PMD_MASK;
        if (hstart < hend)
@@ -2498,8 +2497,7 @@ static bool hugepage_vma_check(struct vm_area_struct *vma)
                return false;
        if (is_vma_temporary_stack(vma))
                return false;
-       VM_BUG_ON_VMA(vma->vm_flags & VM_NO_THP, vma);
-       return true;
+       return !(vma->vm_flags & VM_NO_THP);
 }
 
 static void collapse_huge_page(struct mm_struct *mm,
index 5c714f33f49477f66f70377e60a8e5930dbcb753..d1f6dc5a715d8349313d54a75dc1017c0543d5f3 100644 (file)
@@ -196,6 +196,7 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg);
 /* "mc" and its members are protected by cgroup_mutex */
 static struct move_charge_struct {
        spinlock_t        lock; /* for from, to */
+       struct mm_struct  *mm;
        struct mem_cgroup *from;
        struct mem_cgroup *to;
        unsigned long flags;
@@ -1332,7 +1333,7 @@ static unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg)
        return limit;
 }
 
-static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
+static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
                                     int order)
 {
        struct oom_control oc = {
@@ -1410,6 +1411,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
        }
 unlock:
        mutex_unlock(&oom_lock);
+       return chosen;
 }
 
 #if MAX_NUMNODES > 1
@@ -4799,6 +4801,8 @@ static void __mem_cgroup_clear_mc(void)
 
 static void mem_cgroup_clear_mc(void)
 {
+       struct mm_struct *mm = mc.mm;
+
        /*
         * we must clear moving_task before waking up waiters at the end of
         * task migration.
@@ -4808,7 +4812,10 @@ static void mem_cgroup_clear_mc(void)
        spin_lock(&mc.lock);
        mc.from = NULL;
        mc.to = NULL;
+       mc.mm = NULL;
        spin_unlock(&mc.lock);
+
+       mmput(mm);
 }
 
 static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
@@ -4865,6 +4872,7 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
                VM_BUG_ON(mc.moved_swap);
 
                spin_lock(&mc.lock);
+               mc.mm = mm;
                mc.from = from;
                mc.to = memcg;
                mc.flags = move_flags;
@@ -4874,8 +4882,9 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
                ret = mem_cgroup_precharge_mc(mm);
                if (ret)
                        mem_cgroup_clear_mc();
+       } else {
+               mmput(mm);
        }
-       mmput(mm);
        return ret;
 }
 
@@ -4989,11 +4998,11 @@ put:                    /* get_mctgt_type() gets the page */
        return ret;
 }
 
-static void mem_cgroup_move_charge(struct mm_struct *mm)
+static void mem_cgroup_move_charge(void)
 {
        struct mm_walk mem_cgroup_move_charge_walk = {
                .pmd_entry = mem_cgroup_move_charge_pte_range,
-               .mm = mm,
+               .mm = mc.mm,
        };
 
        lru_add_drain_all();
@@ -5005,7 +5014,7 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
        atomic_inc(&mc.from->moving_account);
        synchronize_rcu();
 retry:
-       if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
+       if (unlikely(!down_read_trylock(&mc.mm->mmap_sem))) {
                /*
                 * Someone who are holding the mmap_sem might be waiting in
                 * waitq. So we cancel all extra charges, wake up all waiters,
@@ -5022,23 +5031,16 @@ retry:
         * additional charge, the page walk just aborts.
         */
        walk_page_range(0, ~0UL, &mem_cgroup_move_charge_walk);
-       up_read(&mm->mmap_sem);
+       up_read(&mc.mm->mmap_sem);
        atomic_dec(&mc.from->moving_account);
 }
 
-static void mem_cgroup_move_task(struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(void)
 {
-       struct cgroup_subsys_state *css;
-       struct task_struct *p = cgroup_taskset_first(tset, &css);
-       struct mm_struct *mm = get_task_mm(p);
-
-       if (mm) {
-               if (mc.to)
-                       mem_cgroup_move_charge(mm);
-               mmput(mm);
-       }
-       if (mc.to)
+       if (mc.to) {
+               mem_cgroup_move_charge();
                mem_cgroup_clear_mc();
+       }
 }
 #else  /* !CONFIG_MMU */
 static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
@@ -5052,7 +5054,7 @@ static int mem_cgroup_allow_attach(struct cgroup_taskset *tset)
 static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
 {
 }
-static void mem_cgroup_move_task(struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(void)
 {
 }
 #endif
@@ -5130,6 +5132,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
                                 char *buf, size_t nbytes, loff_t off)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+       unsigned long nr_pages;
        unsigned long high;
        int err;
 
@@ -5140,6 +5143,11 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
 
        memcg->high = high;
 
+       nr_pages = page_counter_read(&memcg->memory);
+       if (nr_pages > high)
+               try_to_free_mem_cgroup_pages(memcg, nr_pages - high,
+                                            GFP_KERNEL, true);
+
        memcg_wb_domain_size_changed(memcg);
        return nbytes;
 }
@@ -5161,6 +5169,8 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
                                char *buf, size_t nbytes, loff_t off)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+       unsigned int nr_reclaims = MEM_CGROUP_RECLAIM_RETRIES;
+       bool drained = false;
        unsigned long max;
        int err;
 
@@ -5169,9 +5179,36 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
        if (err)
                return err;
 
-       err = mem_cgroup_resize_limit(memcg, max);
-       if (err)
-               return err;
+       xchg(&memcg->memory.limit, max);
+
+       for (;;) {
+               unsigned long nr_pages = page_counter_read(&memcg->memory);
+
+               if (nr_pages <= max)
+                       break;
+
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+
+               if (!drained) {
+                       drain_all_stock(memcg);
+                       drained = true;
+                       continue;
+               }
+
+               if (nr_reclaims) {
+                       if (!try_to_free_mem_cgroup_pages(memcg, nr_pages - max,
+                                                         GFP_KERNEL, true))
+                               nr_reclaims--;
+                       continue;
+               }
+
+               mem_cgroup_events(memcg, MEMCG_OOM, 1);
+               if (!mem_cgroup_out_of_memory(memcg, GFP_KERNEL, 0))
+                       break;
+       }
 
        memcg_wb_domain_size_changed(memcg);
        return nbytes;
@@ -5233,6 +5270,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
        .cancel_attach = mem_cgroup_cancel_attach,
        .attach = mem_cgroup_move_task,
        .allow_attach = mem_cgroup_allow_attach,
+       .post_attach = mem_cgroup_move_task,
        .bind = mem_cgroup_bind,
        .dfl_cftypes = memory_files,
        .legacy_cftypes = mem_cgroup_legacy_files,
index b80bf4746b67ac0de41505165ef9c147e93e44ef..76dcee3177146f0fa8820c5585f8674271b6f12c 100644 (file)
@@ -797,6 +797,46 @@ out:
        return pfn_to_page(pfn);
 }
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
+                               pmd_t pmd)
+{
+       unsigned long pfn = pmd_pfn(pmd);
+
+       /*
+        * There is no pmd_special() but there may be special pmds, e.g.
+        * in a direct-access (dax) mapping, so let's just replicate the
+        * !HAVE_PTE_SPECIAL case from vm_normal_page() here.
+        */
+       if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) {
+               if (vma->vm_flags & VM_MIXEDMAP) {
+                       if (!pfn_valid(pfn))
+                               return NULL;
+                       goto out;
+               } else {
+                       unsigned long off;
+                       off = (addr - vma->vm_start) >> PAGE_SHIFT;
+                       if (pfn == vma->vm_pgoff + off)
+                               return NULL;
+                       if (!is_cow_mapping(vma->vm_flags))
+                               return NULL;
+               }
+       }
+
+       if (is_zero_pfn(pfn))
+               return NULL;
+       if (unlikely(pfn > highest_memmap_pfn))
+               return NULL;
+
+       /*
+        * NOTE! We still have PageReserved() pages in the page tables.
+        * eg. VDSO mappings can cause them to exist.
+        */
+out:
+       return pfn_to_page(pfn);
+}
+#endif
+
 /*
  * copy one vm_area from one task to the other. Assumes the page tables
  * already present in the new task to be cleared in the whole range
index 6d17e0ab42d40f3253df41bbecc1e0d85acb204b..bbeb0b71fcf41b99a0173ba8dbb5990190fb59ce 100644 (file)
@@ -963,7 +963,13 @@ out:
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
                /* Soft-offlined page shouldn't go through lru cache list */
-               if (reason == MR_MEMORY_FAILURE) {
+               if (reason == MR_MEMORY_FAILURE && rc == MIGRATEPAGE_SUCCESS) {
+                       /*
+                        * With this release, we free successfully migrated
+                        * page and set PG_HWPoison on just freed page
+                        * intentionally. Although it's rather weird, it's how
+                        * HWPoison flag works at the moment.
+                        */
                        put_page(page);
                        if (!test_set_page_hwpoison(page))
                                num_poisoned_pages_inc();
index 6c561acdca92730aaabd50926fd01b7fd9345fb3..a089cca8d79aae15a561c8dba77d45b0c39f95dc 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2634,6 +2634,7 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
 
        return 0;
 }
+EXPORT_SYMBOL(do_munmap);
 
 int vm_munmap(unsigned long start, size_t len)
 {
index d15d88c8efa1e25bf76fe3bf07f6eeb08fd14fd5..e40c9364582dbbb18a3e977030b63ad8cca6ec2b 100644 (file)
@@ -1899,7 +1899,8 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb)
        if (gdtc->dirty > gdtc->bg_thresh)
                return true;
 
-       if (wb_stat(wb, WB_RECLAIMABLE) > __wb_calc_thresh(gdtc))
+       if (wb_stat(wb, WB_RECLAIMABLE) >
+           wb_calc_thresh(gdtc->wb, gdtc->bg_thresh))
                return true;
 
        if (mdtc) {
@@ -1913,7 +1914,8 @@ bool wb_over_bg_thresh(struct bdi_writeback *wb)
                if (mdtc->dirty > mdtc->bg_thresh)
                        return true;
 
-               if (wb_stat(wb, WB_RECLAIMABLE) > __wb_calc_thresh(mdtc))
+               if (wb_stat(wb, WB_RECLAIMABLE) >
+                   wb_calc_thresh(mdtc->wb, mdtc->bg_thresh))
                        return true;
        }
 
index 89ef8347900c93505576b338ea3c2dd0ebf2b98b..755f29fac22f917d56f175efb8ac7021006e9722 100644 (file)
@@ -674,34 +674,28 @@ static inline void __free_one_page(struct page *page,
        unsigned long combined_idx;
        unsigned long uninitialized_var(buddy_idx);
        struct page *buddy;
-       unsigned int max_order = MAX_ORDER;
+       unsigned int max_order;
+
+       max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
 
        VM_BUG_ON(!zone_is_initialized(zone));
        VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page);
 
        VM_BUG_ON(migratetype == -1);
-       if (is_migrate_isolate(migratetype)) {
-               /*
-                * We restrict max order of merging to prevent merge
-                * between freepages on isolate pageblock and normal
-                * pageblock. Without this, pageblock isolation
-                * could cause incorrect freepage accounting.
-                */
-               max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
-       } else {
+       if (likely(!is_migrate_isolate(migratetype)))
                __mod_zone_freepage_state(zone, 1 << order, migratetype);
-       }
 
-       page_idx = pfn & ((1 << max_order) - 1);
+       page_idx = pfn & ((1 << MAX_ORDER) - 1);
 
        VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page);
        VM_BUG_ON_PAGE(bad_range(zone, page), page);
 
+continue_merging:
        while (order < max_order - 1) {
                buddy_idx = __find_buddy_index(page_idx, order);
                buddy = page + (buddy_idx - page_idx);
                if (!page_is_buddy(page, buddy, order))
-                       break;
+                       goto done_merging;
                /*
                 * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
                 * merge with it and move up one order.
@@ -718,6 +712,32 @@ static inline void __free_one_page(struct page *page,
                page_idx = combined_idx;
                order++;
        }
+       if (max_order < MAX_ORDER) {
+               /* If we are here, it means order is >= pageblock_order.
+                * We want to prevent merge between freepages on isolate
+                * pageblock and normal pageblock. Without this, pageblock
+                * isolation could cause incorrect freepage or CMA accounting.
+                *
+                * We don't want to hit this code for the more frequent
+                * low-order merging.
+                */
+               if (unlikely(has_isolate_pageblock(zone))) {
+                       int buddy_mt;
+
+                       buddy_idx = __find_buddy_index(page_idx, order);
+                       buddy = page + (buddy_idx - page_idx);
+                       buddy_mt = get_pageblock_migratetype(buddy);
+
+                       if (migratetype != buddy_mt
+                                       && (is_migrate_isolate(migratetype) ||
+                                               is_migrate_isolate(buddy_mt)))
+                               goto done_merging;
+               }
+               max_order++;
+               goto continue_merging;
+       }
+
+done_merging:
        set_page_order(page, order);
 
        /*
@@ -6191,7 +6211,7 @@ int __meminit init_per_zone_wmark_min(void)
        setup_per_zone_inactive_ratio();
        return 0;
 }
-module_init(init_per_zone_wmark_min)
+core_initcall(init_per_zone_wmark_min)
 
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
index 4568fd58f70a02c472e525528db58eeb20c06ebf..00c96462cc36cddb28f680f26cc7aeb4f6b2b04a 100644 (file)
@@ -283,11 +283,11 @@ struct page *alloc_migrate_target(struct page *page, unsigned long private,
         * now as a simple work-around, we use the next node for destination.
         */
        if (PageHuge(page)) {
-               nodemask_t src = nodemask_of_node(page_to_nid(page));
-               nodemask_t dst;
-               nodes_complement(dst, src);
+               int node = next_online_node(page_to_nid(page));
+               if (node == MAX_NUMNODES)
+                       node = first_online_node;
                return alloc_huge_page_node(page_hstate(compound_head(page)),
-                                           next_node(page_to_nid(page), dst));
+                                           node);
        }
 
        if (PageHighMem(page))
index 46997517406ede0e987388763c9fa1d07875c1db..65d5f92d51d27ec1e0993cbe194eaaaae9bcd503 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2819,6 +2819,7 @@ struct detached_freelist {
        void *tail;
        void *freelist;
        int cnt;
+       struct kmem_cache *s;
 };
 
 /*
@@ -2833,8 +2834,9 @@ struct detached_freelist {
  * synchronization primitive.  Look ahead in the array is limited due
  * to performance reasons.
  */
-static int build_detached_freelist(struct kmem_cache *s, size_t size,
-                                  void **p, struct detached_freelist *df)
+static inline
+int build_detached_freelist(struct kmem_cache *s, size_t size,
+                           void **p, struct detached_freelist *df)
 {
        size_t first_skipped_index = 0;
        int lookahead = 3;
@@ -2850,8 +2852,11 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
        if (!object)
                return 0;
 
+       /* Support for memcg, compiler can optimize this out */
+       df->s = cache_from_obj(s, object);
+
        /* Start new detached freelist */
-       set_freepointer(s, object, NULL);
+       set_freepointer(df->s, object, NULL);
        df->page = virt_to_head_page(object);
        df->tail = object;
        df->freelist = object;
@@ -2866,7 +2871,7 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
                /* df->page is always set at this point */
                if (df->page == virt_to_head_page(object)) {
                        /* Opportunity build freelist */
-                       set_freepointer(s, object, df->freelist);
+                       set_freepointer(df->s, object, df->freelist);
                        df->freelist = object;
                        df->cnt++;
                        p[size] = NULL; /* mark object processed */
@@ -2885,25 +2890,20 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
        return first_skipped_index;
 }
 
-
 /* Note that interrupts must be enabled when calling this function. */
-void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p)
+void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
 {
        if (WARN_ON(!size))
                return;
 
        do {
                struct detached_freelist df;
-               struct kmem_cache *s;
-
-               /* Support for memcg */
-               s = cache_from_obj(orig_s, p[size - 1]);
 
                size = build_detached_freelist(s, size, p, &df);
                if (unlikely(!df.page))
                        continue;
 
-               slab_free(s, df.page, df.freelist, df.tail, df.cnt, _RET_IP_);
+               slab_free(df.s, df.page, df.freelist, df.tail, df.cnt,_RET_IP_);
        } while (likely(size));
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
index 0c56f6a812bcd9d375aa74cf4b59b7d2b6176e91..2e6547ec1b09df26585800bebdab95ecc40245ef 100644 (file)
@@ -2577,7 +2577,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                sc->gfp_mask |= __GFP_HIGHMEM;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
-                                       requested_highidx, sc->nodemask) {
+                                       gfp_zone(sc->gfp_mask), sc->nodemask) {
                enum zone_type classzone_idx;
 
                if (!populated_zone(zone))
index bf14508afd64573d8310a5a3e12b99b629fc8c02..340261946fda6a18845c1c9fae378ade8c2abb61 100644 (file)
@@ -170,6 +170,8 @@ static struct zswap_tree *zswap_trees[MAX_SWAPFILES];
 static LIST_HEAD(zswap_pools);
 /* protects zswap_pools list modification */
 static DEFINE_SPINLOCK(zswap_pools_lock);
+/* pool counter to provide unique names to zpool */
+static atomic_t zswap_pools_count = ATOMIC_INIT(0);
 
 /* used by param callback function */
 static bool zswap_init_started;
@@ -565,6 +567,7 @@ static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor)
 static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
 {
        struct zswap_pool *pool;
+       char name[38]; /* 'zswap' + 32 char (max) num + \0 */
        gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM;
 
        pool = kzalloc(sizeof(*pool), GFP_KERNEL);
@@ -573,7 +576,10 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
                return NULL;
        }
 
-       pool->zpool = zpool_create_pool(type, "zswap", gfp, &zswap_zpool_ops);
+       /* unique name for each pool specifically required by zsmalloc */
+       snprintf(name, 38, "zswap%x", atomic_inc_return(&zswap_pools_count));
+
+       pool->zpool = zpool_create_pool(type, name, gfp, &zswap_zpool_ops);
        if (!pool->zpool) {
                pr_err("%s zpool not available\n", type);
                goto error;
index b563a3f5f2a8a33932418965920ed58b80511f88..2fa3be96510161190365ff59b48ec8a293037853 100644 (file)
@@ -228,8 +228,23 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
 }
 #endif
 
+static bool ax25_validate_header(const char *header, unsigned int len)
+{
+       ax25_digi digi;
+
+       if (!len)
+               return false;
+
+       if (header[0])
+               return true;
+
+       return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
+                              NULL);
+}
+
 const struct header_ops ax25_header_ops = {
        .create = ax25_hard_header,
+       .validate = ax25_validate_header,
 };
 
 EXPORT_SYMBOL(ax25_header_ops);
index a49c705fb86b861f5595c8c0cfb7b8b1e1010589..5f19133c5530f57e5f3ceeed6b3ec8d3a5cc11be 100644 (file)
@@ -553,6 +553,7 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
  * be sent to
  * @bat_priv: the bat priv with all the soft interface information
  * @ip_dst: ipv4 to look up in the DHT
+ * @vid: VLAN identifier
  *
  * An originator O is selected if and only if its DHT_ID value is one of three
  * closest values (from the LEFT, with wrap around if needed) then the hash
@@ -561,7 +562,8 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
  * Returns the candidate array of size BATADV_DAT_CANDIDATE_NUM.
  */
 static struct batadv_dat_candidate *
-batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
+batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
+                            unsigned short vid)
 {
        int select;
        batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;
@@ -577,7 +579,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
                return NULL;
 
        dat.ip = ip_dst;
-       dat.vid = 0;
+       dat.vid = vid;
        ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat,
                                                    BATADV_DAT_ADDR_MAX);
 
@@ -597,6 +599,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: payload to send
  * @ip: the DHT key
+ * @vid: VLAN identifier
  * @packet_subtype: unicast4addr packet subtype to use
  *
  * This function copies the skb with pskb_copy() and is sent as unicast packet
@@ -607,7 +610,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
  */
 static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
                                 struct sk_buff *skb, __be32 ip,
-                                int packet_subtype)
+                                unsigned short vid, int packet_subtype)
 {
        int i;
        bool ret = false;
@@ -616,7 +619,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
        struct sk_buff *tmp_skb;
        struct batadv_dat_candidate *cand;
 
-       cand = batadv_dat_select_candidates(bat_priv, ip);
+       cand = batadv_dat_select_candidates(bat_priv, ip, vid);
        if (!cand)
                goto out;
 
@@ -1004,7 +1007,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
                ret = true;
        } else {
                /* Send the request to the DHT */
-               ret = batadv_dat_send_data(bat_priv, skb, ip_dst,
+               ret = batadv_dat_send_data(bat_priv, skb, ip_dst, vid,
                                           BATADV_P_DAT_DHT_GET);
        }
 out:
@@ -1132,8 +1135,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
        /* Send the ARP reply to the candidates for both the IP addresses that
         * the node obtained from the ARP reply
         */
-       batadv_dat_send_data(bat_priv, skb, ip_src, BATADV_P_DAT_DHT_PUT);
-       batadv_dat_send_data(bat_priv, skb, ip_dst, BATADV_P_DAT_DHT_PUT);
+       batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT);
+       batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT);
 }
 
 /**
index 3207667e69de30e92499c705f39319c55f36732f..d8a2f33e60e552dcd6a33aa385f03e3bbfa5e278 100644 (file)
@@ -104,6 +104,15 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
                neigh_node = NULL;
 
        spin_lock_bh(&orig_node->neigh_list_lock);
+       /* curr_router used earlier may not be the current orig_ifinfo->router
+        * anymore because it was dereferenced outside of the neigh_list_lock
+        * protected region. After the new best neighbor has replace the current
+        * best neighbor the reference counter needs to decrease. Consequently,
+        * the code needs to ensure the curr_router variable contains a pointer
+        * to the replaced best neighbor.
+        */
+       curr_router = rcu_dereference_protected(orig_ifinfo->router, true);
+
        rcu_assign_pointer(orig_ifinfo->router, neigh_node);
        spin_unlock_bh(&orig_node->neigh_list_lock);
        batadv_orig_ifinfo_free_ref(orig_ifinfo);
index f664324805eba5d93cc02b4436429dbf44b7b03d..0e0c3b8ed927fb8fe39ba4d106ba14fa3b3941e9 100644 (file)
@@ -630,6 +630,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
 
                if (pending) {
                        hlist_del(&forw_packet->list);
+                       if (!forw_packet->own)
+                               atomic_inc(&bat_priv->bcast_queue_left);
+
                        batadv_forw_packet_free(forw_packet);
                }
        }
@@ -657,6 +660,9 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
 
                if (pending) {
                        hlist_del(&forw_packet->list);
+                       if (!forw_packet->own)
+                               atomic_inc(&bat_priv->batman_queue_left);
+
                        batadv_forw_packet_free(forw_packet);
                }
        }
index ac4d08de5df46abc5c7986b29eb89627fe160fc3..720f1a5b81ac0694d624a1a74f553c71d1bb0121 100644 (file)
@@ -407,11 +407,17 @@ void batadv_interface_rx(struct net_device *soft_iface,
         */
        nf_reset(skb);
 
+       if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
+               goto dropped;
+
        vid = batadv_get_vid(skb, 0);
        ethhdr = eth_hdr(skb);
 
        switch (ntohs(ethhdr->h_proto)) {
        case ETH_P_8021Q:
+               if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
+                       goto dropped;
+
                vhdr = (struct vlan_ethhdr *)skb->data;
 
                if (vhdr->h_vlan_encapsulated_proto != ethertype)
@@ -423,8 +429,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
        }
 
        /* skb->dev & skb->pkt_type are set here */
-       if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
-               goto dropped;
        skb->protocol = eth_type_trans(skb, soft_iface);
 
        /* should not be necessary anymore as we use skb_pull_rcsum()
index 7f22119276f391067b424da490e1c667d7a6272b..b1b0a1c0bd8d3faf75a6ff5de00931b163fcac66 100644 (file)
@@ -7155,6 +7155,10 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                       status);
 
+       if (data_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len)
+               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
+                                      MGMT_STATUS_INVALID_PARAMS);
+
        flags = __le32_to_cpu(cp->flags);
        timeout = __le16_to_cpu(cp->timeout);
        duration = __le16_to_cpu(cp->duration);
index 5f3f6455317924e0e74281d23075d2af68d72d73..eff69cb270d229746b64b6373c276faf40596a11 100644 (file)
@@ -567,6 +567,14 @@ int br_set_max_age(struct net_bridge *br, unsigned long val)
 
 }
 
+/* Set time interval that dynamic forwarding entries live
+ * For pure software bridge, allow values outside the 802.1
+ * standard specification for special cases:
+ *  0 - entry never ages (all permanant)
+ *  1 - entry disappears (no persistance)
+ *
+ * Offloaded switch entries maybe more restrictive
+ */
 int br_set_ageing_time(struct net_bridge *br, u32 ageing_time)
 {
        struct switchdev_attr attr = {
@@ -577,11 +585,8 @@ int br_set_ageing_time(struct net_bridge *br, u32 ageing_time)
        unsigned long t = clock_t_to_jiffies(ageing_time);
        int err;
 
-       if (t < BR_MIN_AGEING_TIME || t > BR_MAX_AGEING_TIME)
-               return -ERANGE;
-
        err = switchdev_port_attr_set(br->dev, &attr);
-       if (err)
+       if (err && err != -EOPNOTSUPP)
                return err;
 
        br->ageing_time = t;
index 37157c4c1a78de437ee753a889cbdf2ebb160323..f393a22b9d5049b3161812105474bd93d72db965 100644 (file)
@@ -1139,7 +1139,8 @@ void bpf_prog_destroy(struct bpf_prog *fp)
 }
 EXPORT_SYMBOL_GPL(bpf_prog_destroy);
 
-static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
+static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk,
+                           bool locked)
 {
        struct sk_filter *fp, *old_fp;
 
@@ -1155,10 +1156,8 @@ static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
                return -ENOMEM;
        }
 
-       old_fp = rcu_dereference_protected(sk->sk_filter,
-                                          sock_owned_by_user(sk));
+       old_fp = rcu_dereference_protected(sk->sk_filter, locked);
        rcu_assign_pointer(sk->sk_filter, fp);
-
        if (old_fp)
                sk_filter_uncharge(sk, old_fp);
 
@@ -1175,7 +1174,8 @@ static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk)
  * occurs or there is insufficient memory for the filter a negative
  * errno code is returned. On success the return is zero.
  */
-int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
+int __sk_attach_filter(struct sock_fprog *fprog, struct sock *sk,
+                      bool locked)
 {
        unsigned int fsize = bpf_classic_proglen(fprog);
        unsigned int bpf_fsize = bpf_prog_size(fprog->len);
@@ -1213,7 +1213,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        if (IS_ERR(prog))
                return PTR_ERR(prog);
 
-       err = __sk_attach_prog(prog, sk);
+       err = __sk_attach_prog(prog, sk, locked);
        if (err < 0) {
                __bpf_prog_release(prog);
                return err;
@@ -1221,7 +1221,12 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(sk_attach_filter);
+EXPORT_SYMBOL_GPL(__sk_attach_filter);
+
+int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
+{
+       return __sk_attach_filter(fprog, sk, sock_owned_by_user(sk));
+}
 
 int sk_attach_bpf(u32 ufd, struct sock *sk)
 {
@@ -1240,7 +1245,7 @@ int sk_attach_bpf(u32 ufd, struct sock *sk)
                return -EINVAL;
        }
 
-       err = __sk_attach_prog(prog, sk);
+       err = __sk_attach_prog(prog, sk, sock_owned_by_user(sk));
        if (err < 0) {
                bpf_prog_put(prog);
                return err;
@@ -1913,7 +1918,7 @@ static int __init register_sk_filter_ops(void)
 }
 late_initcall(register_sk_filter_ops);
 
-int sk_detach_filter(struct sock *sk)
+int __sk_detach_filter(struct sock *sk, bool locked)
 {
        int ret = -ENOENT;
        struct sk_filter *filter;
@@ -1921,8 +1926,7 @@ int sk_detach_filter(struct sock *sk)
        if (sock_flag(sk, SOCK_FILTER_LOCKED))
                return -EPERM;
 
-       filter = rcu_dereference_protected(sk->sk_filter,
-                                          sock_owned_by_user(sk));
+       filter = rcu_dereference_protected(sk->sk_filter, locked);
        if (filter) {
                RCU_INIT_POINTER(sk->sk_filter, NULL);
                sk_filter_uncharge(sk, filter);
@@ -1931,7 +1935,12 @@ int sk_detach_filter(struct sock *sk)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(sk_detach_filter);
+EXPORT_SYMBOL_GPL(__sk_detach_filter);
+
+int sk_detach_filter(struct sock *sk)
+{
+       return __sk_detach_filter(sk, sock_owned_by_user(sk));
+}
 
 int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,
                  unsigned int len)
index 34ba7a08876de74409ea5d2ad3af6f78124ff0a7..ca966f7de351953b75f3551723fc0c36ac465bb8 100644 (file)
@@ -905,6 +905,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
               + rtnl_link_get_af_size(dev, ext_filter_mask) /* IFLA_AF_SPEC */
               + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_PORT_ID */
               + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_SWITCH_ID */
+              + nla_total_size(IFNAMSIZ) /* IFLA_PHYS_PORT_NAME */
               + nla_total_size(1); /* IFLA_PROTO_DOWN */
 
 }
index 5bf88f58bee7405ff65f80487a64339b92a91bcb..8616d1147c938808da752734b6cecea260b149b9 100644 (file)
@@ -2947,6 +2947,24 @@ int skb_append_pagefrags(struct sk_buff *skb, struct page *page,
 }
 EXPORT_SYMBOL_GPL(skb_append_pagefrags);
 
+/**
+ *     skb_push_rcsum - push skb and update receive checksum
+ *     @skb: buffer to update
+ *     @len: length of data pulled
+ *
+ *     This function performs an skb_push on the packet and updates
+ *     the CHECKSUM_COMPLETE checksum.  It should be used on
+ *     receive path processing instead of skb_push unless you know
+ *     that the checksum difference is zero (e.g., a valid IP header)
+ *     or you are setting ip_summed to CHECKSUM_NONE.
+ */
+static unsigned char *skb_push_rcsum(struct sk_buff *skb, unsigned len)
+{
+       skb_push(skb, len);
+       skb_postpush_rcsum(skb, skb->data, len);
+       return skb->data;
+}
+
 /**
  *     skb_pull_rcsum - pull skb and update receive checksum
  *     @skb: buffer to update
@@ -4084,9 +4102,9 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
        if (!pskb_may_pull(skb_chk, offset))
                goto err;
 
-       __skb_pull(skb_chk, offset);
+       skb_pull_rcsum(skb_chk, offset);
        ret = skb_chkf(skb_chk);
-       __skb_push(skb_chk, offset);
+       skb_push_rcsum(skb_chk, offset);
 
        if (ret)
                goto err;
index 902d606324a04ff81adbdc301a1ed58baa3f61f9..8be8f27bfaccdddf0dd1949d0dfd59ee63ad8ebc 100644 (file)
@@ -204,8 +204,6 @@ void dccp_req_err(struct sock *sk, u64 seq)
         * ICMPs are not backlogged, hence we cannot get an established
         * socket here.
         */
-       WARN_ON(req->sk);
-
        if (!between48(seq, dccp_rsk(req)->dreq_iss, dccp_rsk(req)->dreq_gss)) {
                NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
        } else {
index 011e73357ba5467495a98aacba9e491654f34a30..926169c94a0b616ec1236d5f4056b3c681e731d0 100644 (file)
@@ -335,6 +335,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 
        ASSERT_RTNL();
 
+       if (in_dev->dead)
+               goto no_promotions;
+
        /* 1. Deleting primary ifaddr forces deletion all secondaries
         * unless alias promotion is set
         **/
@@ -381,6 +384,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
                        fib_del_ifaddr(ifa, ifa1);
        }
 
+no_promotions:
        /* 2. Unlink it */
 
        *ifap = ifa1->ifa_next;
index e10edb5e78b05d8f894aeccc7e5b9799454ecc0a..f97ae9d93ee9c302245dc9a01a1c0bdff24269f7 100644 (file)
@@ -280,7 +280,6 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
        struct in_device *in_dev;
        struct fib_result res;
        struct rtable *rt;
-       struct flowi4 fl4;
        struct net *net;
        int scope;
 
@@ -296,14 +295,13 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
 
        scope = RT_SCOPE_UNIVERSE;
        if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
-               fl4.flowi4_oif = 0;
-               fl4.flowi4_iif = LOOPBACK_IFINDEX;
-               fl4.daddr = ip_hdr(skb)->saddr;
-               fl4.saddr = 0;
-               fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
-               fl4.flowi4_scope = scope;
-               fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0;
-               fl4.flowi4_tun_key.tun_id = 0;
+               struct flowi4 fl4 = {
+                       .flowi4_iif = LOOPBACK_IFINDEX,
+                       .daddr = ip_hdr(skb)->saddr,
+                       .flowi4_tos = RT_TOS(ip_hdr(skb)->tos),
+                       .flowi4_scope = scope,
+                       .flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0,
+               };
                if (!fib_lookup(net, &fl4, &res, 0))
                        return FIB_RES_PREFSRC(net, res);
        } else {
@@ -923,6 +921,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
                subnet = 1;
        }
 
+       if (in_dev->dead)
+               goto no_promotions;
+
        /* Deletion is more complicated than add.
         * We should take care of not to delete too much :-)
         *
@@ -998,6 +999,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
                }
        }
 
+no_promotions:
        if (!(ok & BRD_OK))
                fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
        if (subnet && ifa->ifa_prefixlen < 31) {
index 05e4cba14162f3583ec588657af7e8b68546b111..b3086cf2702759d1077cb6a014afbd130d8206db 100644 (file)
@@ -356,9 +356,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
        skb_dst_set(skb, &rt->dst);
        skb->dev = dev;
 
-       skb->reserved_tailroom = skb_end_offset(skb) -
-                                min(mtu, skb_end_offset(skb));
        skb_reserve(skb, hlen);
+       skb_tailroom_reserve(skb, mtu, tlen);
 
        skb_reset_network_header(skb);
        pip = ip_hdr(skb);
index e73b4f8b20964780e2303b53c4a24dc2ba562e50..dbf7f7ee2958a0b2bb01d83eddab0cf919012074 100644 (file)
@@ -1237,13 +1237,16 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
        if (!skb)
                return -EINVAL;
 
-       cork->length += size;
        if ((size + skb->len > mtu) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO)) {
+               if (skb->ip_summed != CHECKSUM_PARTIAL)
+                       return -EOPNOTSUPP;
+
                skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
        }
+       cork->length += size;
 
        while (size > 0) {
                if (skb_is_gso(skb)) {
index cbb51f3fac06c66e76204957b3243f50a58384b4..ce30c8b72457fd425438ca675ff42cdd67e17505 100644 (file)
@@ -663,6 +663,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
        connected = (tunnel->parms.iph.daddr != 0);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        dst = tnl_params->daddr;
        if (dst == 0) {
                /* NBMA tunnel */
@@ -760,7 +762,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                                tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
 
-                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                        dst_link_failure(skb);
                } else
                        tunnel->err_count = 0;
index c6eb42100e9a7d78a6a5c27434e42e3282b3af74..ea91058b5f6f4245a84179f81a8641756f60efff 100644 (file)
@@ -108,10 +108,18 @@ static int masq_inet_event(struct notifier_block *this,
                           unsigned long event,
                           void *ptr)
 {
-       struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+       struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev;
        struct netdev_notifier_info info;
 
-       netdev_notifier_info_init(&info, dev);
+       /* The masq_dev_notifier will catch the case of the device going
+        * down.  So if the inetdev is dead and being destroyed we have
+        * no work to do.  Otherwise this is an individual address removal
+        * and we have to perform the flush.
+        */
+       if (idev->dead)
+               return NOTIFY_DONE;
+
+       netdev_notifier_info_init(&info, idev->dev);
        return masq_device_event(this, event, &info);
 }
 
index c478092172f2df4db4140d01c86ad1fc88a328df..7decaa4393605749796bcf96e4fc3e102182f1d5 100644 (file)
@@ -320,8 +320,6 @@ void tcp_req_err(struct sock *sk, u32 seq, bool abort)
        /* ICMPs are not backlogged, hence we cannot get
         * an established socket here.
         */
-       WARN_ON(req->sk);
-
        if (seq != tcp_rsk(req)->snt_isn) {
                NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
        } else if (abort) {
index c8cbc2b4b7921fb4f70681e4ac6d945f5499654c..a726d7853ce53fe03b48b199ca909c02393cabcf 100644 (file)
@@ -550,7 +550,7 @@ reset:
         */
        if (crtt > tp->srtt_us) {
                /* Set RTO like tcp_rtt_estimator(), but from cached RTT. */
-               crtt /= 8 * USEC_PER_MSEC;
+               crtt /= 8 * USEC_PER_SEC / HZ;
                inet_csk(sk)->icsk_rto = crtt + max(2 * crtt, tcp_rto_min(sk));
        } else if (tp->srtt_us == 0) {
                /* RFC6298: 5.7 We've failed to get a valid RTT sample from
index ac6b1961ffeb32a40b662300aebee4ba182ce31a..9475a2748a9a269b29cd026318d78a4fb03e42e5 100644 (file)
@@ -458,7 +458,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
 
                newtp->rcv_wup = newtp->copied_seq =
                newtp->rcv_nxt = treq->rcv_isn + 1;
-               newtp->segs_in = 0;
+               newtp->segs_in = 1;
 
                newtp->snd_sml = newtp->snd_una =
                newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1;
@@ -818,6 +818,7 @@ int tcp_child_process(struct sock *parent, struct sock *child,
        int ret = 0;
        int state = child->sk_state;
 
+       tcp_sk(child)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs);
        if (!sock_owned_by_user(child)) {
                ret = tcp_rcv_state_process(child, skb);
                /* Wakeup parent, send SIGIO */
index d9f5bbb4fa9be73d53a57d45a371fd8830a0c61c..2ef43a102951c3ab4af81662b0f553122197693e 100644 (file)
@@ -1991,10 +1991,14 @@ void udp_v4_early_demux(struct sk_buff *skb)
                if (!in_dev)
                        return;
 
-               ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
-                                      iph->protocol);
-               if (!ours)
-                       return;
+               /* we are supposed to accept bcast packets */
+               if (skb->pkt_type == PACKET_MULTICAST) {
+                       ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
+                                              iph->protocol);
+                       if (!ours)
+                               return;
+               }
+
                sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr,
                                                   uh->source, iph->saddr, dif);
        } else if (skb->pkt_type == PACKET_HOST) {
index aba428626b5290ddf68c8b350b8b2879119d136b..280a9bdeddeeaad5dcbf3181e02cae946403e44d 100644 (file)
@@ -89,6 +89,8 @@ int udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
        uh->source = src_port;
        uh->len = htons(skb->len);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        udp_set_csum(nocheck, skb, src, dst, skb->len);
 
        return iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP,
index 835ec57c233b64dcb8a789975d52cb8f0c749d66..840a4388f860dc713431be32f3193332533024f2 100644 (file)
@@ -260,7 +260,11 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                                                return -EINVAL;
                                        }
                                }
-                               return -ENOENT;
+                               if (!found)
+                                       return -ENOENT;
+                               if (fragoff)
+                                       *fragoff = _frag_off;
+                               break;
                        }
                        hdrlen = 8;
                } else if (nexthdr == NEXTHDR_AUTH) {
index e5ea177d34c6492713d5271032394a69874a300c..4650c6824783ea29f687780aa61669a82e889858 100644 (file)
@@ -778,6 +778,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
        __u32 mtu;
        int err;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
index 31144c486c521d98fca1e9099eb9801ae3e31854..a175152d3e46e822237fd6012fb6ef0379dc2f14 100644 (file)
@@ -1091,8 +1091,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                        int getfrag(void *from, char *to, int offset, int len,
                        int odd, struct sk_buff *skb),
                        void *from, int length, int hh_len, int fragheaderlen,
-                       int transhdrlen, int mtu, unsigned int flags,
-                       const struct flowi6 *fl6)
+                       int exthdrlen, int transhdrlen, int mtu,
+                       unsigned int flags, const struct flowi6 *fl6)
 
 {
        struct sk_buff *skb;
@@ -1117,7 +1117,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb_put(skb, fragheaderlen + transhdrlen);
 
                /* initialize network header pointer */
-               skb_reset_network_header(skb);
+               skb_set_network_header(skb, exthdrlen);
 
                /* initialize protocol header pointer */
                skb->transport_header = skb->network_header + fragheaderlen;
@@ -1359,7 +1359,7 @@ emsgsize:
            (rt->dst.dev->features & NETIF_F_UFO) &&
            (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
                err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
-                                         hh_len, fragheaderlen,
+                                         hh_len, fragheaderlen, exthdrlen,
                                          transhdrlen, mtu, flags, fl6);
                if (err)
                        goto error;
index 137fca42aaa6bb809d46e7809b240d8810d89a04..3991b21e24ad359e64c415e4108c485cf31a49cc 100644 (file)
@@ -343,12 +343,12 @@ static int ip6_tnl_create2(struct net_device *dev)
 
        t = netdev_priv(dev);
 
+       dev->rtnl_link_ops = &ip6_link_ops;
        err = register_netdevice(dev);
        if (err < 0)
                goto out;
 
        strcpy(t->parms.name, dev->name);
-       dev->rtnl_link_ops = &ip6_link_ops;
 
        dev_hold(dev);
        ip6_tnl_link(ip6n, t);
@@ -1180,6 +1180,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 tproto;
        int err;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        tproto = ACCESS_ONCE(t->parms.proto);
        if (tproto != IPPROTO_IPIP && tproto != 0)
                return -1;
index 5ee56d0a8699e22434d5ad8b4380f890fa8d2126..d64ee7e8366492a439ab70ea7487bd3669800097 100644 (file)
@@ -1574,9 +1574,8 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
                return NULL;
 
        skb->priority = TC_PRIO_CONTROL;
-       skb->reserved_tailroom = skb_end_offset(skb) -
-                                min(mtu, skb_end_offset(skb));
        skb_reserve(skb, hlen);
+       skb_tailroom_reserve(skb, mtu, tlen);
 
        if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
index a1b6adc20e1e58c36c6209b690f641d2ee820f62..9cb0ff3043369e667ba816906c36b77f928bf14f 100644 (file)
@@ -837,8 +837,8 @@ start_lookup:
                flush_stack(stack, count, skb, count - 1);
        } else {
                if (!inner_flushed)
-                       UDP_INC_STATS_BH(net, UDP_MIB_IGNOREDMULTI,
-                                        proto == IPPROTO_UDPLITE);
+                       UDP6_INC_STATS_BH(net, UDP_MIB_IGNOREDMULTI,
+                                         proto == IPPROTO_UDPLITE);
                consume_skb(skb);
        }
        return 0;
@@ -916,11 +916,9 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
-               /* a return value > 0 means to resubmit the input, but
-                * it wants the return to be -protocol, or 0
-                */
+               /* a return value > 0 means to resubmit the input */
                if (ret > 0)
-                       return -ret;
+                       return ret;
 
                return 0;
        }
index ec22078b0914ff7ce65c3b11801504e252102dc2..42de4ccd159f6f6853930afd44cea239e2011a54 100644 (file)
@@ -123,12 +123,11 @@ static int l2tp_ip_recv(struct sk_buff *skb)
        struct l2tp_tunnel *tunnel = NULL;
        int length;
 
-       /* Point to L2TP header */
-       optr = ptr = skb->data;
-
        if (!pskb_may_pull(skb, 4))
                goto discard;
 
+       /* Point to L2TP header */
+       optr = ptr = skb->data;
        session_id = ntohl(*((__be32 *) ptr));
        ptr += 4;
 
@@ -156,6 +155,9 @@ static int l2tp_ip_recv(struct sk_buff *skb)
                if (!pskb_may_pull(skb, length))
                        goto discard;
 
+               /* Point to L2TP header */
+               optr = ptr = skb->data;
+               ptr += 4;
                pr_debug("%s: ip recv\n", tunnel->name);
                print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length);
        }
index a2c8747d2936c305753224e7a786d67087b2cb1a..9ee4ddb6b3973899995e6e3f5766f7e210f90370 100644 (file)
@@ -135,12 +135,11 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
        struct l2tp_tunnel *tunnel = NULL;
        int length;
 
-       /* Point to L2TP header */
-       optr = ptr = skb->data;
-
        if (!pskb_may_pull(skb, 4))
                goto discard;
 
+       /* Point to L2TP header */
+       optr = ptr = skb->data;
        session_id = ntohl(*((__be32 *) ptr));
        ptr += 4;
 
@@ -168,6 +167,9 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
                if (!pskb_may_pull(skb, length))
                        goto discard;
 
+               /* Point to L2TP header */
+               optr = ptr = skb->data;
+               ptr += 4;
                pr_debug("%s: ip recv\n", tunnel->name);
                print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length);
        }
index 6a12b0f5cac871e7906b7fee7a5da868b21d25c7..980e9e9b6684fd28fc65014550e83871ca37a282 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1484,14 +1485,21 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 
                sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
 
-               num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
-                                                        &ifibss->chandef,
-                                                        channels,
-                                                        ARRAY_SIZE(channels));
                scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
-               ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-                                           ifibss->ssid_len, channels, num,
-                                           scan_width);
+
+               if (ifibss->fixed_channel) {
+                       num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
+                                                                &ifibss->chandef,
+                                                                channels,
+                                                                ARRAY_SIZE(channels));
+                       ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                                   ifibss->ssid_len, channels,
+                                                   num, scan_width);
+               } else {
+                       ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                                   ifibss->ssid_len, NULL,
+                                                   0, scan_width);
+               }
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
index c9e325d2e120c0f9c230dbace71c3c405b9216a3..bcb0a1b645567e5c67e5c75f780fe38ce3356e40 100644 (file)
@@ -977,7 +977,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.txq) {
                struct txq_info *txqi = to_txq_info(sdata->vif.txq);
 
+               spin_lock_bh(&txqi->queue.lock);
                ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
+               spin_unlock_bh(&txqi->queue.lock);
+
                atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
        }
 
@@ -1747,7 +1750,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
                ret = dev_alloc_name(ndev, ndev->name);
                if (ret < 0) {
-                       free_netdev(ndev);
+                       ieee80211_if_free(ndev);
                        return ret;
                }
 
@@ -1833,7 +1836,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
                ret = register_netdevice(ndev);
                if (ret) {
-                       free_netdev(ndev);
+                       ieee80211_if_free(ndev);
                        return ret;
                }
        }
index 4cbf36cae806d2b2cafe0360b1fdcddf227a0a2b..a3bb8f7f5fc57739c31a58a7a24377d260e12da2 100644 (file)
@@ -2250,7 +2250,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       u16 q, hdrlen;
+       u16 ac, q, hdrlen;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -2319,7 +2319,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            ether_addr_equal(sdata->vif.addr, hdr->addr3))
                return RX_CONTINUE;
 
-       q = ieee80211_select_queue_80211(sdata, skb, hdr);
+       ac = ieee80211_select_queue_80211(sdata, skb, hdr);
+       q = sdata->vif.hw_queue[ac];
        if (ieee80211_queue_stopped(&local->hw, q)) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
                return RX_DROP_MONITOR;
index f91d1873218c7e07a1a8aecb006e02026ecc42ce..67066d048e6fb00033a660e7bbaad11d5621b1ac 100644 (file)
@@ -256,11 +256,11 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 }
 
 /* Caller must hold local->sta_mtx */
-static void sta_info_hash_add(struct ieee80211_local *local,
-                             struct sta_info *sta)
+static int sta_info_hash_add(struct ieee80211_local *local,
+                            struct sta_info *sta)
 {
-       rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
-                              sta_rht_params);
+       return rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
+                                     sta_rht_params);
 }
 
 static void sta_deliver_ps_frames(struct work_struct *wk)
@@ -484,11 +484,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct station_info sinfo;
+       struct station_info *sinfo;
        int err = 0;
 
        lockdep_assert_held(&local->sta_mtx);
 
+       sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
+       if (!sinfo) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+
        /* check if STA exists already */
        if (sta_info_get_bss(sdata, sta->sta.addr)) {
                err = -EEXIST;
@@ -503,7 +509,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
 
        /* make the station visible */
-       sta_info_hash_add(local, sta);
+       err = sta_info_hash_add(local, sta);
+       if (err)
+               goto out_drop_sta;
 
        list_add_tail_rcu(&sta->list, &local->sta_list);
 
@@ -520,10 +528,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        ieee80211_sta_debugfs_add(sta);
        rate_control_add_sta_debugfs(sta);
 
-       memset(&sinfo, 0, sizeof(sinfo));
-       sinfo.filled = 0;
-       sinfo.generation = local->sta_generation;
-       cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+       sinfo->generation = local->sta_generation;
+       cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
+       kfree(sinfo);
 
        sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
 
@@ -538,6 +545,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
  out_remove:
        sta_info_hash_del(local, sta);
        list_del_rcu(&sta->list);
+ out_drop_sta:
        local->num_sta--;
        synchronize_net();
        __cleanup_single_sta(sta);
@@ -882,7 +890,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct station_info sinfo = {};
+       struct station_info *sinfo;
        int ret;
 
        /*
@@ -920,8 +928,11 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
 
        sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
 
-       sta_set_sinfo(sta, &sinfo);
-       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+       sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
+       if (sinfo)
+               sta_set_sinfo(sta, sinfo);
+       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
+       kfree(sinfo);
 
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
index c32fc411a911a414db2d0c1e141cb76093079d33..881bc20728097f7e42831399393c3dea34304e39 100644 (file)
@@ -518,6 +518,9 @@ static struct net_device *find_outdev(struct net *net,
        if (!dev)
                return ERR_PTR(-ENODEV);
 
+       if (IS_ERR(dev))
+               return dev;
+
        /* The caller is holding rtnl anyways, so release the dev reference */
        dev_put(dev);
 
index f57b4dcdb2330e40110ce18ede71b742249edf00..4da560005b0e9168760c3e76825f18551d60d238 100644 (file)
@@ -1757,15 +1757,34 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
        cp = pp->conn_in_get(ipvs, af, skb, &iph);
 
        conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
-       if (conn_reuse_mode && !iph.fragoffs &&
-           is_new_conn(skb, &iph) && cp &&
-           ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
-             unlikely(!atomic_read(&cp->dest->weight))) ||
-            unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) {
-               if (!atomic_read(&cp->n_control))
-                       ip_vs_conn_expire_now(cp);
-               __ip_vs_conn_put(cp);
-               cp = NULL;
+       if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) {
+               bool uses_ct = false, resched = false;
+
+               if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
+                   unlikely(!atomic_read(&cp->dest->weight))) {
+                       resched = true;
+                       uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
+               } else if (is_new_conn_expected(cp, conn_reuse_mode)) {
+                       uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
+                       if (!atomic_read(&cp->n_control)) {
+                               resched = true;
+                       } else {
+                               /* Do not reschedule controlling connection
+                                * that uses conntrack while it is still
+                                * referenced by controlled connection(s).
+                                */
+                               resched = !uses_ct;
+                       }
+               }
+
+               if (resched) {
+                       if (!atomic_read(&cp->n_control))
+                               ip_vs_conn_expire_now(cp);
+                       __ip_vs_conn_put(cp);
+                       if (uses_ct)
+                               return NF_DROP;
+                       cp = NULL;
+               }
        }
 
        if (unlikely(!cp)) {
index 1b8d594e493a32f0ea461ade2d2a85387054a78d..0a6eb5c0d9e9c0c067ef23b57684506831932e89 100644 (file)
@@ -70,10 +70,10 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
        const char *dptr;
        int retc;
 
-       ip_vs_fill_iph_skb(p->af, skb, false, &iph);
+       retc = ip_vs_fill_iph_skb(p->af, skb, false, &iph);
 
        /* Only useful with UDP */
-       if (iph.protocol != IPPROTO_UDP)
+       if (!retc || iph.protocol != IPPROTO_UDP)
                return -EINVAL;
        /* todo: IPv6 fragments:
         *       I think this only should be done for the first fragment. /HS
@@ -88,7 +88,7 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
        dptr = skb->data + dataoff;
        datalen = skb->len - dataoff;
 
-       if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen))
+       if (get_callid(dptr, 0, datalen, &matchoff, &matchlen))
                return -EINVAL;
 
        /* N.B: pe_data is only set on success,
index 59651af8cc2705b39f3ad1ea71ab0b161668af02..992b35fb8615ca301621f76390a30b160657acc9 100644 (file)
@@ -1305,7 +1305,7 @@ static int netlink_release(struct socket *sock)
 
        skb_queue_purge(&sk->sk_write_queue);
 
-       if (nlk->portid) {
+       if (nlk->portid && nlk->bound) {
                struct netlink_notify n = {
                                                .net = sock_net(sk),
                                                .protocol = sk->sk_protocol,
index 992396aa635ce1174f6e62f19ae3f19a550668c6..da1ae0e13cb5b413ddc627a2c841b2fbc1820823 100644 (file)
@@ -1916,6 +1916,10 @@ retry:
                goto retry;
        }
 
+       if (!dev_validate_header(dev, skb->data, len)) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
        if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
            !packet_extra_vlan_len_allowed(dev, skb)) {
                err = -EMSGSIZE;
@@ -2326,18 +2330,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
        sock_wfree(skb);
 }
 
-static bool ll_header_truncated(const struct net_device *dev, int len)
-{
-       /* net device doesn't like empty head */
-       if (unlikely(len < dev->hard_header_len)) {
-               net_warn_ratelimited("%s: packet size is too short (%d < %d)\n",
-                                    current->comm, len, dev->hard_header_len);
-               return true;
-       }
-
-       return false;
-}
-
 static void tpacket_set_protocol(const struct net_device *dev,
                                 struct sk_buff *skb)
 {
@@ -2420,19 +2412,19 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                if (unlikely(err < 0))
                        return -EINVAL;
        } else if (dev->hard_header_len) {
-               if (ll_header_truncated(dev, tp_len))
-                       return -EINVAL;
+               int hdrlen = min_t(int, dev->hard_header_len, tp_len);
 
                skb_push(skb, dev->hard_header_len);
-               err = skb_store_bits(skb, 0, data,
-                               dev->hard_header_len);
+               err = skb_store_bits(skb, 0, data, hdrlen);
                if (unlikely(err))
                        return err;
+               if (!dev_validate_header(dev, skb->data, hdrlen))
+                       return -EINVAL;
                if (!skb->protocol)
                        tpacket_set_protocol(dev, skb);
 
-               data += dev->hard_header_len;
-               to_write -= dev->hard_header_len;
+               data += hdrlen;
+               to_write -= hdrlen;
        }
 
        offset = offset_in_page(data);
@@ -2763,9 +2755,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len);
                if (unlikely(offset < 0))
                        goto out_free;
-       } else {
-               if (ll_header_truncated(dev, len))
-                       goto out_free;
        }
 
        /* Returns -EFAULT on error */
@@ -2773,6 +2762,12 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        if (err)
                goto out_free;
 
+       if (sock->type == SOCK_RAW &&
+           !dev_validate_header(dev, skb->data, len)) {
+               err = -EINVAL;
+               goto out_free;
+       }
+
        sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
 
        if (!gso_type && (len > dev->mtu + reserve + extra_len) &&
index ec529121f38a03c4b3e2317249cd0694fd619d3f..ce46f1c7f133ad5b114e4c2cd571d26c2b9ee901 100644 (file)
@@ -526,6 +526,8 @@ static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
                }
                return 0;
        }
+       if (addr1->v6.sin6_port != addr2->v6.sin6_port)
+               return 0;
        if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
                return 0;
        /* If this is a linklocal address, compare the scope_id. */
index d730ef9dfbf02aba150d5229a0d2875ddc23aa4d..263b334ec5e48ce89b37d4c756acf8daaa59c6be 100644 (file)
@@ -2238,31 +2238,31 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                        break;
        }
 
-out_put:
-       fput_light(sock->file, fput_needed);
-
        if (err == 0)
-               return datagrams;
+               goto out_put;
 
-       if (datagrams != 0) {
+       if (datagrams == 0) {
+               datagrams = err;
+               goto out_put;
+       }
+
+       /*
+        * We may return less entries than requested (vlen) if the
+        * sock is non block and there aren't enough datagrams...
+        */
+       if (err != -EAGAIN) {
                /*
-                * We may return less entries than requested (vlen) if the
-                * sock is non block and there aren't enough datagrams...
+                * ... or  if recvmsg returns an error after we
+                * received some datagrams, where we record the
+                * error to return on the next call or if the
+                * app asks about it using getsockopt(SO_ERROR).
                 */
-               if (err != -EAGAIN) {
-                       /*
-                        * ... or  if recvmsg returns an error after we
-                        * received some datagrams, where we record the
-                        * error to return on the next call or if the
-                        * app asks about it using getsockopt(SO_ERROR).
-                        */
-                       sock->sk->sk_err = -err;
-               }
-
-               return datagrams;
+               sock->sk->sk_err = -err;
        }
+out_put:
+       fput_light(sock->file, fput_needed);
 
-       return err;
+       return datagrams;
 }
 
 SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
index 21e20353178e05e4940512141ac50fc41d5f4954..63fb5ee212cf8d168a53ce819d3e3f42a7e53fba 100644 (file)
@@ -1182,14 +1182,14 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
        }
 
        crq->q.reader = 0;
-       crq->item = cache_get(h);
        crq->buf = buf;
        crq->len = 0;
        crq->readers = 0;
        spin_lock(&queue_lock);
-       if (test_bit(CACHE_PENDING, &h->flags))
+       if (test_bit(CACHE_PENDING, &h->flags)) {
+               crq->item = cache_get(h);
                list_add_tail(&crq->q.list, &detail->queue);
-       else
+       else
                /* Lost a race, no longer PENDING, so don't enqueue */
                ret = -EAGAIN;
        spin_unlock(&queue_lock);
index b53246fb04128345304f2de5d3c895683ab0133b..e53003cf7703af30f3eaaf0d904f339ce3c7e757 100644 (file)
@@ -673,7 +673,7 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
        struct tipc_sock *tsk = tipc_sk(sk);
        struct net *net = sock_net(sk);
        struct tipc_msg *mhdr = &tsk->phdr;
-       struct sk_buff_head *pktchain = &sk->sk_write_queue;
+       struct sk_buff_head pktchain;
        struct iov_iter save = msg->msg_iter;
        uint mtu;
        int rc;
@@ -687,14 +687,16 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
        msg_set_nameupper(mhdr, seq->upper);
        msg_set_hdr_sz(mhdr, MCAST_H_SIZE);
 
+       skb_queue_head_init(&pktchain);
+
 new_mtu:
        mtu = tipc_bcast_get_mtu(net);
-       rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, pktchain);
+       rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, &pktchain);
        if (unlikely(rc < 0))
                return rc;
 
        do {
-               rc = tipc_bcast_xmit(net, pktchain);
+               rc = tipc_bcast_xmit(net, &pktchain);
                if (likely(!rc))
                        return dsz;
 
@@ -704,7 +706,7 @@ new_mtu:
                        if (!rc)
                                continue;
                }
-               __skb_queue_purge(pktchain);
+               __skb_queue_purge(&pktchain);
                if (rc == -EMSGSIZE) {
                        msg->msg_iter = save;
                        goto new_mtu;
@@ -863,7 +865,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
        struct net *net = sock_net(sk);
        struct tipc_msg *mhdr = &tsk->phdr;
        u32 dnode, dport;
-       struct sk_buff_head *pktchain = &sk->sk_write_queue;
+       struct sk_buff_head pktchain;
        struct sk_buff *skb;
        struct tipc_name_seq *seq;
        struct iov_iter save;
@@ -924,17 +926,18 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
                msg_set_hdr_sz(mhdr, BASIC_H_SIZE);
        }
 
+       skb_queue_head_init(&pktchain);
        save = m->msg_iter;
 new_mtu:
        mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
-       rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, pktchain);
+       rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, &pktchain);
        if (rc < 0)
                return rc;
 
        do {
-               skb = skb_peek(pktchain);
+               skb = skb_peek(&pktchain);
                TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
-               rc = tipc_node_xmit(net, pktchain, dnode, tsk->portid);
+               rc = tipc_node_xmit(net, &pktchain, dnode, tsk->portid);
                if (likely(!rc)) {
                        if (sock->state != SS_READY)
                                sock->state = SS_CONNECTING;
@@ -946,7 +949,7 @@ new_mtu:
                        if (!rc)
                                continue;
                }
-               __skb_queue_purge(pktchain);
+               __skb_queue_purge(&pktchain);
                if (rc == -EMSGSIZE) {
                        m->msg_iter = save;
                        goto new_mtu;
@@ -1016,7 +1019,7 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
        struct net *net = sock_net(sk);
        struct tipc_sock *tsk = tipc_sk(sk);
        struct tipc_msg *mhdr = &tsk->phdr;
-       struct sk_buff_head *pktchain = &sk->sk_write_queue;
+       struct sk_buff_head pktchain;
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        u32 portid = tsk->portid;
        int rc = -EINVAL;
@@ -1044,17 +1047,19 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
 
        timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
        dnode = tsk_peer_node(tsk);
+       skb_queue_head_init(&pktchain);
 
 next:
        save = m->msg_iter;
        mtu = tsk->max_pkt;
        send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
-       rc = tipc_msg_build(mhdr, m, sent, send, mtu, pktchain);
+       rc = tipc_msg_build(mhdr, m, sent, send, mtu, &pktchain);
        if (unlikely(rc < 0))
                return rc;
+
        do {
                if (likely(!tsk_conn_cong(tsk))) {
-                       rc = tipc_node_xmit(net, pktchain, dnode, portid);
+                       rc = tipc_node_xmit(net, &pktchain, dnode, portid);
                        if (likely(!rc)) {
                                tsk->sent_unacked++;
                                sent += send;
@@ -1063,7 +1068,7 @@ next:
                                goto next;
                        }
                        if (rc == -EMSGSIZE) {
-                               __skb_queue_purge(pktchain);
+                               __skb_queue_purge(&pktchain);
                                tsk->max_pkt = tipc_node_get_mtu(net, dnode,
                                                                 portid);
                                m->msg_iter = save;
@@ -1077,7 +1082,7 @@ next:
                rc = tipc_wait_for_sndpkt(sock, &timeo);
        } while (!rc);
 
-       __skb_queue_purge(pktchain);
+       __skb_queue_purge(&pktchain);
        return sent ? sent : rc;
 }
 
index 75b0d23ee882293a07fb9e236757931780def482..5d89f13a98dbafaa8b8921cd6df2ed7e570ccd66 100644 (file)
@@ -13161,7 +13161,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
        struct wireless_dev *wdev;
        struct cfg80211_beacon_registration *reg, *tmp;
 
-       if (state != NETLINK_URELEASE)
+       if (state != NETLINK_URELEASE || notify->protocol != NETLINK_GENERIC)
                return NOTIFY_DONE;
 
        rcu_read_lock();
index ad7f5b3f9b619ff22cb22da32b7f259abe82ca3d..1c4ad477ce935eb9f217fe6aebbd61551b0c1eea 100644 (file)
@@ -292,12 +292,15 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
 
                skb_dst_force(skb);
+               dev_hold(skb->dev);
 
                nexthdr = x->type->input(x, skb);
 
                if (nexthdr == -EINPROGRESS)
                        return 0;
 resume:
+               dev_put(skb->dev);
+
                spin_lock(&x->lock);
                if (nexthdr <= 0) {
                        if (nexthdr == -EBADMSG) {
index f085f5968c5238d631d6239c9d2a92a1b85fcd91..ce8cc9c006e56dd46c5c337553755e11a40b5717 100644 (file)
@@ -123,7 +123,7 @@ list_remove_head(x,c,...)
 |
 sizeof(<+...c...+>)
 |
-&c->member
+ &c->member
 |
 c = E
 |
index d79cba4ce3ebfb24a660da011076deb81a6ff4ad..ebced77deb9c4dc380ab5f58751950adc0ac3d7f 100644 (file)
@@ -96,13 +96,15 @@ savedefconfig: $(obj)/conf
 defconfig: $(obj)/conf
 ifeq ($(KBUILD_DEFCONFIG),)
        $< $(silent) --defconfig $(Kconfig)
-else ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
+else
+ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
        @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
        $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
 else
        @$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'"
        $(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG)
 endif
+endif
 
 %_defconfig: $(obj)/conf
        $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
index 0b7dc2fd7bac0e2985a0b16c023b98cca23325e7..dd243d2abd875b535d006535232821eefad3460b 100644 (file)
@@ -267,10 +267,8 @@ int conf_read_simple(const char *name, int def)
                if (in)
                        goto load;
                sym_add_change_count(1);
-               if (!sym_defconfig_list) {
-                       sym_calc_value(modules_sym);
+               if (!sym_defconfig_list)
                        return 1;
-               }
 
                for_all_defaults(sym_defconfig_list, prop) {
                        if (expr_calc_value(prop->visible.expr) == no ||
@@ -403,7 +401,6 @@ setsym:
        }
        free(line);
        fclose(in);
-       sym_calc_value(modules_sym);
        return 0;
 }
 
@@ -414,8 +411,12 @@ int conf_read(const char *name)
 
        sym_set_change_count(0);
 
-       if (conf_read_simple(name, S_DEF_USER))
+       if (conf_read_simple(name, S_DEF_USER)) {
+               sym_calc_value(modules_sym);
                return 1;
+       }
+
+       sym_calc_value(modules_sym);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
@@ -846,6 +847,7 @@ static int conf_split_config(void)
 
        name = conf_get_autoconfig_name();
        conf_read_simple(name, S_DEF_AUTO);
+       sym_calc_value(modules_sym);
 
        if (chdir("include/config"))
                return 1;
index 71004daefe31b6fc557453d1655005c81f7fa9cc..fe44d68e93449b1d133ee62b1470018f6a22a395 100755 (executable)
@@ -131,11 +131,11 @@ echo 'rm -rf $RPM_BUILD_ROOT'
 echo ""
 echo "%post"
 echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then"
-echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm"
-echo "cp /boot/System.map-$KERNELRELEASE /boot/System.map-$KERNELRELEASE-rpm"
+echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm"
+echo "cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm"
 echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE"
-echo "/sbin/installkernel $KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
-echo "rm -f /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
+echo "/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
+echo "rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
 echo "fi"
 echo ""
 echo "%files"
index c2423d913b46bd0e659ea4d4c057a3af6119c2d4..a2c0d620ca80fcca79260a1899e8a8d38c354247 100644 (file)
@@ -266,9 +266,9 @@ do_file(char const *const fname)
                break;
        }  /* end switch */
        if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
-       ||  r2(&ehdr->e_type) != ET_EXEC
+       ||  (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN)
        ||  ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
-               fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
+               fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
                fail_file();
        }
 
@@ -282,12 +282,13 @@ do_file(char const *const fname)
        case EM_386:
        case EM_X86_64:
        case EM_S390:
+       case EM_AARCH64:
+       case EM_PARISC:
                custom_sort = sort_relative_table;
                break;
        case EM_ARCOMPACT:
        case EM_ARCV2:
        case EM_ARM:
-       case EM_AARCH64:
        case EM_MICROBLAZE:
        case EM_MIPS:
        case EM_XTENSA:
@@ -304,7 +305,7 @@ do_file(char const *const fname)
                if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
                ||  r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
                        fprintf(stderr,
-                               "unrecognized ET_EXEC file: %s\n", fname);
+                               "unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
                        fail_file();
                }
                do32(ehdr, fname, custom_sort);
@@ -314,7 +315,7 @@ do_file(char const *const fname)
                if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
                ||  r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
                        fprintf(stderr,
-                               "unrecognized ET_EXEC file: %s\n", fname);
+                               "unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
                        fail_file();
                }
                do64(ghdr, fname, custom_sort);
index 6b5a811e01a544f3379829b8ebfa3773904691bb..3a9b66c6e09c38933b63a4af6ee20e34efa09118 100644 (file)
@@ -322,7 +322,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                        char name[16];
                        snd_pcm_debug_name(substream, name, sizeof(name));
                        pcm_err(substream->pcm,
-                               "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+                               "invalid position: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
                                name, pos, runtime->buffer_size,
                                runtime->period_size);
                }
index f24c9fccf00876ed6b2b120a89ccf0200025bff8..b982d1b089bd90ff44267f528dff8690d76ad4db 100644 (file)
@@ -1051,8 +1051,8 @@ static int snd_timer_s_start(struct snd_timer * timer)
                njiff += timer->sticks - priv->correction;
                priv->correction = 0;
        }
-       priv->last_expires = priv->tlist.expires = njiff;
-       add_timer(&priv->tlist);
+       priv->last_expires = njiff;
+       mod_timer(&priv->tlist, njiff);
        return 0;
 }
 
index 5c4fa8eba1d023c3f1e004e42e46424ac26c58e9..367dbf0d285e322eaf5ac8069ce6efb3d07a85a9 100644 (file)
@@ -843,7 +843,7 @@ static hda_nid_t path_power_update(struct hda_codec *codec,
                                   bool allow_powerdown)
 {
        hda_nid_t nid, changed = 0;
-       int i, state;
+       int i, state, power;
 
        for (i = 0; i < path->depth; i++) {
                nid = path->path[i];
@@ -855,7 +855,9 @@ static hda_nid_t path_power_update(struct hda_codec *codec,
                        state = AC_PWRST_D0;
                else
                        state = AC_PWRST_D3;
-               if (!snd_hda_check_power_state(codec, nid, state)) {
+               power = snd_hda_codec_read(codec, nid, 0,
+                                          AC_VERB_GET_POWER_STATE, 0);
+               if (power != (state | (state << 4))) {
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_POWER_STATE, state);
                        changed = nid;
index 2ff692dd2c5f79ef577aa3be3b6df5326e3d8470..411630e9c034aec5136fd67ee5013331db25f175 100644 (file)
@@ -2207,6 +2207,9 @@ static const struct pci_device_id azx_ids[] = {
        /* Broxton-P(Apollolake) */
        { PCI_DEVICE(0x8086, 0x5a98),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
+       /* Broxton-T */
+       { PCI_DEVICE(0x8086, 0x1a98),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0a0c),
          .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
index c1c855a6c0af8199d03b04419d16d3494507ddeb..80bbadc83721447754392238118eee98484616b6 100644 (file)
@@ -174,8 +174,12 @@ static void cs_automute(struct hda_codec *codec)
        snd_hda_gen_update_outputs(codec);
 
        if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
-               spec->gpio_data = spec->gen.hp_jack_present ?
-                       spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
+               if (spec->gen.automute_speaker)
+                       spec->gpio_data = spec->gen.hp_jack_present ?
+                               spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
+               else
+                       spec->gpio_data =
+                               spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
                snd_hda_codec_write(codec, 0x01, 0,
                                    AC_VERB_SET_GPIO_DATA, spec->gpio_data);
        }
@@ -357,6 +361,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
        int err;
+       int i;
 
        err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
        if (err < 0)
@@ -366,6 +371,19 @@ static int cs_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       /* keep the ADCs powered up when it's dynamically switchable */
+       if (spec->gen.dyn_adc_switch) {
+               unsigned int done = 0;
+               for (i = 0; i < spec->gen.input_mux.num_items; i++) {
+                       int idx = spec->gen.dyn_adc_idx[i];
+                       if (done & (1 << idx))
+                               continue;
+                       snd_hda_gen_fix_pin_power(codec,
+                                                 spec->gen.adc_nids[idx]);
+                       done |= 1 << idx;
+               }
+       }
+
        return 0;
 }
 
index ef198903c0c3e6bca1685c3cc6a53420e77e1333..600af5878e7545563384e387966062a9691bd33b 100644 (file)
@@ -204,8 +204,13 @@ static void cx_auto_reboot_notify(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
 
-       if (codec->core.vendor_id != 0x14f150f2)
+       switch (codec->core.vendor_id) {
+       case 0x14f150f2: /* CX20722 */
+       case 0x14f150f4: /* CX20724 */
+               break;
+       default:
                return;
+       }
 
        /* Turn the CX20722 codec into D3 to avoid spurious noises
           from the internal speaker during (and after) reboot */
index 70c9456033790d7a213d4a47dd144b952d06c370..f7bcd8dbac14f91c6ccfd409d8e898c27ba2d3bb 100644 (file)
@@ -2353,6 +2353,10 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
        struct hda_codec *codec = audio_ptr;
        int pin_nid = port + 0x04;
 
+       /* we assume only from port-B to port-D */
+       if (port < 1 || port > 3)
+               return;
+
        /* skip notification during system suspend (but not in runtime PM);
         * the state will be updated at resume
         */
index c2430b36e1cef101d460c4ca651a9d1b6228735b..ac4490a968638ff7eed3b4007ccdcda8a7b81cea 100644 (file)
@@ -3801,6 +3801,10 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
 
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+               {}
+       };
        static struct coef_fw coef0255[] = {
                WRITE_COEF(0x45, 0xc089),
                WRITE_COEF(0x45, 0xc489),
@@ -3842,6 +3846,9 @@ static void alc_headset_mode_default(struct hda_codec *codec)
        };
 
        switch (codec->core.vendor_id) {
+       case 0x10ec0225:
+               alc_process_coef_fw(codec, coef0225);
+               break;
        case 0x10ec0255:
        case 0x10ec0256:
                alc_process_coef_fw(codec, coef0255);
@@ -4750,6 +4757,10 @@ enum {
        ALC293_FIXUP_LENOVO_SPK_NOISE,
        ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
        ALC255_FIXUP_DELL_SPK_NOISE,
+       ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC280_FIXUP_HP_HEADSET_MIC,
+       ALC221_FIXUP_HP_FRONT_MIC,
+       ALC292_FIXUP_TPT460,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5375,6 +5386,36 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
        },
+       [ALC225_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Disable pass-through path for FRONT 14h */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC280_FIXUP_HP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC,
+       },
+       [ALC221_FIXUP_HP_FRONT_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a19020 }, /* Front Mic */
+                       { }
+               },
+       },
+       [ALC292_FIXUP_TPT460] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_tpt440_dock,
+               .chained = true,
+               .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5408,6 +5449,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13),
+       SND_PCI_QUIRK(0x1028, 0x0669, "Dell Optiplex 9020m", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -5479,6 +5521,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_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),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5527,8 +5571,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
+       SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+       SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
@@ -5539,6 +5584,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x504a, "ThinkPad X260", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -5621,6 +5667,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
        {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
        {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
+       {.id = ALC292_FIXUP_TPT460, .name = "tpt460"},
        {}
 };
 #define ALC225_STANDARD_PINS \
@@ -5647,10 +5694,10 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x21, 0x03211020}
 
 static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC225_STANDARD_PINS,
                {0x14, 0x901701a0}),
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC225_STANDARD_PINS,
                {0x14, 0x901701b0}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
@@ -6378,6 +6425,7 @@ enum {
        ALC668_FIXUP_AUTO_MUTE,
        ALC668_FIXUP_DELL_DISABLE_AAMIX,
        ALC668_FIXUP_DELL_XPS13,
+       ALC662_FIXUP_ASUS_Nx50,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -6618,6 +6666,12 @@ static const struct hda_fixup alc662_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_bass_chmap,
        },
+       [ALC662_FIXUP_ASUS_Nx50] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_1A
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6640,8 +6694,9 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
-       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A),
+       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
        SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
+       SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
        SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
        SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
        SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
index 42bcbac801a322d0f7cf8df6961e9c6129ae0093..ccdab29a8b6680ed5e7d4efcf0d99fa482ece5fc 100644 (file)
@@ -2879,6 +2879,7 @@ static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
 
 static struct snd_pci_quirk intel8x0_clock_list[] = {
        SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000),
+       SND_PCI_QUIRK(0x1014, 0x0581, "AD1981B", 48000),
        SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100),
        SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000),
        SND_PCI_QUIRK(0x1028, 0x01ad, "AD1981B", 48000),
index c5194f5b150aadb7d0b08cd5831aab2a03f2392d..d7e71f3092998cdaa3894adefdd9468c236bb24e 100644 (file)
@@ -1341,5 +1341,6 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
        }
 
        pcxhr_msg_thread(mgr);
+       mutex_unlock(&mgr->lock);
        return IRQ_HANDLED;
 }
index e619d5651b09bbd6401cdea6734acf0a4a6f17dc..080c78e88e102199cb9b8923f0556ce084ad22d8 100644 (file)
@@ -352,6 +352,11 @@ static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
        regcache_cache_only(ssm4567->regmap, !enable);
 
        if (enable) {
+               ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET,
+                       0x00);
+               if (ret)
+                       return ret;
+
                ret = regmap_update_bits(ssm4567->regmap,
                        SSM4567_REG_POWER_CTRL,
                        SSM4567_POWER_SPWDN, 0x00);
index e4145509d63cb36fdec39069a9b487c9e16ee3c5..9c52193924603d00493708c66d05d36279d529c6 100644 (file)
@@ -324,7 +324,7 @@ static const struct snd_soc_component_driver s3c_ac97_component = {
 
 static int s3c_ac97_probe(struct platform_device *pdev)
 {
-       struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+       struct resource *mem_res, *irq_res;
        struct s3c_audio_pdata *ac97_pdata;
        int ret;
 
@@ -335,24 +335,6 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        }
 
        /* Check for availability of necessary resource */
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmatx_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmarx_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-       if (!dmamic_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
-               return -ENXIO;
-       }
-
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!irq_res) {
                dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
@@ -364,11 +346,11 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        if (IS_ERR(s3c_ac97.regs))
                return PTR_ERR(s3c_ac97.regs);
 
-       s3c_ac97_pcm_out.channel = dmatx_res->start;
+       s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback;
        s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-       s3c_ac97_pcm_in.channel = dmarx_res->start;
+       s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture;
        s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-       s3c_ac97_mic_in.channel = dmamic_res->start;
+       s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic;
        s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
 
        init_completion(&s3c_ac97.done);
index 0e85dcfec02347eed1c4ee88fbf3c79a9f0cb675..085ef30f5ca28464b3c3e1b7293b50f50fd8b61d 100644 (file)
@@ -15,7 +15,7 @@
 #include <sound/dmaengine_pcm.h>
 
 struct s3c_dma_params {
-       int channel;                            /* Channel ID */
+       void *slave;                            /* Channel ID */
        dma_addr_t dma_addr;
        int dma_size;                   /* Size of the DMA transfer */
        char *ch_name;
index 506f5bf6d08265e6ff456cd9ca8a26d6782d4055..727008d57d1439e276c73b880685adbcef030d74 100644 (file)
@@ -50,14 +50,14 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
 
        if (playback) {
                playback_data = &playback->dma_data;
-               playback_data->filter_data = (void *)playback->channel;
+               playback_data->filter_data = playback->slave;
                playback_data->chan_name = playback->ch_name;
                playback_data->addr = playback->dma_addr;
                playback_data->addr_width = playback->dma_size;
        }
        if (capture) {
                capture_data = &capture->dma_data;
-               capture_data->filter_data = (void *)capture->channel;
+               capture_data->filter_data = capture->slave;
                capture_data->chan_name = capture->ch_name;
                capture_data->addr = capture->dma_addr;
                capture_data->addr_width = capture->dma_size;
index 7dbf899b2af24c50a589aa0ceadb5e09a169be30..e163b0148c4bc5b4c2eaf45e7281e7ab2e69bf0b 100644 (file)
@@ -1260,27 +1260,14 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        pri_dai->lock = &pri_dai->spinlock;
 
        if (!np) {
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (!res) {
-                       dev_err(&pdev->dev,
-                               "Unable to get I2S-TX dma resource\n");
-                       return -ENXIO;
-               }
-               pri_dai->dma_playback.channel = res->start;
-
-               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (!res) {
-                       dev_err(&pdev->dev,
-                               "Unable to get I2S-RX dma resource\n");
-                       return -ENXIO;
-               }
-               pri_dai->dma_capture.channel = res->start;
-
                if (i2s_pdata == NULL) {
                        dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
                        return -EINVAL;
                }
 
+               pri_dai->dma_playback.slave = i2s_pdata->dma_playback;
+               pri_dai->dma_capture.slave = i2s_pdata->dma_capture;
+
                if (&i2s_pdata->type)
                        i2s_cfg = &i2s_pdata->type.i2s;
 
@@ -1341,11 +1328,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
                sec_dai->dma_playback.ch_name = "tx-sec";
 
-               if (!np) {
-                       res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-                       if (res)
-                               sec_dai->dma_playback.channel = res->start;
-               }
+               if (!np)
+                       sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec;
 
                sec_dai->dma_playback.dma_size = 4;
                sec_dai->addr = pri_dai->addr;
index b320a9d3fbf82f6b49b9d6a8509c302c9a3ac86c..c77f324e0bb85727b04589d4477d4150adb62976 100644 (file)
@@ -486,7 +486,7 @@ static const struct snd_soc_component_driver s3c_pcm_component = {
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
        struct s3c_pcm_info *pcm;
-       struct resource *mem_res, *dmatx_res, *dmarx_res;
+       struct resource *mem_res;
        struct s3c_audio_pdata *pcm_pdata;
        int ret;
 
@@ -499,18 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        pcm_pdata = pdev->dev.platform_data;
 
        /* Check for availability of necessary resource */
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmatx_res) {
-               dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmarx_res) {
-               dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
-               return -ENXIO;
-       }
-
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem_res) {
                dev_err(&pdev->dev, "Unable to get register resource\n");
@@ -568,8 +556,10 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
                                                        + S3C_PCM_TXFIFO;
 
-       s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
-       s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+       if (pcm_pdata) {
+               s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture;
+               s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback;
+       }
 
        pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
        pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
index df65c5b494b17aad482c7821586b6ed6832bf9f6..b6ab3fc5789e89a92b937e1b2c95a1c6fa2c0063 100644 (file)
@@ -709,7 +709,7 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 #endif
 
 int s3c_i2sv2_register_component(struct device *dev, int id,
-                          struct snd_soc_component_driver *cmp_drv,
+                          const struct snd_soc_component_driver *cmp_drv,
                           struct snd_soc_dai_driver *dai_drv)
 {
        struct snd_soc_dai_ops *ops = (struct snd_soc_dai_ops *)dai_drv->ops;
index 90abab364b495fd18d11ed421a37bc123e3fa45e..d0684145ed1fd50967c1ce27075af3636aec15aa 100644 (file)
@@ -101,7 +101,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
  * soc core.
  */
 extern int s3c_i2sv2_register_component(struct device *dev, int id,
-                                       struct snd_soc_component_driver *cmp_drv,
+                                       const struct snd_soc_component_driver *cmp_drv,
                                        struct snd_soc_dai_driver *dai_drv);
 
 #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
index 2b766d212ce0796a7dd5c9b54b7ad09668e0be02..77d27c85a32a64a5c2000c65924d0b6bf190b1d9 100644 (file)
 #include "s3c2412-i2s.h"
 
 static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
-       .channel        = DMACH_I2S_OUT,
+       .slave          = (void *)(uintptr_t)DMACH_I2S_OUT,
        .ch_name        = "tx",
        .dma_size       = 4,
 };
 
 static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
-       .channel        = DMACH_I2S_IN,
+       .slave          = (void *)(uintptr_t)DMACH_I2S_IN,
        .ch_name        = "rx",
        .dma_size       = 4,
 };
index 5bf723689692fc52ffc5edce20f82e8d5cb4fc21..9da3a77ea2c796095a44bc8a1cda5ea9e4e5cd66 100644 (file)
 #include "s3c24xx-i2s.h"
 
 static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
-       .channel        = DMACH_I2S_OUT,
+       .slave          = (void *)(uintptr_t)DMACH_I2S_OUT,
        .ch_name        = "tx",
        .dma_size       = 2,
 };
 
 static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
-       .channel        = DMACH_I2S_IN,
+       .slave          = (void *)(uintptr_t)DMACH_I2S_IN,
        .ch_name        = "rx",
        .dma_size       = 2,
 };
index 36dbc0e96004095d1617d9a355af620e124567a9..9dd7ee6d03ff16828ea52f211a3a5741444b98ca 100644 (file)
@@ -359,7 +359,7 @@ static const struct snd_soc_component_driver samsung_spdif_component = {
 static int spdif_probe(struct platform_device *pdev)
 {
        struct s3c_audio_pdata *spdif_pdata;
-       struct resource *mem_res, *dma_res;
+       struct resource *mem_res;
        struct samsung_spdif_info *spdif;
        int ret;
 
@@ -367,12 +367,6 @@ static int spdif_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "Entered %s\n", __func__);
 
-       dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dma_res) {
-               dev_err(&pdev->dev, "Unable to get dma resource.\n");
-               return -ENXIO;
-       }
-
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem_res) {
                dev_err(&pdev->dev, "Unable to get register resource.\n");
@@ -432,7 +426,7 @@ static int spdif_probe(struct platform_device *pdev)
 
        spdif_stereo_out.dma_size = 2;
        spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
-       spdif_stereo_out.channel = dma_res->start;
+       spdif_stereo_out.slave = spdif_pdata ? spdif_pdata->dma_playback : NULL;
 
        spdif->dma_playback = &spdif_stereo_out;
 
index 416514fe9e6350a80fcdf60770a9079029a687cb..afb70a5d4fd3552964917abe09a88c60e0f8c8d7 100644 (file)
@@ -2188,6 +2188,13 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
        int count = 0;
        char *state = "not set";
 
+       /* card won't be set for the dummy component, as a spot fix
+        * we're checking for that case specifically here but in future
+        * we will ensure that the dummy component looks like others.
+        */
+       if (!cmpnt->card)
+               return 0;
+
        list_for_each_entry(w, &cmpnt->card->widgets, list) {
                if (w->dapm != dapm)
                        continue;
index 2ed260b10f6dc02cd129550ba1067c878034cb07..7ccbcaf6a1476423e0d2becf0bf91f3463a47b46 100644 (file)
@@ -285,6 +285,8 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
        unsigned char data[3];
        int err, crate;
 
+       if (get_iface_desc(alts)->bNumEndpoints < 1)
+               return -EINVAL;
        ep = get_endpoint(alts, 0)->bEndpointAddress;
 
        /* if endpoint doesn't have sampling rate control, bail out */
index 7b1cb365ffab74d6028206adb8012226da963bac..c07a7eda42a28eee533752e28f787ccfd2230ed2 100644 (file)
@@ -438,6 +438,9 @@ exit_clear:
  *
  * New endpoints will be added to chip->ep_list and must be freed by
  * calling snd_usb_endpoint_free().
+ *
+ * For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that
+ * bNumEndpoints > 1 beforehand.
  */
 struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
                                              struct usb_host_interface *alts,
index ddca6547399b0103b37abbdf73cfa5c9e710a7fd..1f8fb0d904e059d4e6084d0c221489d598e9e4c1 100644 (file)
@@ -348,6 +348,16 @@ static struct usbmix_name_map bose_companion5_map[] = {
        { 0 }   /* terminator */
 };
 
+/*
+ * Dell usb dock with ALC4020 codec had a firmware problem where it got
+ * screwed up when zero volume is passed; just skip it as a workaround
+ */
+static const struct usbmix_name_map dell_alc4020_map[] = {
+       { 16, NULL },
+       { 19, NULL },
+       { 0 }
+};
+
 /*
  * Control map entries
  */
@@ -430,6 +440,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x0ccd, 0x0028),
                .map = aureon_51_2_map,
        },
+       {
+               .id = USB_ID(0x0bda, 0x4014),
+               .map = dell_alc4020_map,
+       },
        {
                .id = USB_ID(0x0dba, 0x1000),
                .map = mbox1_map,
index 279025650568ec2936e270d33a1737fd5f504cd6..f6c3bf79af9a7d9f7cabe6b83c3573a59964b826 100644 (file)
@@ -1519,7 +1519,11 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
 
        /* use known values for that card: interface#1 altsetting#1 */
        iface = usb_ifnum_to_if(chip->dev, 1);
+       if (!iface || iface->num_altsetting < 2)
+               return -EINVAL;
        alts = &iface->altsetting[1];
+       if (get_iface_desc(alts)->bNumEndpoints < 1)
+               return -EINVAL;
        ep = get_endpoint(alts, 0)->bEndpointAddress;
 
        err = snd_usb_ctl_msg(chip->dev,
index 9245f52d43bdecfeb710b6cfc6ae99b3202aae90..44d178ee9177565bba3fde9d2ac2b7308e8dd7ae 100644 (file)
@@ -159,6 +159,8 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
        unsigned char data[1];
        int err;
 
+       if (get_iface_desc(alts)->bNumEndpoints < 1)
+               return -EINVAL;
        ep = get_endpoint(alts, 0)->bEndpointAddress;
 
        data[0] = 1;
index c458d60d50300823e03e39109b715c94bf44cbbf..001fb4dc07227e9c3a620a5593f0636823bd29fb 100644 (file)
@@ -150,6 +150,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                usb_audio_err(chip, "cannot memdup\n");
                return -ENOMEM;
        }
+       INIT_LIST_HEAD(&fp->list);
        if (fp->nr_rates > MAX_NR_RATES) {
                kfree(fp);
                return -EINVAL;
@@ -167,19 +168,20 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        stream = (fp->endpoint & USB_DIR_IN)
                ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
        err = snd_usb_add_audio_stream(chip, stream, fp);
-       if (err < 0) {
-               kfree(fp);
-               kfree(rate_table);
-               return err;
-       }
+       if (err < 0)
+               goto error;
        if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
            fp->altset_idx >= iface->num_altsetting) {
-               kfree(fp);
-               kfree(rate_table);
-               return -EINVAL;
+               err = -EINVAL;
+               goto error;
        }
        alts = &iface->altsetting[fp->altset_idx];
        altsd = get_iface_desc(alts);
+       if (altsd->bNumEndpoints < 1) {
+               err = -EINVAL;
+               goto error;
+       }
+
        fp->protocol = altsd->bInterfaceProtocol;
 
        if (fp->datainterval == 0)
@@ -190,6 +192,12 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        snd_usb_init_pitch(chip, fp->iface, alts, fp);
        snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max);
        return 0;
+
+ error:
+       list_del(&fp->list); /* unlink for avoiding double-free */
+       kfree(fp);
+       kfree(rate_table);
+       return err;
 }
 
 static int create_auto_pcm_quirk(struct snd_usb_audio *chip,
@@ -462,6 +470,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
        fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
        fp->datainterval = 0;
        fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+       INIT_LIST_HEAD(&fp->list);
 
        switch (fp->maxpacksize) {
        case 0x120:
@@ -485,6 +494,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
                ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
        err = snd_usb_add_audio_stream(chip, stream, fp);
        if (err < 0) {
+               list_del(&fp->list); /* unlink for avoiding double-free */
                kfree(fp);
                return err;
        }
@@ -1121,12 +1131,15 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        switch (chip->usb_id) {
        case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema  */
        case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */
+       case USB_ID(0x045E, 0x076E): /* MS Lifecam HD-5001 */
        case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */
        case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */
        case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
+       case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */
        case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
        case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
        case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+       case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
        case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */
                return true;
        }
index 8ee14f2365e749d964c369acef5ac45f95a060ca..3b23102230c03d1558b0f067f963ccb0b5dfaaf4 100644 (file)
@@ -316,7 +316,9 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
 /*
  * add this endpoint to the chip instance.
  * if a stream with the same endpoint already exists, append to it.
- * if not, create a new pcm stream.
+ * if not, create a new pcm stream. note, fp is added to the substream
+ * fmt_list and will be freed on the chip instance release. do not free
+ * fp or do remove it from the substream fmt_list to avoid double-free.
  */
 int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
                             int stream,
@@ -677,6 +679,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                                        * (fp->maxpacksize & 0x7ff);
                fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
                fp->clock = clock;
+               INIT_LIST_HEAD(&fp->list);
 
                /* some quirks for attributes here */
 
@@ -725,6 +728,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
                err = snd_usb_add_audio_stream(chip, stream, fp);
                if (err < 0) {
+                       list_del(&fp->list); /* unlink for avoiding double-free */
                        kfree(fp->rate_table);
                        kfree(fp->chmap);
                        kfree(fp);
index a8ab795569266f6e48550e4fb400d27a6f4c817d..a8c4644022a6b6cfb5f46785847178ed28159e62 100644 (file)
@@ -5,6 +5,8 @@ PTHREAD_LIBS = -lpthread
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) $(shell getconf LFS_CFLAGS)
 
+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
+
 all: hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
 %: %.c
        $(CC) $(CFLAGS) -o $@ $^
index 4e074a6608269793d52a2ea4f28061532bb9798b..90c3558c2c12fd5b2420f7e5ee7b3129fbd77255 100644 (file)
@@ -62,6 +62,14 @@ OPTIONS
 --scale::
        scale/normalize counter values
 
+-d::
+--detailed::
+       print more detailed statistics, can be specified up to 3 times
+
+          -d:          detailed events, L1 and LLC data cache
+        -d -d:     more detailed events, dTLB and iTLB events
+     -d -d -d:     very detailed events, adding prefetch events
+
 -r::
 --repeat=<n>::
        repeat command and print average + stddev (max: 100). 0 means forever.
index 81def6c3f24bf16397c8e15d26178cd4957bd86f..3900386a3629410b903223642b449159ecd18e13 100644 (file)
@@ -2059,10 +2059,12 @@ skip_annotation:
                         *
                         * See hist_browser__show_entry.
                         */
-                       nr_options += add_script_opt(browser,
-                                                    &actions[nr_options],
-                                                    &options[nr_options],
-                                                    NULL, browser->selection->sym);
+                       if (sort__has_sym && browser->selection->sym) {
+                               nr_options += add_script_opt(browser,
+                                                            &actions[nr_options],
+                                                            &options[nr_options],
+                                                            NULL, browser->selection->sym);
+                       }
                }
                nr_options += add_script_opt(browser, &actions[nr_options],
                                             &options[nr_options], NULL, NULL);
index 8b10621b415c684564a6dd5af130ebc9d3ab33c7..956187bf1a8532454dec1c2aa8fa4c4a9a827928 100644 (file)
@@ -274,7 +274,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                strcpy(execname, "");
 
                /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
-               n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
+               n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n",
                       &event->mmap2.start, &event->mmap2.len, prot,
                       &event->mmap2.pgoff, &event->mmap2.maj,
                       &event->mmap2.min,
index d1392194a9a951bd3e1dd5c9b72fd383ede98439..b4b96120fc3b4336749e97a7ede90725c1c4340e 100644 (file)
@@ -1211,12 +1211,12 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus,
         */
        if (cpus != evlist->cpus) {
                cpu_map__put(evlist->cpus);
-               evlist->cpus = cpus;
+               evlist->cpus = cpu_map__get(cpus);
        }
 
        if (threads != evlist->threads) {
                thread_map__put(evlist->threads);
-               evlist->threads = threads;
+               evlist->threads = thread_map__get(threads);
        }
 
        perf_evlist__propagate_maps(evlist);
index 97f963a3dcb95157f8dcaf3e568d3ac487989608..9227c2f076c36195ec476dc64d6236341026decd 100644 (file)
@@ -1127,7 +1127,7 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq)
                pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n",
                       ret);
 
-       if (pt->synth_opts.callchain)
+       if (pt->synth_opts.last_branch)
                intel_pt_reset_last_branch_rb(ptq);
 
        return ret;
index b48e87693aa56b5ed7c3e3563fb19ab3a15d712c..a35db828bd0d32d09068fed2e1c451e28db90dbf 100644 (file)
@@ -2101,11 +2101,11 @@ char *parse_events_formats_error_string(char *additional_terms)
 
        /* valid terms */
        if (additional_terms) {
-               if (!asprintf(&str, "valid terms: %s,%s",
-                             additional_terms, static_terms))
+               if (asprintf(&str, "valid terms: %s,%s",
+                            additional_terms, static_terms) < 0)
                        goto fail;
        } else {
-               if (!asprintf(&str, "valid terms: %s", static_terms))
+               if (asprintf(&str, "valid terms: %s", static_terms) < 0)
                        goto fail;
        }
        return str;
index e4b173dec4b9978cb3d1eb53c3569277c5110714..6f2a0279476c1a98c2f44fafc3e3fcbfc9ef4bcb 100644 (file)
@@ -283,13 +283,12 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
 {
        struct dirent *evt_ent;
        DIR *event_dir;
-       int ret = 0;
 
        event_dir = opendir(dir);
        if (!event_dir)
                return -EINVAL;
 
-       while (!ret && (evt_ent = readdir(event_dir))) {
+       while ((evt_ent = readdir(event_dir))) {
                char path[PATH_MAX];
                char *name = evt_ent->d_name;
                FILE *file;
@@ -305,17 +304,19 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
 
                snprintf(path, PATH_MAX, "%s/%s", dir, name);
 
-               ret = -EINVAL;
                file = fopen(path, "r");
-               if (!file)
-                       break;
+               if (!file) {
+                       pr_debug("Cannot open %s\n", path);
+                       continue;
+               }
 
-               ret = perf_pmu__new_alias(head, dir, name, file);
+               if (perf_pmu__new_alias(head, dir, name, file) < 0)
+                       pr_debug("Cannot set up %s\n", name);
                fclose(file);
        }
 
        closedir(event_dir);
-       return ret;
+       return 0;
 }
 
 /*
index 1833103768cb99fbdbb92ea8910b08488fd2aac3..c8680984d2d6680f56a974a1b54056a5e74263e1 100644 (file)
@@ -22,6 +22,7 @@ cflags = getenv('CFLAGS', '').split()
 # switch off several checks (need to be at the end of cflags list)
 cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
 
+src_perf  = getenv('srctree') + '/tools/perf'
 build_lib = getenv('PYTHON_EXTBUILD_LIB')
 build_tmp = getenv('PYTHON_EXTBUILD_TMP')
 libtraceevent = getenv('LIBTRACEEVENT')
@@ -30,6 +31,9 @@ libapikfs = getenv('LIBAPI')
 ext_sources = [f.strip() for f in file('util/python-ext-sources')
                                if len(f.strip()) > 0 and f[0] != '#']
 
+# use full paths with source files
+ext_sources = map(lambda x: '%s/%s' % (src_perf, x) , ext_sources)
+
 perf = Extension('perf',
                  sources = ext_sources,
                  include_dirs = ['util/include'],
index ea6064696fe43867d1d1baee35059b276d84817b..a7b9022b5c8fc07eaf381059618c25ebee70dc0c 100644 (file)
@@ -86,6 +86,8 @@ static void kvm_timer_inject_irq_work(struct work_struct *work)
        vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired);
        vcpu->arch.timer_cpu.armed = false;
 
+       WARN_ON(!kvm_timer_should_fire(vcpu));
+
        /*
         * If the vcpu is blocked we want to wake it up so that it will see
         * the timer has expired when entering the guest.
@@ -93,10 +95,46 @@ static void kvm_timer_inject_irq_work(struct work_struct *work)
        kvm_vcpu_kick(vcpu);
 }
 
+static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu)
+{
+       cycle_t cval, now;
+
+       cval = vcpu->arch.timer_cpu.cntv_cval;
+       now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
+
+       if (now < cval) {
+               u64 ns;
+
+               ns = cyclecounter_cyc2ns(timecounter->cc,
+                                        cval - now,
+                                        timecounter->mask,
+                                        &timecounter->frac);
+               return ns;
+       }
+
+       return 0;
+}
+
 static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt)
 {
        struct arch_timer_cpu *timer;
+       struct kvm_vcpu *vcpu;
+       u64 ns;
+
        timer = container_of(hrt, struct arch_timer_cpu, timer);
+       vcpu = container_of(timer, struct kvm_vcpu, arch.timer_cpu);
+
+       /*
+        * Check that the timer has really expired from the guest's
+        * PoV (NTP on the host may have forced it to expire
+        * early). If we should have slept longer, restart it.
+        */
+       ns = kvm_timer_compute_delta(vcpu);
+       if (unlikely(ns)) {
+               hrtimer_forward_now(hrt, ns_to_ktime(ns));
+               return HRTIMER_RESTART;
+       }
+
        queue_work(wqueue, &timer->expired);
        return HRTIMER_NORESTART;
 }
@@ -170,8 +208,6 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
 void kvm_timer_schedule(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
-       u64 ns;
-       cycle_t cval, now;
 
        BUG_ON(timer_is_armed(timer));
 
@@ -191,14 +227,7 @@ void kvm_timer_schedule(struct kvm_vcpu *vcpu)
                return;
 
        /*  The timer has not yet expired, schedule a background timer */
-       cval = timer->cntv_cval;
-       now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
-
-       ns = cyclecounter_cyc2ns(timecounter->cc,
-                                cval - now,
-                                timecounter->mask,
-                                &timecounter->frac);
-       timer_arm(timer, ns);
+       timer_arm(timer, kvm_timer_compute_delta(vcpu));
 }
 
 void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
index 7338e30421d84101313535a5cdc51a23678682ac..fefbf2d148efb6c1197ade46fd3f2ccca198b826 100644 (file)
@@ -547,6 +547,16 @@ static struct kvm *kvm_create_vm(unsigned long type)
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
+       spin_lock_init(&kvm->mmu_lock);
+       atomic_inc(&current->mm->mm_count);
+       kvm->mm = current->mm;
+       kvm_eventfd_init(kvm);
+       mutex_init(&kvm->lock);
+       mutex_init(&kvm->irq_lock);
+       mutex_init(&kvm->slots_lock);
+       atomic_set(&kvm->users_count, 1);
+       INIT_LIST_HEAD(&kvm->devices);
+
        r = kvm_arch_init_vm(kvm, type);
        if (r)
                goto out_err_no_disable;
@@ -579,16 +589,6 @@ static struct kvm *kvm_create_vm(unsigned long type)
                        goto out_err;
        }
 
-       spin_lock_init(&kvm->mmu_lock);
-       kvm->mm = current->mm;
-       atomic_inc(&kvm->mm->mm_count);
-       kvm_eventfd_init(kvm);
-       mutex_init(&kvm->lock);
-       mutex_init(&kvm->irq_lock);
-       mutex_init(&kvm->slots_lock);
-       atomic_set(&kvm->users_count, 1);
-       INIT_LIST_HEAD(&kvm->devices);
-
        r = kvm_init_mmu_notifier(kvm);
        if (r)
                goto out_err;
@@ -613,6 +613,7 @@ out_err_no_disable:
        for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++)
                kvm_free_memslots(kvm, kvm->memslots[i]);
        kvm_arch_free_vm(kvm);
+       mmdrop(current->mm);
        return ERR_PTR(r);
 }