Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
authorHuang, Tao <huangtao@rock-chips.com>
Fri, 4 Nov 2016 06:23:25 +0000 (14:23 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 4 Nov 2016 06:30:24 +0000 (14:30 +0800)
* linux-linaro-lsk-v4.4-android: (1362 commits)
  Linux 4.4.30
  Revert "fix minor infoleak in get_user_ex()"
  Revert "x86/mm: Expand the exception table logic to allow new handling options"
  Linux 4.4.29
  ARM: pxa: pxa_cplds: fix interrupt handling
  powerpc/nvram: Fix an incorrect partition merge
  mpt3sas: Don't spam logs if logging level is 0
  perf symbols: Fixup symbol sizes before picking best ones
  perf symbols: Check symbol_conf.allow_aliases for kallsyms loading too
  perf hists browser: Fix event group display
  clk: divider: Fix clk_divider_round_rate() to use clk_readl()
  clk: qoriq: fix a register offset error
  s390/con3270: fix insufficient space padding
  s390/con3270: fix use of uninitialised data
  s390/cio: fix accidental interrupt enabling during resume
  x86/mm: Expand the exception table logic to allow new handling options
  dmaengine: ipu: remove bogus NO_IRQ reference
  power: bq24257: Fix use of uninitialized pointer bq->charger
  staging: r8188eu: Fix scheduling while atomic splat
  ASoC: dapm: Fix kcontrol creation for output driver widget
  ...

1200 files changed:
Documentation/cgroups/cgroups.txt
Documentation/device-mapper/boot.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt
Documentation/devicetree/bindings/misc/memory-state-time.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
Documentation/filesystems/proc.txt
Documentation/kernel-parameters.txt
Documentation/mic/mpssd/mpssd.c
Documentation/module-signing.txt
Documentation/pinctrl.txt
Documentation/scheduler/sched-tune.txt
Documentation/x86/pat.txt
Makefile
android/configs/android-base.cfg
android/configs/android-recommended.cfg
arch/Kconfig
arch/alpha/include/asm/uaccess.h
arch/arc/Makefile
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/entry.h
arch/arc/include/asm/irqflags-compact.h
arch/arc/include/asm/pgtable.h
arch/arc/include/asm/uaccess.h
arch/arc/kernel/signal.c
arch/arc/kernel/stacktrace.c
arch/arc/mm/cache.c
arch/arm/Kconfig
arch/arm/boot/compressed/head.S
arch/arm/boot/dts/armada-390.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/kirkwood-ib62x0.dts
arch/arm/boot/dts/omap3-overo-base.dtsi
arch/arm/boot/dts/omap3-overo-chestnut43-common.dtsi
arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
arch/arm/boot/dts/omap3-overo-tobiduo-common.dtsi
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/boot/dts/stih407-family.dtsi
arch/arm/boot/dts/stih410.dtsi
arch/arm/boot/dts/sun4i-a10-a1000.dts
arch/arm/boot/dts/sun4i-a10-hackberry.dts
arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/common/sa1111.c
arch/arm/crypto/aes-ce-glue.c
arch/arm/crypto/ghash-ce-glue.c
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/pgtable-3level.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/topology.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/devtree.c
arch/arm/kernel/setup.c
arch/arm/kernel/sys_oabi-compat.c
arch/arm/kernel/topology.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/kvm/arm.c
arch/arm/kvm/mmu.c
arch/arm/mach-imx/pm-imx6.c
arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/prcm43xx.h
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/pxa_cplds_irqs.c
arch/arm/mach-pxa/xcep.c
arch/arm/mach-realview/core.c
arch/arm/mach-sa1100/clock.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-shmobile/regulator-quirk-rcar-gen2.c
arch/arm/mm/mmu.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/rockchip/rk3368.dtsi
arch/arm64/crypto/aes-glue.c
arch/arm64/include/asm/alternative.h
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/debug-monitors.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/futex.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/kernel-pgtable.h
arch/arm64/include/asm/kprobes.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/module.h
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/probes.h [new file with mode: 0644]
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/spinlock.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/uapi/asm/auxvec.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/arm64ksyms.c
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/head.S
arch/arm64/kernel/hw_breakpoint.c
arch/arm64/kernel/insn.c
arch/arm64/kernel/kgdb.c
arch/arm64/kernel/probes/Makefile [new file with mode: 0644]
arch/arm64/kernel/probes/decode-insn.c [new file with mode: 0644]
arch/arm64/kernel/probes/decode-insn.h [new file with mode: 0644]
arch/arm64/kernel/probes/kprobes.c [new file with mode: 0644]
arch/arm64/kernel/probes/kprobes_trampoline.S [new file with mode: 0644]
arch/arm64/kernel/probes/simulate-insn.c [new file with mode: 0644]
arch/arm64/kernel/probes/simulate-insn.h [new file with mode: 0644]
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/hyp-init.S
arch/arm64/lib/clear_user.S
arch/arm64/lib/copy_from_user.S
arch/arm64/lib/copy_in_user.S
arch/arm64/lib/copy_to_user.S
arch/arm64/mm/cache.S
arch/arm64/mm/context.c
arch/arm64/mm/fault.c
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/proc-macros.S [deleted file]
arch/arm64/mm/proc.S
arch/arm64/xen/hypercall.S
arch/avr32/include/asm/uaccess.h
arch/avr32/kernel/avr32_ksyms.c
arch/avr32/lib/copy_user.S
arch/avr32/mach-at32ap/pio.c
arch/blackfin/include/asm/uaccess.h
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/cris/include/asm/uaccess.h
arch/frv/include/asm/uaccess.h
arch/hexagon/include/asm/uaccess.h
arch/ia64/Kconfig
arch/ia64/include/asm/early_ioremap.h [new file with mode: 0644]
arch/ia64/include/asm/io.h
arch/ia64/include/asm/uaccess.h
arch/m32r/include/asm/uaccess.h
arch/metag/include/asm/atomic.h
arch/metag/include/asm/atomic_lnkget.h
arch/metag/include/asm/cmpxchg_lnkget.h
arch/metag/include/asm/uaccess.h
arch/microblaze/include/asm/uaccess.h
arch/mips/Kconfig.debug
arch/mips/Makefile
arch/mips/include/asm/asmmacro.h
arch/mips/include/asm/mach-paravirt/kernel-entry-init.h
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/uaccess.h
arch/mips/include/asm/uprobes.h
arch/mips/kernel/csrc-r4k.c
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/process.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/smp.c
arch/mips/kernel/uprobes.c
arch/mips/kernel/vdso.c
arch/mips/kvm/emulate.c
arch/mips/kvm/tlb.c
arch/mips/loongson64/loongson-3/hpet.c
arch/mips/mm/uasm-mips.c
arch/mips/mti-malta/malta-setup.c
arch/mips/vdso/Makefile
arch/mn10300/include/asm/uaccess.h
arch/mn10300/lib/usercopy.c
arch/nios2/include/asm/uaccess.h
arch/openrisc/include/asm/uaccess.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/uaccess.h
arch/parisc/include/uapi/asm/errno.h
arch/parisc/kernel/setup.c
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/icswx.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/uaccess.h
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/nvram_64.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/tm.S
arch/powerpc/kernel/vdso64/datapage.S
arch/powerpc/kernel/vdso64/gettimeofday.S
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/booke.c
arch/powerpc/lib/copyuser_64.S
arch/powerpc/mm/copro_fault.c
arch/powerpc/mm/slb_low.S
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/opal-dump.c
arch/powerpc/platforms/powernv/opal-elog.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/pseries/lpar.c
arch/s390/Kconfig
arch/s390/crypto/prng.c
arch/s390/include/asm/pci_dma.h
arch/s390/include/asm/tlbflush.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/ipl.c
arch/s390/lib/uaccess.c
arch/s390/mm/pgtable.c
arch/s390/pci/pci.c
arch/s390/pci/pci_dma.c
arch/score/include/asm/uaccess.h
arch/sh/include/asm/uaccess.h
arch/sh/include/asm/uaccess_64.h
arch/sparc/Kconfig
arch/sparc/include/asm/uaccess_32.h
arch/sparc/include/asm/uaccess_64.h
arch/tile/include/asm/elf.h
arch/tile/include/uapi/asm/auxvec.h
arch/um/include/asm/common.lds.S
arch/x86/Kconfig
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/configs/tiny.config
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/include/asm/mtrr.h
arch/x86/include/asm/pat.h
arch/x86/include/asm/pvclock.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_32.h
arch/x86/include/asm/uaccess_64.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/mtrr/mtrr.h
arch/x86/kernel/cpu/perf_event_intel_cqm.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/e820.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/uprobes.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/mtrr.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/mmap.c
arch/x86/mm/pat.c
arch/x86/pci/intel_mid_pci.c
arch/x86/xen/enlighten.c
backported-features [new file with mode: 0644]
block/bio.c
block/blk-cgroup.c
block/blk-core.c
block/blk-merge.c
block/blk-mq.c
block/cfq-iosched.c
block/genhd.c
block/ioprio.c
crypto/asymmetric_keys/pkcs7_parser.c
crypto/async_tx/async_pq.c
crypto/blkcipher.c
crypto/cryptd.c
crypto/echainiv.c
crypto/gcm.c
crypto/ghash-generic.c
crypto/scatterwalk.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/cppc_acpi.c
drivers/acpi/ec.c
drivers/acpi/nfit.c
drivers/acpi/nfit.h
drivers/acpi/numa.c
drivers/acpi/scan.c
drivers/acpi/sysfs.c
drivers/android/binder.c
drivers/ata/libata-core.c
drivers/base/dma-mapping.c
drivers/base/platform.c
drivers/bcma/bcma_private.h
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_intel.c
drivers/bus/arm-ccn.c
drivers/char/hw_random/exynos-rng.c
drivers/char/hw_random/omap-rng.c
drivers/char/random.c
drivers/char/tpm/tpm-dev.c
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm-sysfs.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm_crb.c
drivers/clk/clk-divider.c
drivers/clk/clk-qoriq.c
drivers/clk/clk-xgene.c
drivers/clk/imx/clk-imx35.c
drivers/clk/imx/clk-imx6q.c
drivers/clk/rockchip/clk-mmc-phase.c
drivers/clocksource/sun4i_timer.c
drivers/cpufreq/Kconfig
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/intel_pstate.c
drivers/cpuidle/cpuidle-arm.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/nx/nx-842-powernv.c
drivers/crypto/nx/nx.c
drivers/crypto/qat/qat_common/qat_algs.c
drivers/crypto/vmx/aes_cbc.c
drivers/crypto/vmx/aes_ctr.c
drivers/crypto/vmx/ghash.c
drivers/crypto/vmx/ppc-xlate.pl
drivers/dma/at_xdmac.c
drivers/dma/ipu/ipu_irq.c
drivers/dma/sh/usb-dmac.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/firmware/efi/Makefile
drivers/firmware/efi/arm-init.c [new file with mode: 0644]
drivers/firmware/efi/arm-runtime.c [new file with mode: 0644]
drivers/firmware/efi/efi.c
drivers/gpio/Kconfig
drivers/gpio/gpio-intel-mid.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-sa1100.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/atombios_dp.c
drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/cz_dpm.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_cache.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/gma500/cdv_intel_dp.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nv04_fbcon.c
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nvc0_fbcon.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
drivers/gpu/drm/qxl/qxl_draw.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_dp_mst.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sislands_smc.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/hid/hid-core.c
drivers/hid/hid-sony.c
drivers/hid/uhid.c
drivers/hv/channel.c
drivers/hv/channel_mgmt.c
drivers/hv/hv.c
drivers/hv/hv_fcopy.c
drivers/hv/hv_kvp.c
drivers/hv/hv_snapshot.c
drivers/hv/hv_utils_transport.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c
drivers/hwmon/adt7411.c
drivers/hwmon/iio_hwmon.c
drivers/hwtracing/intel_th/core.c
drivers/hwtracing/intel_th/intel_th.h
drivers/hwtracing/intel_th/pci.c
drivers/i2c/busses/i2c-cros-ec-tunnel.c
drivers/i2c/busses/i2c-efm32.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-qup.c
drivers/i2c/muxes/i2c-mux-reg.c
drivers/idle/intel_idle.c
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/accel/kxsd9.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ad799x.c
drivers/iio/adc/at91_adc.c
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/common/hid-sensors/hid-sensor-attributes.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/proximity/as3935.c
drivers/infiniband/core/iwpm_util.c
drivers/infiniband/core/multicast.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/mcg.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx5/cq.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/keyreset.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elantech.c
drivers/input/mouse/vmmouse.c
drivers/input/serio/i8042-io.h
drivers/input/serio/i8042-ip22io.h
drivers/input/serio/i8042-ppcio.h
drivers/input/serio/i8042-sparcio.h
drivers/input/serio/i8042-unicore32io.h
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/serio/libps2.c
drivers/input/touchscreen/sur40.c
drivers/input/touchscreen/tsc2004.c
drivers/input/touchscreen/tsc2005.c
drivers/input/touchscreen/tsc200x-core.c
drivers/input/touchscreen/tsc200x-core.h
drivers/input/touchscreen/wacom_w8001.c
drivers/iommu/amd_iommu.c
drivers/iommu/arm-smmu-v3.c
drivers/iommu/dma-iommu.c
drivers/iommu/dmar.c
drivers/iommu/exynos-iommu.c
drivers/iommu/intel-iommu.c
drivers/irqchip/irq-atmel-aic.c
drivers/irqchip/irq-atmel-aic5.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/lightnvm/gennvm.c
drivers/lightnvm/rrpc.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/bcache/super.c
drivers/md/dm-android-verity.c [new file with mode: 0644]
drivers/md/dm-android-verity.h [new file with mode: 0644]
drivers/md/dm-crypt.c
drivers/md/dm-flakey.c
drivers/md/dm-ioctl.c
drivers/md/dm-linear.c
drivers/md/dm-log-writes.c
drivers/md/dm-mpath.c
drivers/md/dm-table.c
drivers/md/dm-verity-target.c
drivers/md/dm-verity.h
drivers/md/dm.c
drivers/md/md.c
drivers/media/dvb-core/dvb_ringbuffer.c
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/mb86a20s.c
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/rc/ir-rc5-decoder.c
drivers/media/tuners/tuner-xc2028.c
drivers/media/usb/airspy/airspy.c
drivers/media/usb/cx231xx/cx231xx-avcore.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-core.c
drivers/media/usb/em28xx/em28xx-i2c.c
drivers/media/usb/gspca/cpia1.c
drivers/media/usb/gspca/konica.c
drivers/media/usb/gspca/t613.c
drivers/media/usb/usbtv/usbtv-audio.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-v4l2.c
drivers/memstick/host/rtsx_usb_ms.c
drivers/mfd/Kconfig
drivers/mfd/atmel-hlcdc.c
drivers/mfd/qcom_rpm.c
drivers/mfd/rtsx_usb.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/cxl/Makefile
drivers/misc/cxl/api.c
drivers/misc/cxl/context.c
drivers/misc/cxl/cxl.h
drivers/misc/cxl/fault.c
drivers/misc/cxl/file.c
drivers/misc/cxl/pci.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/pci-me.c
drivers/misc/memory_state_time.c [new file with mode: 0644]
drivers/mmc/card/block.c
drivers/mmc/card/queue.h
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/host.h
drivers/mmc/host/Kconfig
drivers/mmc/host/pxamci.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mtd/maps/pmcmsp-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/wl.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/can/at91_can.c
drivers/net/can/c_can/c_can.c
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/dsa/bcm_sf2.h
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/cavium/liquidio/lio_main.c
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nic_main.c
drivers/net/ethernet/cavium/thunder/nic_reg.h
drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/cavium/thunder/thunder_bgx.h
drivers/net/ethernet/intel/e1000/e1000.h
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/fm10k/fm10k.h
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/fm10k/fm10k_pci.c
drivers/net/ethernet/intel/fm10k/fm10k_type.h
drivers/net/ethernet/intel/fm10k/fm10k_vf.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_i210.c
drivers/net/ethernet/intel/igb/e1000_i210.h
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/qlogic/qed/qed_spq.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smc91x.h
drivers/net/phy/phy.c
drivers/net/ppp/ppp_generic.c
drivers/net/tun.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/stf.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlwifi/dvm/calib.c
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/sf.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/realtek/rtlwifi/regd.c
drivers/nfc/fdp/fdp.c
drivers/nvme/host/pci.c
drivers/of/base.c
drivers/of/dynamic.c
drivers/of/of_private.h
drivers/pci/msi.c
drivers/pci/pci-sysfs.c
drivers/pci/quirks.c
drivers/perf/arm_pmu.c
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/pinctrl-amd.c
drivers/pinctrl/pinctrl-at91-pio4.c
drivers/pinctrl/pinctrl-pistachio.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a23.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a33.c
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
drivers/platform/chrome/cros_ec_dev.c
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/x86/hp-wmi.c
drivers/pnp/quirks.c
drivers/power/bq24257_charger.c
drivers/power/max17042_battery.c
drivers/power/power_supply_core.c
drivers/power/reset/hisi-reboot.c
drivers/power/tps65217_charger.c
drivers/pps/clients/pps_parport.c
drivers/pwm/core.c
drivers/pwm/pwm-fsl-ftm.c
drivers/pwm/pwm-lpc32xx.c
drivers/regulator/anatop-regulator.c
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/qcom_spmi-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/remoteproc/remoteproc_core.c
drivers/rtc/rtc-s3c.c
drivers/s390/block/dasd.c
drivers/s390/char/con3270.c
drivers/s390/char/sclp_ctl.c
drivers/s390/cio/chp.c
drivers/s390/cio/chp.h
drivers/s390/cio/chsc.c
drivers/s390/cio/cmf.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_dbf.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/aacraid/commctrl.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/constants.c
drivers/scsi/cxlflash/common.h
drivers/scsi/cxlflash/main.c
drivers/scsi/cxlflash/main.h
drivers/scsi/cxlflash/superpipe.c
drivers/scsi/cxlflash/vlun.c
drivers/scsi/fnic/fnic_fcs.c
drivers/scsi/hpsa.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ipr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/soc/qcom/spm.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sun4i.c
drivers/spi/spi-sun6i.c
drivers/staging/android/ion/ion.c
drivers/staging/comedi/drivers/comedi_test.c
drivers/staging/comedi/drivers/daqboard2000.c
drivers/staging/comedi/drivers/ni_mio_common.c
drivers/staging/fbtft/fbtft-core.c
drivers/staging/iio/adc/ad7192.c
drivers/staging/lustre/lustre/llite/llite_internal.h
drivers/staging/rdma/ipath/ipath_file_ops.c
drivers/staging/rtl8188eu/core/rtw_cmd.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/target_core_device.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_sbc.c
drivers/target/target_core_transport.c
drivers/target/target_core_xcopy.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_mid.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/samsung.c
drivers/tty/tty_ldisc.c
drivers/uio/uio_dmem_genirq.c
drivers/usb/chipidea/udc.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/class/usbtmc.c
drivers/usb/common/common.c
drivers/usb/core/config.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/core/urb.c
drivers/usb/core/usb.h
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_accessory.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/udc/fsl_qe_udc.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ohci-q.c
drivers/usb/host/xhci-hub.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/misc/legousbtower.c
drivers/usb/misc/usbtest.c
drivers/usb/musb/musb_host.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/usb-serial-simple.c
drivers/usb/serial/usb-serial.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vhost/scsi.c
drivers/video/fbdev/efifb.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/w1/masters/omap_hdq.c
drivers/xen/xen-pciback/conf_space.c
drivers/xen/xenbus/xenbus_dev_frontend.c
drivers/xen/xenbus/xenbus_xs.c
fs/9p/acl.c
fs/9p/vfs_file.c
fs/aio.c
fs/attr.c
fs/autofs4/autofs_i.h
fs/autofs4/expire.c
fs/autofs4/root.c
fs/btrfs/acl.c
fs/btrfs/compression.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/ioctl.c
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
fs/btrfs/tree-log.c
fs/ceph/acl.c
fs/ceph/file.c
fs/ceph/inode.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_debug.h
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/readdir.c
fs/cifs/smb2glob.h
fs/cifs/smb2inode.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/dcache.c
fs/devpts/inode.c
fs/dlm/lowcomms.c
fs/ecryptfs/file.c
fs/ecryptfs/kthread.c
fs/ext2/acl.c
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/crypto_policy.c
fs/ext4/extents.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/readpage.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/xattr.c
fs/f2fs/acl.c
fs/f2fs/crypto_policy.c
fs/f2fs/data.c
fs/f2fs/inline.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/inode.c
fs/gfs2/acl.c
fs/hfsplus/posix_acl.c
fs/hostfs/hostfs_kern.c
fs/inode.c
fs/isofs/inode.c
fs/jbd2/commit.c
fs/jbd2/transaction.c
fs/jffs2/acl.c
fs/jfs/acl.c
fs/kernfs/file.c
fs/locks.c
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/nfs/callback.c
fs/nfs/callback_xdr.c
fs/nfs/delegation.c
fs/nfs/filelayout/filelayout.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/pnfs.c
fs/nfs/write.c
fs/nfsd/nfs4state.c
fs/nilfs2/the_nilfs.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify_user.c
fs/notify/group.c
fs/notify/notification.c
fs/ocfs2/acl.c
fs/ocfs2/dlm/dlmconvert.c
fs/ocfs2/file.c
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/posix_acl.c
fs/proc/base.c
fs/proc/kcore.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/pstore/inode.c
fs/pstore/platform.c
fs/pstore/pmsg.c
fs/pstore/ram.c
fs/pstore/ram_core.c
fs/reiserfs/file.c
fs/reiserfs/ibalance.c
fs/reiserfs/namei.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr.h
fs/reiserfs/xattr_acl.c
fs/reiserfs/xattr_security.c
fs/reiserfs/xattr_trusted.c
fs/reiserfs/xattr_user.c
fs/sdcardfs/derived_perm.c
fs/seq_file.c
fs/super.c
fs/sysfs/file.c
fs/ubifs/tnc_commit.c
fs/ubifs/xattr.c
fs/utimes.c
fs/xfs/libxfs/xfs_sb.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_buf.c
include/asm-generic/uaccess.h
include/asm-generic/vmlinux.lds.h
include/crypto/ghash.h [new file with mode: 0644]
include/drm/drmP.h
include/drm/i915_pciids.h
include/linux/acpi.h
include/linux/backing-dev-defs.h
include/linux/backing-dev.h
include/linux/bcma/bcma.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/can/dev.h
include/linux/capability.h
include/linux/cgroup-defs.h
include/linux/cgroup.h
include/linux/device-mapper.h
include/linux/devpts_fs.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/i8042.h
include/linux/inet_diag.h
include/linux/irq.h
include/linux/irqchip/arm-gic-v3.h
include/linux/kernel.h
include/linux/lightnvm.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/memory-state-time.h [new file with mode: 0644]
include/linux/mfd/88pm80x.h
include/linux/mfd/cros_ec.h
include/linux/mfd/ti_am335x_tscadc.h
include/linux/mlx5/qp.h
include/linux/mm.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmzone.h
include/linux/msi.h
include/linux/netdevice.h
include/linux/nvmem-consumer.h
include/linux/pagemap.h
include/linux/pci_ids.h
include/linux/percpu-rwsem.h
include/linux/perf_event.h
include/linux/posix_acl.h
include/linux/pstore.h
include/linux/pstore_ram.h
include/linux/rcu_sync.h
include/linux/sched.h
include/linux/sched/sysctl.h
include/linux/sched_energy.h
include/linux/sem.h
include/linux/serio.h
include/linux/slab.h
include/linux/slub_def.h
include/linux/smc91x.h
include/linux/string.h
include/linux/swap.h
include/linux/sysctl.h
include/linux/thread_info.h
include/linux/time.h
include/linux/uaccess.h
include/linux/uio.h
include/linux/vmstat.h
include/net/af_unix.h
include/net/fib_rules.h
include/net/ip_tunnels.h
include/net/tcp.h
include/net/udp.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/trace/events/android_fs.h [new file with mode: 0644]
include/trace/events/android_fs_template.h [new file with mode: 0644]
include/trace/events/power.h
include/trace/events/sched.h
include/trace/events/sunrpc.h
include/uapi/linux/hyperv.h
include/uapi/linux/inet_diag.h
include/uapi/linux/rtnetlink.h
include/uapi/linux/usb/ch9.h
include/uapi/linux/videodev2.h
include/uapi/scsi/cxlflash_ioctl.h
init/Kconfig
init/Makefile
init/do_mounts.c
init/do_mounts.h
init/do_mounts_dm.c [new file with mode: 0644]
ipc/msg.c
ipc/sem.c
kernel/audit.c
kernel/audit_watch.c
kernel/auditsc.c
kernel/capability.c
kernel/cgroup.c
kernel/configs/tiny.config
kernel/cpu.c
kernel/cpuset.c
kernel/cred.c
kernel/events/core.c
kernel/events/uprobes.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/irq/generic-chip.c
kernel/irq/msi.c
kernel/kexec_file.c
kernel/locking/percpu-rwsem.c
kernel/module.c
kernel/panic.c
kernel/power/hibernate.c
kernel/power/snapshot.c
kernel/printk/braille.c
kernel/rcu/sync.c
kernel/sched/Makefile
kernel/sched/core.c
kernel/sched/cpufreq_sched.c
kernel/sched/cputime.c
kernel/sched/fair.c
kernel/sched/features.h
kernel/sched/idle.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stop_task.c
kernel/sched/tune.c
kernel/sched/tune.h
kernel/sched/walt.c [new file with mode: 0644]
kernel/sched/walt.h [new file with mode: 0644]
kernel/sysctl.c
kernel/time/clocksource.c
kernel/time/hrtimer.c
kernel/time/ntp.c
kernel/time/posix-cpu-timers.c
kernel/time/timekeeping.c
kernel/time/timekeeping_debug.c
kernel/trace/Makefile
kernel/trace/trace.c
lib/Kconfig.debug
lib/asn1_decoder.c
lib/iov_iter.c
lib/kstrtox.c
lib/mpi/mpicoder.c
lib/string.c
lib/strncpy_from_user.c
lib/strnlen_user.c
mm/Makefile
mm/backing-dev.c
mm/compaction.c
mm/filemap.c
mm/gup.c
mm/hugetlb.c
mm/internal.h
mm/ksm.c
mm/maccess.c
mm/memblock.c
mm/memcontrol.c
mm/page_alloc.c
mm/slab.c
mm/slab_common.c
mm/slub.c
mm/usercopy.c [new file with mode: 0644]
mm/util.c
mm/vmscan.c
mm/vmstat.c
mm/workingset.c
net/batman-adv/originator.c
net/batman-adv/types.h
net/bluetooth/l2cap_sock.c
net/bridge/br_multicast.c
net/caif/cfpkt_skbuff.c
net/ceph/osdmap.c
net/core/dev.c
net/ipv4/af_inet.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/fou.c
net/ipv4/gre_offload.c
net/ipv4/inet_diag.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ip_vti.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_yeah.c
net/ipv4/udp.c
net/ipv4/udp_diag.c
net/ipv4/udp_offload.c
net/ipv6/addrconf.c
net/ipv6/icmp.c
net/ipv6/ip6_offload.c
net/ipv6/ping.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/irda/af_irda.c
net/irda/iriap.c
net/mac80211/cfg.c
net/mac80211/tx.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nfnetlink.c
net/netfilter/x_tables.c
net/netlabel/netlabel_kapi.c
net/rds/recv.c
net/rds/tcp.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/svc.c
net/sunrpc/xprtsock.c
net/sysctl_net.c
net/tipc/link.c
net/tipc/name_distr.c
net/tipc/netlink_compat.c
net/tipc/socket.c
net/tipc/subscr.c
net/tipc/udp_media.c
net/unix/af_unix.c
net/wireless/nl80211.c
net/wireless/wext-core.c
samples/kprobes/kprobe_example.c
scripts/recordmcount.c
security/Kconfig
security/apparmor/apparmorfs.c
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/lsm_audit.c
sound/core/rawmidi.c
sound/core/timer.c
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_hwdep.c
sound/firewire/fireworks/fireworks_proc.c
sound/firewire/fireworks/fireworks_transaction.c
sound/firewire/tascam/tascam-hwdep.c
sound/hda/array.c
sound/pci/ali5451/ali5451.c
sound/pci/hda/dell_wmi_helper.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/thinkpad_helper.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/intel/atom/sst/sst_pvt.c
sound/soc/intel/skylake/skl.c
sound/soc/omap/omap-mcpdm.c
sound/soc/soc-dapm.c
sound/soc/soc-topology.c
sound/usb/line6/driver.c
sound/usb/line6/pcm.c
sound/usb/line6/pod.c
sound/usb/mixer_quirks.c
sound/usb/quirks.c
tools/hv/hv_fcopy_daemon.c
tools/perf/arch/x86/util/intel-pt.c
tools/perf/ui/browsers/hists.c
tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
tools/perf/util/intel-pt.c
tools/perf/util/stat.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/testing/nvdimm/test/nfit.c
tools/vm/slabinfo.c
virt/kvm/kvm_main.c

index 2d984e20783be198586267633e65a842ae61559e..c6256ae9885b8ac7445f6d10066ee541ebb388b8 100644 (file)
@@ -578,15 +578,6 @@ is completely unused; @cgrp->parent is still valid. (Note - can also
 be called for a newly-created cgroup if an error occurs after this
 subsystem's create() method has been called for the new cgroup).
 
-int allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
-(cgroup_mutex held by caller)
-
-Called prior to moving a task into a cgroup; if the subsystem
-returns an error, this will abort the attach operation.  Used
-to extend the permission checks - if all subsystems in a cgroup
-return 0, the attach will be allowed to proceed, even if the
-default permission check (root or same user) fails.
-
 int can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 (cgroup_mutex held by caller)
 
diff --git a/Documentation/device-mapper/boot.txt b/Documentation/device-mapper/boot.txt
new file mode 100644 (file)
index 0000000..adcaad5
--- /dev/null
@@ -0,0 +1,42 @@
+Boot time creation of mapped devices
+===================================
+
+It is possible to configure a device mapper device to act as the root
+device for your system in two ways.
+
+The first is to build an initial ramdisk which boots to a minimal
+userspace which configures the device, then pivot_root(8) in to it.
+
+For simple device mapper configurations, it is possible to boot directly
+using the following kernel command line:
+
+dm="<name> <uuid> <ro>,table line 1,...,table line n"
+
+name = the name to associate with the device
+       after boot, udev, if used, will use that name to label
+       the device node.
+uuid = may be 'none' or the UUID desired for the device.
+ro = may be "ro" or "rw".  If "ro", the device and device table will be
+       marked read-only.
+
+Each table line may be as normal when using the dmsetup tool except for
+two variations:
+1. Any use of commas will be interpreted as a newline
+2. Quotation marks cannot be escaped and cannot be used without
+   terminating the dm= argument.
+
+Unless renamed by udev, the device node created will be dm-0 as the
+first minor number for the device-mapper is used during early creation.
+
+Example
+=======
+
+- Booting to a linear array made up of user-mode linux block devices:
+
+  dm="lroot none 0, 0 4096 linear 98:16 0, 4096 4096 linear 98:32 0" \
+  root=/dev/dm-0
+
+Will boot to a rw dm-linear target of 8192 sectors split across two
+block devices identified by their major:minor numbers.  After boot, udev
+will rename this target to /dev/mapper/lroot (depending on the rules).
+No uuid was assigned.
index bf99e2f24788001557194d56d92224fe8411a1e8..205593f56fe759706ea6fd321c08e66059ebd489 100644 (file)
@@ -16,6 +16,11 @@ Required properties:
 - vref-supply: The regulator supply ADC reference voltage.
 - #io-channel-cells: Should be 1, see ../iio-bindings.txt
 
+Optional properties:
+- resets: Must contain an entry for each entry in reset-names if need support
+         this option. See ../reset/reset.txt for details.
+- reset-names: Must include the name "saradc-apb".
+
 Example:
        saradc: saradc@2006c000 {
                compatible = "rockchip,saradc";
@@ -23,6 +28,8 @@ Example:
                interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
                clock-names = "saradc", "apb_pclk";
+               resets = <&cru SRST_SARADC>;
+               reset-names = "saradc-apb";
                #io-channel-cells = <1>;
                vref-supply = <&vcc18>;
        };
diff --git a/Documentation/devicetree/bindings/misc/memory-state-time.txt b/Documentation/devicetree/bindings/misc/memory-state-time.txt
new file mode 100644 (file)
index 0000000..c99a506
--- /dev/null
@@ -0,0 +1,8 @@
+Memory bandwidth and frequency state tracking
+
+Required properties:
+- compatible : should be:
+       "memory-state-time"
+- freq-tbl: Should contain entries with each frequency in Hz.
+- bw-buckets: Should contain upper-bound limits for each bandwidth bucket in Mbps.
+       Must match the framework power_profile.xml for the device.
index d00bfd8624a500eb797aac8273f8fc5f1df3c785..e0381c28773de5ab972a8368012760cbf8ca1b29 100644 (file)
@@ -81,9 +81,9 @@ pm8916:
        l14, l15, l16, l17, l18
 
 pm8941:
-       s1, s2, s3, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14,
-       l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3,
-       mvs1, mvs2
+       s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
+       l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3,
+       5vs1, 5vs2
 
 The content of each sub-node is defined by the standard binding for regulators -
 see regulator.txt - with additional custom properties described below:
index 1c425191574cb3e04a6406fe765ce3ca89c23fce..fea4777a569594d9b4ed7af58f82ddfa0b690dfb 100644 (file)
@@ -347,7 +347,7 @@ address           perms offset  dev   inode      pathname
 a7cb1000-a7cb2000 ---p 00000000 00:00 0
 a7cb2000-a7eb2000 rw-p 00000000 00:00 0
 a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack:1001]
+a7eb3000-a7ed5000 rw-p 00000000 00:00 0
 a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
 a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
 a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
@@ -379,7 +379,6 @@ is not associated with a file:
 
  [heap]                   = the heap of the program
  [stack]                  = the stack of the main process
- [stack:1001]             = the stack of the thread with tid 1001
  [vdso]                   = the "virtual dynamic shared object",
                             the kernel system call handler
  [anon:<name>]            = an anonymous mapping that has been
@@ -389,10 +388,8 @@ is not associated with a file:
 
 The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
 of the individual tasks of a process. In this file you will see a mapping marked
-as [stack] if that task sees it as a stack. This is a key difference from the
-content of /proc/PID/maps, where you will see all mappings that are being used
-as stack by all of those tasks. Hence, for the example above, the task-level
-map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
+as [stack] if that task sees it as a stack. Hence, for the example above, the
+task-level map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
 
 08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
 08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
index 554f3844d4993549943caaccbf706bab7e063178..583935f88ee8247608af8d46c3af6ca16f3ad67f 100644 (file)
@@ -56,6 +56,7 @@ parameter is applicable:
        BLACKFIN Blackfin architecture is enabled.
        CLK     Common clock infrastructure is enabled.
        CMA     Contiguous Memory Area support is enabled.
+       DM      Device mapper support is enabled.
        DRM     Direct Rendering Management support is enabled.
        DYNAMIC_DEBUG Build in debug messages and enable them at runtime
        EDD     BIOS Enhanced Disk Drive Services (EDD) is enabled
@@ -915,6 +916,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        dis_ucode_ldr   [X86] Disable the microcode loader.
 
+       dm=             [DM] Allows early creation of a device-mapper device.
+                       See Documentation/device-mapper/boot.txt.
+
+       dmasound=       [HW,OSS] Sound subsystem buff
+
        dma_debug=off   If the kernel is compiled with DMA_API_DEBUG support,
                        this option disables the debugging code at boot.
 
@@ -1371,7 +1377,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        i8042.nopnp     [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
                             controllers
        i8042.notimeout [HW] Ignore timeout condition signalled by controller
-       i8042.reset     [HW] Reset the controller during init and cleanup
+       i8042.reset     [HW] Reset the controller during init, cleanup and
+                            suspend-to-ram transitions, only during s2r
+                            transitions, or never reset
+                       Format: { 1 | Y | y | 0 | N | n }
+                       1, Y, y: always reset controller
+                       0, N, n: don't ever reset controller
+                       Default: only on s2r transitions on x86; most other
+                       architectures force reset to be always executed
        i8042.unlock    [HW] Unlock (ignore) the keylock
        i8042.kbdreset  [HW] Reset device connected to KBD port
 
index aaeafa18d99bb70bee8cf5bd1d39829b17d6d3d4..c99a75968c011ef802e184f91255842c0b672608 100644 (file)
@@ -1538,9 +1538,9 @@ set_cmdline(struct mic_info *mic)
 
        len = snprintf(buffer, PATH_MAX,
                "clocksource=tsc highres=off nohz=off ");
-       len += snprintf(buffer + len, PATH_MAX,
+       len += snprintf(buffer + len, PATH_MAX - len,
                "cpufreq_on;corec6_off;pc3_off;pc6_off ");
-       len += snprintf(buffer + len, PATH_MAX,
+       len += snprintf(buffer + len, PATH_MAX - len,
                "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0",
                mic->id + 1);
 
index a78bf1ffa68cb4c4defe32146fc75f8449a46245..39b7f612c4184e4b8b5889fa7b6410f80e692589 100644 (file)
@@ -271,3 +271,9 @@ Since the private key is used to sign modules, viruses and malware could use
 the private key to sign modules and compromise the operating system.  The
 private key must be either destroyed or moved to a secure location and not kept
 in the root node of the kernel source tree.
+
+If you use the same private key to sign modules for multiple kernel
+configurations, you must ensure that the module version information is
+sufficient to prevent loading a module into a different kernel.  Either
+set CONFIG_MODVERSIONS=y or ensure that each configuration has a different
+kernel release string by changing EXTRAVERSION or CONFIG_LOCALVERSION.
index 4976389e432d4dd5207d65ad7c37d407c00d9d87..dd15a699ee1cdbb25221481d2d9de1865f775b16 100644 (file)
@@ -831,7 +831,7 @@ separate memory range only intended for GPIO driving, and the register
 range dealing with pin config and pin multiplexing get placed into a
 different memory range and a separate section of the data sheet.
 
-A flag "strict" in struct pinctrl_desc is available to check and deny
+A flag "strict" in struct pinmux_ops is available to check and deny
 simultaneous access to the same pin from GPIO and pin multiplexing
 consumers on hardware of this type. The pinctrl driver should set this flag
 accordingly.
index cb795e643eba1f1bdfb8d4798a3212129bb133da..9bd2231c01b1466a23e49de6cc0f7432474c0c98 100644 (file)
@@ -364,4 +364,3 @@ task is dequeued.
 [1] http://lwn.net/Articles/552889
 [2] http://lkml.org/lkml/2012/5/18/91
 [3] http://lkml.org/lkml/2015/6/26/620
-
index 54944c71b819bd7b37aeb4d221ef02fffd201879..2a4ee6302122f8942ac08f6d26dbdf2f369f4e6e 100644 (file)
@@ -196,3 +196,35 @@ Another, more verbose way of getting PAT related debug messages is with
 "debugpat" boot parameter. With this parameter, various debug messages are
 printed to dmesg log.
 
+PAT Initialization
+------------------
+
+The following table describes how PAT is initialized under various
+configurations. The PAT MSR must be updated by Linux in order to support WC
+and WT attributes. Otherwise, the PAT MSR has the value programmed in it
+by the firmware. Note, Xen enables WC attribute in the PAT MSR for guests.
+
+ MTRR PAT   Call Sequence               PAT State  PAT MSR
+ =========================================================
+ E    E     MTRR -> PAT init            Enabled    OS
+ E    D     MTRR -> PAT init            Disabled    -
+ D    E     MTRR -> PAT disable         Disabled   BIOS
+ D    D     MTRR -> PAT disable         Disabled    -
+ -    np/E  PAT  -> PAT disable         Disabled   BIOS
+ -    np/D  PAT  -> PAT disable         Disabled    -
+ E    !P/E  MTRR -> PAT init            Disabled   BIOS
+ D    !P/E  MTRR -> PAT disable         Disabled   BIOS
+ !M   !P/E  MTRR stub -> PAT disable    Disabled   BIOS
+
+ Legend
+ ------------------------------------------------
+ E         Feature enabled in CPU
+ D        Feature disabled/unsupported in CPU
+ np       "nopat" boot option specified
+ !P       CONFIG_X86_PAT option unset
+ !M       CONFIG_MTRR option unset
+ Enabled   PAT state set to enabled
+ Disabled  PAT state set to disabled
+ OS        PAT initializes PAT MSR with OS setting
+ BIOS      PAT keeps PAT MSR with BIOS setting
+
index bf85ba0fb248214768f2ee984e9e998c449fb7aa..f9d5de6e299bf90509abb43ab68589ac64f4f998 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 4
-SUBLEVEL = 16
+SUBLEVEL = 30
 EXTRAVERSION =
 NAME = Blurry Fish Butt
 
@@ -128,6 +128,10 @@ _all:
 # Cancel implicit rules on top Makefile
 $(CURDIR)/Makefile Makefile: ;
 
+ifneq ($(words $(subst :, ,$(CURDIR))), 1)
+  $(error main directory cannot contain spaces nor colons)
+endif
+
 ifneq ($(KBUILD_OUTPUT),)
 # Invoke a second make in the output directory, passing relevant variables
 # check that the output directory actually exists
@@ -507,6 +511,12 @@ ifeq ($(KBUILD_EXTMOD),)
                 endif
         endif
 endif
+# install and module_install need also be processed one by one
+ifneq ($(filter install,$(MAKECMDGOALS)),)
+        ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
+               mixed-targets := 1
+        endif
+endif
 
 ifeq ($(mixed-targets),1)
 # ===========================================================================
@@ -618,11 +628,16 @@ ARCH_CFLAGS :=
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
+KBUILD_CFLAGS  += $(call cc-disable-warning,maybe-uninitialized,)
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS  += -Os $(call cc-disable-warning,maybe-uninitialized,)
+KBUILD_CFLAGS  += -Os
 else
+ifdef CONFIG_PROFILE_ALL_BRANCHES
 KBUILD_CFLAGS  += -O2
+else
+KBUILD_CFLAGS   += -O2
+endif
 endif
 
 # Tell gcc to never replace conditional load with a non-conditional one
@@ -1277,7 +1292,7 @@ help:
        @echo  '  firmware_install- Install all firmware to INSTALL_FW_PATH'
        @echo  '                    (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
        @echo  '  dir/            - Build all files in dir and below'
-       @echo  '  dir/file.[oisS] - Build specified target only'
+       @echo  '  dir/file.[ois - Build specified target only'
        @echo  '  dir/file.lst    - Build specified mixed source/assembly target only'
        @echo  '                    (requires a recent binutils and recent build (System.map))'
        @echo  '  dir/file.ko     - Build module including final link'
@@ -1517,11 +1532,11 @@ image_name:
 # Clear a bunch of variables before executing the submake
 tools/: FORCE
        $(Q)mkdir -p $(objtree)/tools
-       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/
 
 tools/%: FORCE
        $(Q)mkdir -p $(objtree)/tools
-       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(O) subdir=tools -C $(src)/tools/ $*
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $*
 
 # Single targets
 # ---------------------------------------------------------------------------
index 6496bb3961a2516c0aa73c7ea65eea7386622186..8531a7a79e336d534ecb9fc05d6f952e6d9ce94b 100644 (file)
@@ -24,6 +24,7 @@ CONFIG_DM_VERITY=y
 CONFIG_DM_VERITY_FEC=y
 CONFIG_EMBEDDED=y
 CONFIG_FB=y
+CONFIG_HARDENED_USERCOPY=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_INET6_AH=y
 CONFIG_INET6_ESP=y
@@ -139,8 +140,10 @@ CONFIG_PPP_MPPE=y
 CONFIG_PREEMPT=y
 CONFIG_PROFILING=y
 CONFIG_QUOTA=y
+CONFIG_RANDOMIZE_BASE=y
 CONFIG_RTC_CLASS=y
 CONFIG_RT_GROUP_SCHED=y
+CONFIG_SECCOMP=y
 CONFIG_SECURITY=y
 CONFIG_SECURITY_NETWORK=y
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
index c3222a77ba24a34db0be0a34f19ea8c862761b04..3465a848d74da4e4d0945e64bd2c4080f639b77a 100644 (file)
@@ -11,6 +11,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_CC_STACKPROTECTOR_STRONG=y
 CONFIG_COMPACTION=y
 CONFIG_DEBUG_RODATA=y
 CONFIG_DM_UEVENT=y
@@ -118,6 +119,7 @@ CONFIG_TIMER_STATS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_UHID=y
+CONFIG_MEMORY_STATE_TIME=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_HIDDEV=y
index 31a318a56d98ff6d74c672c906a711d024abb8db..98f64ad1caf1817e5535a223f84412422c20c1ed 100644 (file)
@@ -423,6 +423,15 @@ config CC_STACKPROTECTOR_STRONG
 
 endchoice
 
+config HAVE_ARCH_WITHIN_STACK_FRAMES
+       bool
+       help
+         An architecture should select this if it can walk the kernel stack
+         frames to determine if an object is part of either the arguments
+         or local variables (i.e. that it excludes saved return addresses,
+         and similar) by implementing an inline arch_within_stack_frames(),
+         which is used by CONFIG_HARDENED_USERCOPY.
+
 config HAVE_CONTEXT_TRACKING
        bool
        help
index 9b0d40093c9a377ff142ffe2241c44b152e41ffd..c0ddbbf73400eb8bf5cd123f6891b35fa604cc6e 100644 (file)
@@ -371,14 +371,6 @@ __copy_tofrom_user_nocheck(void *to, const void *from, long len)
        return __cu_len;
 }
 
-extern inline long
-__copy_tofrom_user(void *to, const void *from, long len, const void __user *validate)
-{
-       if (__access_ok((unsigned long)validate, len, get_fs()))
-               len = __copy_tofrom_user_nocheck(to, from, len);
-       return len;
-}
-
 #define __copy_to_user(to, from, n)                                    \
 ({                                                                     \
        __chk_user_ptr(to);                                             \
@@ -393,17 +385,22 @@ __copy_tofrom_user(void *to, const void *from, long len, const void __user *vali
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
-
 extern inline long
 copy_to_user(void __user *to, const void *from, long n)
 {
-       return __copy_tofrom_user((__force void *)to, from, n, to);
+       if (likely(__access_ok((unsigned long)to, n, get_fs())))
+               n = __copy_tofrom_user_nocheck((__force void *)to, from, n);
+       return n;
 }
 
 extern inline long
 copy_from_user(void *to, const void __user *from, long n)
 {
-       return __copy_tofrom_user(to, (__force void *)from, n, from);
+       if (likely(__access_ok((unsigned long)from, n, get_fs())))
+               n = __copy_tofrom_user_nocheck(to, (__force void *)from, n);
+       else
+               memset(to, 0, n);
+       return n;
 }
 
 extern void __do_clear_user(void);
index aeb19021099e315967ba95524e9528c48da0d159..c05ea2b54276293b8ed250ca23b39260aed2e4f1 100644 (file)
@@ -18,6 +18,20 @@ cflags-y     += -fno-common -pipe -fno-builtin -D__linux__
 cflags-$(CONFIG_ISA_ARCOMPACT) += -mA7
 cflags-$(CONFIG_ISA_ARCV2)     += -mcpu=archs
 
+is_700 = $(shell $(CC) -dM -E - < /dev/null | grep -q "ARC700" && echo 1 || echo 0)
+
+ifdef CONFIG_ISA_ARCOMPACT
+ifeq ($(is_700), 0)
+    $(error Toolchain not configured for ARCompact builds)
+endif
+endif
+
+ifdef CONFIG_ISA_ARCV2
+ifeq ($(is_700), 1)
+    $(error Toolchain not configured for ARCv2 builds)
+endif
+endif
+
 ifdef CONFIG_ARC_CURR_IN_REG
 # For a global register defintion, make sure it gets passed to every file
 # We had a customer reported bug where some code built in kernel was NOT using
@@ -48,8 +62,6 @@ endif
 
 endif
 
-cflags-$(CONFIG_ARC_DW2_UNWIND)                += -fasynchronous-unwind-tables
-
 # By default gcc 4.8 generates dwarf4 which kernel unwinder can't grok
 ifeq ($(atleast_gcc48),y)
 cflags-$(CONFIG_ARC_DW2_UNWIND)                += -gdwarf-2
index 7fac7d85ed6a32bb1abaa4f8e36c5d243cec06c0..2c30a016cf15aaec932427ef77bf6dd2f53e1069 100644 (file)
@@ -374,12 +374,6 @@ static inline int is_isa_arcompact(void)
        return IS_ENABLED(CONFIG_ISA_ARCOMPACT);
 }
 
-#if defined(CONFIG_ISA_ARCOMPACT) && !defined(_CPU_DEFAULT_A7)
-#error "Toolchain not configured for ARCompact builds"
-#elif defined(CONFIG_ISA_ARCV2) && !defined(_CPU_DEFAULT_HS)
-#error "Toolchain not configured for ARCv2 builds"
-#endif
-
 #endif /* __ASEMBLY__ */
 
 #endif /* _ASM_ARC_ARCREGS_H */
index ad7860c5ce153c731264f770067e653b70568fd5..51597f344a62aced8c98cb2035c9ec40eff55e6e 100644 (file)
 
 #ifdef CONFIG_ARC_CURR_IN_REG
        ; Retrieve orig r25 and save it with rest of callee_regs
-       ld.as   r12, [r12, PT_user_r25]
+       ld      r12, [r12, PT_user_r25]
        PUSH    r12
 #else
        PUSH    r25
 
        ; SP is back to start of pt_regs
 #ifdef CONFIG_ARC_CURR_IN_REG
-       st.as   r12, [sp, PT_user_r25]
+       st      r12, [sp, PT_user_r25]
 #endif
 .endm
 
index c1d36458bfb7aa665acb30a2234660034a19aecd..4c6eed80cd8ba3bd935e60b30ffadf147326aeca 100644 (file)
@@ -188,10 +188,10 @@ static inline int arch_irqs_disabled(void)
 .endm
 
 .macro IRQ_ENABLE  scratch
+       TRACE_ASM_IRQ_ENABLE
        lr      \scratch, [status32]
        or      \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
        flag    \scratch
-       TRACE_ASM_IRQ_ENABLE
 .endm
 
 #endif /* __ASSEMBLY__ */
index 57af2f05ae8459e2ee2427d231370269894ba95f..e5fec320f158e51ba6519dd7ee3ef71725943d8c 100644 (file)
 #define ___DEF (_PAGE_PRESENT | _PAGE_CACHEABLE)
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SPECIAL)
 
 /* More Abbrevaited helpers */
 #define PAGE_U_NONE     __pgprot(___DEF)
@@ -277,8 +277,7 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
 
 #define mk_pte(page, prot)     pfn_pte(page_to_pfn(page), prot)
 #define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)
-#define pfn_pte(pfn, prot)     (__pte(((pte_t)(pfn) << PAGE_SHIFT) | \
-                                pgprot_val(prot)))
+#define pfn_pte(pfn, prot)     (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)))
 #define __pte_index(addr)      (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 
 /*
index d1da6032b715a7fea35d71fcedeeeb8cdfe590e4..d4d8df706efa738ae115ddf68b37dad2d8d271c9 100644 (file)
        "2:     ;nop\n"                         \
        "       .section .fixup, \"ax\"\n"      \
        "       .align 4\n"                     \
-       "3:     mov %0, %3\n"                   \
+       "3:     # return -EFAULT\n"             \
+       "       mov %0, %3\n"                   \
+       "       # zero out dst ptr\n"           \
+       "       mov %1,  0\n"                   \
        "       j   2b\n"                       \
        "       .previous\n"                    \
        "       .section __ex_table, \"a\"\n"   \
        "2:     ;nop\n"                         \
        "       .section .fixup, \"ax\"\n"      \
        "       .align 4\n"                     \
-       "3:     mov %0, %3\n"                   \
+       "3:     # return -EFAULT\n"             \
+       "       mov %0, %3\n"                   \
+       "       # zero out dst ptr\n"           \
+       "       mov %1,  0\n"                   \
+       "       mov %R1, 0\n"                   \
        "       j   2b\n"                       \
        "       .previous\n"                    \
        "       .section __ex_table, \"a\"\n"   \
index 004b7f0bc76cc58c6988547df1bb8705cd36004d..257b8699efde4f7557b35d8eec2252b7db4903fd 100644 (file)
@@ -107,13 +107,13 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        struct user_regs_struct uregs;
 
        err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
-       if (!err)
-               set_current_blocked(&set);
-
        err |= __copy_from_user(&uregs.scratch,
                                &(sf->uc.uc_mcontext.regs.scratch),
                                sizeof(sf->uc.uc_mcontext.regs.scratch));
+       if (err)
+               return err;
 
+       set_current_blocked(&set);
        regs->bta       = uregs.scratch.bta;
        regs->lp_start  = uregs.scratch.lp_start;
        regs->lp_end    = uregs.scratch.lp_end;
@@ -138,7 +138,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)
        regs->r0        = uregs.scratch.r0;
        regs->sp        = uregs.scratch.sp;
 
-       return err;
+       return 0;
 }
 
 static inline int is_do_ss_needed(unsigned int magic)
index 001de4ce711eae2b095451a52f68e77db3d81ef4..11b50959f20ed38a18d6edbe9d7da969a1970f54 100644 (file)
@@ -142,7 +142,7 @@ arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
         * prelogue is setup (callee regs saved and then fp set and not other
         * way around
         */
-       pr_warn("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
+       pr_warn_once("CONFIG_ARC_DW2_UNWIND needs to be enabled\n");
        return 0;
 
 #endif
index ff7ff6cbb8112408c05a38a2f8e001265d5d3726..aaf1e2d1d9003c01b7040a611488dcb9d24d3d3e 100644 (file)
@@ -914,6 +914,15 @@ void arc_cache_init(void)
 
        printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
 
+       /*
+        * Only master CPU needs to execute rest of function:
+        *  - Assume SMP so all cores will have same cache config so
+        *    any geomtry checks will be same for all
+        *  - IOC setup / dma callbacks only need to be setup once
+        */
+       if (cpu)
+               return;
+
        if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
                struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
 
index 6f0b7b752328b702eda19f8825a05f5af738b523..868a5f2a1cce20b898258fb0d8d5c02bacf17adb 100644 (file)
@@ -36,6 +36,7 @@ config ARM
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
        select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
        select HAVE_ARCH_MMAP_RND_BITS if MMU
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARM_SMCCC if CPU_V7
index ae85dcdcb7df105abdc399ce619c5413c0b63f5d..d2e43b053d9b61b7ab90478d8c41041b9457baa0 100644 (file)
@@ -776,7 +776,7 @@ __armv7_mmu_cache_on:
                orrne   r0, r0, #1              @ MMU enabled
                movne   r1, #0xfffffffd         @ domain 0 = client
                bic     r6, r6, #1 << 31        @ 32-bit translation system
-               bic     r6, r6, #3 << 0         @ use only ttbr0
+               bic     r6, r6, #(7 << 0) | (1 << 4)    @ use only ttbr0
                mcrne   p15, 0, r3, c2, c0, 0   @ load page table pointer
                mcrne   p15, 0, r0, c8, c7, 0   @ flush I,D TLBs
                mcr     p15, 0, r0, c7, c5, 4   @ ISB
index 094e39c660390440501dce7e64dfdda4b8268a37..6cd18d8aaac795606f06862a107c7b06ec700bce 100644 (file)
@@ -47,6 +47,8 @@
 #include "armada-39x.dtsi"
 
 / {
+       compatible = "marvell,armada390";
+
        soc {
                internal-regs {
                        pinctrl@18000 {
@@ -54,4 +56,5 @@
                                reg = <0x18000 0x20>;
                        };
                };
+       };
 };
index 2b6cc8bf3c5cce97349f2385e5dfba1009b5df0a..e6af41c4bbc129cef7dc82b74ed8ef180f5e20ef 100644 (file)
                                        clocks = <&clks IMX6QDL_CLK_SPDIF_GCLK>, <&clks IMX6QDL_CLK_OSC>,
                                                 <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_ASRC>,
                                                 <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_ESAI_EXTAL>,
-                                                <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_MLB>,
+                                                <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_DUMMY>,
                                                 <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_SPBA>;
                                        clock-names = "core",  "rxtx0",
                                                      "rxtx1", "rxtx2",
index bfa5edde179c30d38d55cb80dd462dc6c3ee8084..2c1e7f09205f5120cb222deb98ec223b539e5e82 100644 (file)
 
        partition@e0000 {
                label = "u-boot environment";
-               reg = <0xe0000 0x100000>;
+               reg = <0xe0000 0x20000>;
        };
 
        partition@100000 {
index a29ad16cc9bbddec399cef41a00106bc636a14a0..64c5af30c1d0df0047bd62024d48d50fe4e218c1 100644 (file)
 };
 
 &gpmc {
-       ranges = <0 0 0x00000000 0x20000000>;
+       ranges = <0 0 0x30000000 0x1000000>,    /* CS0 */
+                <4 0 0x2b000000 0x1000000>,    /* CS4 */
+                <5 0 0x2c000000 0x1000000>;    /* CS5 */
 
        nand@0,0 {
                linux,mtd-name= "micron,mt29c4g96maz";
index 17b82f82638a97e5e6157fc0c9c16d156de962eb..64047788216b5b7e8a2e828d6261e144f69c6b7b 100644 (file)
@@ -55,8 +55,6 @@
 #include "omap-gpmc-smsc9221.dtsi"
 
 &gpmc {
-       ranges = <5 0 0x2c000000 0x1000000>;    /* CS5 */
-
        ethernet@gpmc {
                reg = <5 0 0xff>;
                interrupt-parent = <&gpio6>;
index 9e24b6a1d07b8e4d02b6d0704858680015f0069b..1b304e2f1bd2fd4fd5be23dafcd0f364991fd131 100644 (file)
@@ -27,8 +27,6 @@
 #include "omap-gpmc-smsc9221.dtsi"
 
 &gpmc {
-       ranges = <5 0 0x2c000000 0x1000000>;    /* CS5 */
-
        ethernet@gpmc {
                reg = <5 0 0xff>;
                interrupt-parent = <&gpio6>;
index 334109e14613d6eb3a406f69eb56dce2f9f445c4..82e98ee3023ada85319d96c22da2ac985216b04f 100644 (file)
@@ -15,9 +15,6 @@
 #include "omap-gpmc-smsc9221.dtsi"
 
 &gpmc {
-       ranges = <4 0 0x2b000000 0x1000000>,    /* CS4 */
-                <5 0 0x2c000000 0x1000000>;    /* CS5 */
-
        smsc1: ethernet@gpmc {
                reg = <5 0 0xff>;
                interrupt-parent = <&gpio6>;
index a4c1762b53ea3712a46e5f8a04cff5783d93b14d..e00d50ef678fa7635b516a3ad07964bc43c27a1a 100644 (file)
@@ -5,6 +5,7 @@
 #include <dt-bindings/reset/qcom,gcc-msm8960.h>
 #include <dt-bindings/clock/qcom,mmcc-msm8960.h>
 #include <dt-bindings/soc/qcom,gsbi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 / {
        model = "Qualcomm APQ8064";
 
                                        compatible = "qcom,pm8921-gpio";
                                        reg = <0x150>;
-                                       interrupts = <192 1>, <193 1>, <194 1>,
-                                                    <195 1>, <196 1>, <197 1>,
-                                                    <198 1>, <199 1>, <200 1>,
-                                                    <201 1>, <202 1>, <203 1>,
-                                                    <204 1>, <205 1>, <206 1>,
-                                                    <207 1>, <208 1>, <209 1>,
-                                                    <210 1>, <211 1>, <212 1>,
-                                                    <213 1>, <214 1>, <215 1>,
-                                                    <216 1>, <217 1>, <218 1>,
-                                                    <219 1>, <220 1>, <221 1>,
-                                                    <222 1>, <223 1>, <224 1>,
-                                                    <225 1>, <226 1>, <227 1>,
-                                                    <228 1>, <229 1>, <230 1>,
-                                                    <231 1>, <232 1>, <233 1>,
-                                                    <234 1>, <235 1>;
-
+                                       interrupts = <192 IRQ_TYPE_NONE>,
+                                                    <193 IRQ_TYPE_NONE>,
+                                                    <194 IRQ_TYPE_NONE>,
+                                                    <195 IRQ_TYPE_NONE>,
+                                                    <196 IRQ_TYPE_NONE>,
+                                                    <197 IRQ_TYPE_NONE>,
+                                                    <198 IRQ_TYPE_NONE>,
+                                                    <199 IRQ_TYPE_NONE>,
+                                                    <200 IRQ_TYPE_NONE>,
+                                                    <201 IRQ_TYPE_NONE>,
+                                                    <202 IRQ_TYPE_NONE>,
+                                                    <203 IRQ_TYPE_NONE>,
+                                                    <204 IRQ_TYPE_NONE>,
+                                                    <205 IRQ_TYPE_NONE>,
+                                                    <206 IRQ_TYPE_NONE>,
+                                                    <207 IRQ_TYPE_NONE>,
+                                                    <208 IRQ_TYPE_NONE>,
+                                                    <209 IRQ_TYPE_NONE>,
+                                                    <210 IRQ_TYPE_NONE>,
+                                                    <211 IRQ_TYPE_NONE>,
+                                                    <212 IRQ_TYPE_NONE>,
+                                                    <213 IRQ_TYPE_NONE>,
+                                                    <214 IRQ_TYPE_NONE>,
+                                                    <215 IRQ_TYPE_NONE>,
+                                                    <216 IRQ_TYPE_NONE>,
+                                                    <217 IRQ_TYPE_NONE>,
+                                                    <218 IRQ_TYPE_NONE>,
+                                                    <219 IRQ_TYPE_NONE>,
+                                                    <220 IRQ_TYPE_NONE>,
+                                                    <221 IRQ_TYPE_NONE>,
+                                                    <222 IRQ_TYPE_NONE>,
+                                                    <223 IRQ_TYPE_NONE>,
+                                                    <224 IRQ_TYPE_NONE>,
+                                                    <225 IRQ_TYPE_NONE>,
+                                                    <226 IRQ_TYPE_NONE>,
+                                                    <227 IRQ_TYPE_NONE>,
+                                                    <228 IRQ_TYPE_NONE>,
+                                                    <229 IRQ_TYPE_NONE>,
+                                                    <230 IRQ_TYPE_NONE>,
+                                                    <231 IRQ_TYPE_NONE>,
+                                                    <232 IRQ_TYPE_NONE>,
+                                                    <233 IRQ_TYPE_NONE>,
+                                                    <234 IRQ_TYPE_NONE>,
+                                                    <235 IRQ_TYPE_NONE>;
                                        gpio-controller;
                                        #gpio-cells = <2>;
 
                                        gpio-controller;
                                        #gpio-cells = <2>;
                                        interrupts =
-                                       <128 1>, <129 1>, <130 1>, <131 1>,
-                                       <132 1>, <133 1>, <134 1>, <135 1>,
-                                       <136 1>, <137 1>, <138 1>, <139 1>;
+                                       <128 IRQ_TYPE_NONE>,
+                                       <129 IRQ_TYPE_NONE>,
+                                       <130 IRQ_TYPE_NONE>,
+                                       <131 IRQ_TYPE_NONE>,
+                                       <132 IRQ_TYPE_NONE>,
+                                       <133 IRQ_TYPE_NONE>,
+                                       <134 IRQ_TYPE_NONE>,
+                                       <135 IRQ_TYPE_NONE>,
+                                       <136 IRQ_TYPE_NONE>,
+                                       <137 IRQ_TYPE_NONE>,
+                                       <138 IRQ_TYPE_NONE>,
+                                       <139 IRQ_TYPE_NONE>;
                                };
 
                                rtc@11d {
index 81f81214cdf9580a0cb19ce01d8bfc5e01417252..bbf95375cf99876cf5a465b955046aca4419076d 100644 (file)
                        interrupt-names = "mmcirq";
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_mmc0>;
-                       clock-names = "mmc";
-                       clocks = <&clk_s_c0_flexgen CLK_MMC_0>;
+                       clock-names = "mmc", "icn";
+                       clocks = <&clk_s_c0_flexgen CLK_MMC_0>,
+                                <&clk_s_c0_flexgen CLK_RX_ICN_HVA>;
                        bus-width = <8>;
                        non-removable;
                };
                        interrupt-names = "mmcirq";
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_sd1>;
-                       clock-names = "mmc";
-                       clocks = <&clk_s_c0_flexgen CLK_MMC_1>;
+                       clock-names = "mmc", "icn";
+                       clocks = <&clk_s_c0_flexgen CLK_MMC_1>,
+                                <&clk_s_c0_flexgen CLK_RX_ICN_HVA>;
                        resets = <&softreset STIH407_MMC1_SOFTRESET>;
                        bus-width = <4>;
                };
index 18ed1ad10d32bbb251746e3011c541f9cfcbc861..40318869c733668a15e3d318ff291c3221336125 100644 (file)
@@ -41,7 +41,8 @@
                        compatible = "st,st-ohci-300x";
                        reg = <0x9a03c00 0x100>;
                        interrupts = <GIC_SPI 180 IRQ_TYPE_NONE>;
-                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+                                <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
                        resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>,
                                 <&softreset STIH407_USB2_PORT0_SOFTRESET>;
                        reset-names = "power", "softreset";
@@ -57,7 +58,8 @@
                        interrupts = <GIC_SPI 151 IRQ_TYPE_NONE>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_usb0>;
-                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+                                <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
                        resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>,
                                 <&softreset STIH407_USB2_PORT0_SOFTRESET>;
                        reset-names = "power", "softreset";
@@ -71,7 +73,8 @@
                        compatible = "st,st-ohci-300x";
                        reg = <0x9a83c00 0x100>;
                        interrupts = <GIC_SPI 181 IRQ_TYPE_NONE>;
-                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+                                <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
                        resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>,
                                 <&softreset STIH407_USB2_PORT1_SOFTRESET>;
                        reset-names = "power", "softreset";
@@ -87,7 +90,8 @@
                        interrupts = <GIC_SPI 153 IRQ_TYPE_NONE>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_usb1>;
-                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+                       clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
+                                <&clk_s_c0_flexgen CLK_RX_ICN_DISP_0>;
                        resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>,
                                 <&softreset STIH407_USB2_PORT1_SOFTRESET>;
                        reset-names = "power", "softreset";
index 97570cb7f2fcdb37cac323d3da1529a246314d2c..1d23527d4ecffe5f96ee7cc67b518dc5140a008b 100644 (file)
@@ -84,6 +84,7 @@
                regulator-name = "emac-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               startup-delay-us = <20000>;
                enable-active-high;
                gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>;
        };
index 2b17c519915165cf821d3c86d5af4ee634eab1f9..6de83a6187d0b51a296d457778b98af2b6d813fa 100644 (file)
@@ -66,6 +66,7 @@
                regulator-name = "emac-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               startup-delay-us = <20000>;
                enable-active-high;
                gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>;
        };
index 7afc7a64eef1df3e0af47f01b2a26f9f34cefd37..e28f080b1fd594aab9e82ed4a00454b625f4bc3a 100644 (file)
@@ -80,6 +80,7 @@
                regulator-name = "emac-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               startup-delay-us = <20000>;
                enable-active-high;
                gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>;   /* PH19 */
        };
index 9fea918f949ec1ca8c0a0af1839d1c080ffa2580..39731a78f087f0d705e80b590eb151bb24054af0 100644 (file)
@@ -79,6 +79,7 @@
                regulator-name = "emac-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
+               startup-delay-us = <20000>;
                enable-active-high;
                gpio = <&pio 0 2 GPIO_ACTIVE_HIGH>;
        };
index d910d3a6c41c573c83e6c20898cabf072a79ae9b..84bdba480d5af40c9df19899a6247bdf0ea19b9e 100644 (file)
@@ -83,7 +83,7 @@
                        trips {
                                cpu_alert0: cpu_alert0 {
                                        /* milliCelsius */
-                                       temperature = <850000>;
+                                       temperature = <85000>;
                                        hysteresis = <2000>;
                                        type = "passive";
                                };
index 3d224941b5419e88a25aae2ae70632dba047606c..a3a9ad4dc3c66719413dc72ec07425023f48b800 100644 (file)
@@ -869,9 +869,9 @@ struct sa1111_save_data {
 
 #ifdef CONFIG_PM
 
-static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
+static int sa1111_suspend_noirq(struct device *dev)
 {
-       struct sa1111 *sachip = platform_get_drvdata(dev);
+       struct sa1111 *sachip = dev_get_drvdata(dev);
        struct sa1111_save_data *save;
        unsigned long flags;
        unsigned int val;
@@ -934,9 +934,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
  *     restored by their respective drivers, and must be called
  *     via LDM after this function.
  */
-static int sa1111_resume(struct platform_device *dev)
+static int sa1111_resume_noirq(struct device *dev)
 {
-       struct sa1111 *sachip = platform_get_drvdata(dev);
+       struct sa1111 *sachip = dev_get_drvdata(dev);
        struct sa1111_save_data *save;
        unsigned long flags, id;
        void __iomem *base;
@@ -952,7 +952,7 @@ static int sa1111_resume(struct platform_device *dev)
        id = sa1111_readl(sachip->base + SA1111_SKID);
        if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
                __sa1111_remove(sachip);
-               platform_set_drvdata(dev, NULL);
+               dev_set_drvdata(dev, NULL);
                kfree(save);
                return 0;
        }
@@ -1003,8 +1003,8 @@ static int sa1111_resume(struct platform_device *dev)
 }
 
 #else
-#define sa1111_suspend NULL
-#define sa1111_resume  NULL
+#define sa1111_suspend_noirq NULL
+#define sa1111_resume_noirq  NULL
 #endif
 
 static int sa1111_probe(struct platform_device *pdev)
@@ -1038,6 +1038,11 @@ static int sa1111_remove(struct platform_device *pdev)
        return 0;
 }
 
+static struct dev_pm_ops sa1111_pm_ops = {
+       .suspend_noirq = sa1111_suspend_noirq,
+       .resume_noirq = sa1111_resume_noirq,
+};
+
 /*
  *     Not sure if this should be on the system bus or not yet.
  *     We really want some way to register a system device at
@@ -1050,10 +1055,9 @@ static int sa1111_remove(struct platform_device *pdev)
 static struct platform_driver sa1111_device_driver = {
        .probe          = sa1111_probe,
        .remove         = sa1111_remove,
-       .suspend        = sa1111_suspend,
-       .resume         = sa1111_resume,
        .driver         = {
                .name   = "sa1111",
+               .pm     = &sa1111_pm_ops,
        },
 };
 
index b445a5d56f4342b71540e40c1ce298e0ad786688..593da7ffb449de02acf399a922ea1105225b7afc 100644 (file)
@@ -279,7 +279,7 @@ static int ctr_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                err = blkcipher_walk_done(desc, &walk,
                                          walk.nbytes % AES_BLOCK_SIZE);
        }
-       if (nbytes) {
+       if (walk.nbytes % AES_BLOCK_SIZE) {
                u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
                u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE;
                u8 __aligned(8) tail[AES_BLOCK_SIZE];
index 03a39fe2924648f91c45224c84d1a883e433a6dc..9d9ba9acdddcd3622131270679a7f72e2fa0901a 100644 (file)
@@ -226,6 +226,27 @@ static int ghash_async_digest(struct ahash_request *req)
        }
 }
 
+static int ghash_async_import(struct ahash_request *req, const void *in)
+{
+       struct ahash_request *cryptd_req = ahash_request_ctx(req);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+       struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+       struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+
+       desc->tfm = cryptd_ahash_child(ctx->cryptd_tfm);
+       desc->flags = req->base.flags;
+
+       return crypto_shash_import(desc, in);
+}
+
+static int ghash_async_export(struct ahash_request *req, void *out)
+{
+       struct ahash_request *cryptd_req = ahash_request_ctx(req);
+       struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+
+       return crypto_shash_export(desc, out);
+}
+
 static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
                              unsigned int keylen)
 {
@@ -274,7 +295,10 @@ static struct ahash_alg ghash_async_alg = {
        .final                  = ghash_async_final,
        .setkey                 = ghash_async_setkey,
        .digest                 = ghash_async_digest,
+       .import                 = ghash_async_import,
+       .export                 = ghash_async_export,
        .halg.digestsize        = GHASH_DIGEST_SIZE,
+       .halg.statesize         = sizeof(struct ghash_desc_ctx),
        .halg.base              = {
                .cra_name       = "ghash",
                .cra_driver_name = "ghash-ce",
index f2724f0cdbfc0cbfa29d37bccb53ce34335b211c..51f46b8036b674b782782735308b00b13f5b6f10 100644 (file)
@@ -120,7 +120,7 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
 /* The ARM override for dma_max_pfn() */
 static inline unsigned long dma_max_pfn(struct device *dev)
 {
-       return PHYS_PFN_OFFSET + dma_to_pfn(dev, *dev->dma_mask);
+       return dma_to_pfn(dev, *dev->dma_mask);
 }
 #define dma_max_pfn(dev) dma_max_pfn(dev)
 
index fd929b5ded9e2eb1cb313af62451d0efdd4e2ede..9459ca85bd20c6301a490d2ff9a96446abd550c2 100644 (file)
@@ -250,6 +250,7 @@ PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
 PMD_BIT_FUNC(mksplitting, |= L_PMD_SECT_SPLITTING);
 PMD_BIT_FUNC(mkwrite,   &= ~L_PMD_SECT_RDONLY);
 PMD_BIT_FUNC(mkdirty,   |= L_PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkclean,   &= ~L_PMD_SECT_DIRTY);
 PMD_BIT_FUNC(mkyoung,   |= PMD_SECT_AF);
 
 #define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
index 51622ba7c4a66a91494ecc49be4520fd4b14df88..d3c0c23703b6f90cd2863323462dfbb8da9f13e6 100644 (file)
@@ -121,7 +121,6 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 #define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0))
 
 extern int regs_query_register_offset(const char *name);
-extern const char *regs_query_register_name(unsigned int offset);
 extern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr);
 extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
                                               unsigned int n);
index e3e596cbb1a74433c63c9044962cd462d36e7f8a..d0606412069492767c5f62158e4f9b24ee073570 100644 (file)
@@ -3,6 +3,7 @@
 
 #ifdef CONFIG_ARM_CPU_TOPOLOGY
 
+#include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 
 struct cputopo_arm {
@@ -25,7 +26,6 @@ void store_cpu_topology(unsigned int cpuid);
 const struct cpumask *cpu_coregroup_mask(int cpu);
 
 #ifdef CONFIG_CPU_FREQ
-#include <linux/cpufreq.h>
 #define arch_scale_freq_capacity cpufreq_scale_freq_capacity
 #endif
 #define arch_scale_cpu_capacity scale_cpu_capacity
index 35c9db857ebe9c7d53715ec42518a6e9fbe1dc6e..7fb59199c6bbbebc03fafbff1c8083aa5892de91 100644 (file)
@@ -496,7 +496,10 @@ arm_copy_from_user(void *to, const void __user *from, unsigned long n);
 static inline unsigned long __must_check
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       unsigned int __ua_flags = uaccess_save_and_enable();
+       unsigned int __ua_flags;
+
+       check_object_size(to, n, false);
+       __ua_flags = uaccess_save_and_enable();
        n = arm_copy_from_user(to, from, n);
        uaccess_restore(__ua_flags);
        return n;
@@ -511,11 +514,15 @@ static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 #ifndef CONFIG_UACCESS_WITH_MEMCPY
-       unsigned int __ua_flags = uaccess_save_and_enable();
+       unsigned int __ua_flags;
+
+       check_object_size(from, n, true);
+       __ua_flags = uaccess_save_and_enable();
        n = arm_copy_to_user(to, from, n);
        uaccess_restore(__ua_flags);
        return n;
 #else
+       check_object_size(from, n, true);
        return arm_copy_to_user(to, from, n);
 #endif
 }
index 65addcbf5b308acf5dc584419b90f6c65b28d343..b3b950fc8ea06f86fc476dc4e2025b58ecac176b 100644 (file)
@@ -87,6 +87,8 @@ void __init arm_dt_init_cpu_maps(void)
                return;
 
        for_each_child_of_node(cpus, cpu) {
+               const __be32 *cell;
+               int prop_bytes;
                u32 hwid;
 
                if (of_node_cmp(cpu->type, "cpu"))
@@ -98,7 +100,8 @@ void __init arm_dt_init_cpu_maps(void)
                 * properties is considered invalid to build the
                 * cpu_logical_map.
                 */
-               if (of_property_read_u32(cpu, "reg", &hwid)) {
+               cell = of_get_property(cpu, "reg", &prop_bytes);
+               if (!cell || prop_bytes < sizeof(*cell)) {
                        pr_debug(" * %s missing reg property\n",
                                     cpu->full_name);
                        of_node_put(cpu);
@@ -106,10 +109,15 @@ void __init arm_dt_init_cpu_maps(void)
                }
 
                /*
-                * 8 MSBs must be set to 0 in the DT since the reg property
+                * Bits n:24 must be set to 0 in the DT since the reg property
                 * defines the MPIDR[23:0].
                 */
-               if (hwid & ~MPIDR_HWID_BITMASK) {
+               do {
+                       hwid = be32_to_cpu(*cell++);
+                       prop_bytes -= sizeof(*cell);
+               } while (!hwid && prop_bytes > 0);
+
+               if (prop_bytes || (hwid & ~MPIDR_HWID_BITMASK)) {
                        of_node_put(cpu);
                        return;
                }
index 20edd349d379f22c583438db7fbf52f46e1133ef..bf63b4693457c21e84b8df86c3af69d3745930d8 100644 (file)
@@ -772,7 +772,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
        struct resource *res;
 
        kernel_code.start   = virt_to_phys(_text);
-       kernel_code.end     = virt_to_phys(_etext - 1);
+       kernel_code.end     = virt_to_phys(__init_begin - 1);
        kernel_data.start   = virt_to_phys(_sdata);
        kernel_data.end     = virt_to_phys(_end - 1);
 
index 087acb569b63a4bd90982e0c9b15fc2313636c53..5f221acd21aebb3ca1c2ee560fb68241bc1e02c9 100644 (file)
@@ -279,8 +279,12 @@ asmlinkage long sys_oabi_epoll_wait(int epfd,
        mm_segment_t fs;
        long ret, err, i;
 
-       if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event)))
+       if (maxevents <= 0 ||
+                       maxevents > (INT_MAX/sizeof(*kbuf)) ||
+                       maxevents > (INT_MAX/sizeof(*events)))
                return -EINVAL;
+       if (!access_ok(VERIFY_WRITE, events, sizeof(*events) * maxevents))
+               return -EFAULT;
        kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
        if (!kbuf)
                return -ENOMEM;
@@ -317,6 +321,8 @@ asmlinkage long sys_oabi_semtimedop(int semid,
 
        if (nsops < 1 || nsops > SEMOPM)
                return -EINVAL;
+       if (!access_ok(VERIFY_READ, tsops, sizeof(*tsops) * nsops))
+               return -EFAULT;
        sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
        if (!sops)
                return -ENOMEM;
index f5941004efbac97855237061f5ab4cdd2d0d1780..4f2c51ef162d4c6d0eff8b34ca7d96a2e39de117 100644 (file)
@@ -44,7 +44,7 @@ static DEFINE_PER_CPU(unsigned long, cpu_scale);
 
 unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu)
 {
-#if CONFIG_CPU_FREQ
+#ifdef CONFIG_CPU_FREQ
        unsigned long max_freq_scale = cpufreq_scale_max_freq_capacity(cpu);
 
        return per_cpu(cpu_scale, cpu) * max_freq_scale >> SCHED_CAPACITY_SHIFT;
index 8b60fde5ce48a628e5d1f2c682d2aa0684ed6642..be2ab6d3b91f67d6b04e0d446776f5475eac4c7b 100644 (file)
@@ -120,6 +120,8 @@ SECTIONS
 #ifdef CONFIG_DEBUG_RODATA
        . = ALIGN(1<<SECTION_SHIFT);
 #endif
+       _etext = .;                     /* End of text section */
+
        RO_DATA(PAGE_SIZE)
 
        . = ALIGN(4);
@@ -150,8 +152,6 @@ SECTIONS
 
        NOTES
 
-       _etext = .;                     /* End of text and rodata section */
-
 #ifndef CONFIG_XIP_KERNEL
 # ifdef CONFIG_ARM_KERNMEM_PERMS
        . = ALIGN(1<<SECTION_SHIFT);
index 70e6d557c75f696e537fe2a48bb4cc55721a6f8c..c17cb14f368b5b93924d683cb21e818a60dabcf8 100644 (file)
@@ -155,8 +155,6 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 {
        int i;
 
-       kvm_free_stage2_pgd(kvm);
-
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                if (kvm->vcpus[i]) {
                        kvm_arch_vcpu_free(kvm->vcpus[i]);
index 12d727fae0a7592d3d4ca947ea0507d2fb01c63d..11b6595c26723b511341214e13e1a92fe214a0b2 100644 (file)
@@ -1852,6 +1852,7 @@ void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots)
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
 {
+       kvm_free_stage2_pgd(kvm);
 }
 
 void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
index 4470376af5f815fd5f8f2d12c5e7d18306675bb4..a19d20f23e716678625c0963a52b0c00cf0b7b4e 100644 (file)
@@ -295,7 +295,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
                val &= ~BM_CLPCR_SBYOS;
                if (cpu_is_imx6sl())
                        val |= BM_CLPCR_BYPASS_PMIC_READY;
-               if (cpu_is_imx6sl() || cpu_is_imx6sx())
+               if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
                        val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
                else
                        val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
@@ -310,7 +310,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
                val |= 0x3 << BP_CLPCR_STBY_COUNT;
                val |= BM_CLPCR_VSTBY;
                val |= BM_CLPCR_SBYOS;
-               if (cpu_is_imx6sl())
+               if (cpu_is_imx6sl() || cpu_is_imx6sx())
                        val |= BM_CLPCR_BYPASS_PMIC_READY;
                if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
                        val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
index 907a452b78ea240b07d061993d4355b0dbde01a4..b31ad596be795454817242daefddf29179feef3d 100644 (file)
@@ -1474,6 +1474,7 @@ static void omap_hwmod_am43xx_rst(void)
 {
        RSTCTRL(am33xx_pruss_hwmod, AM43XX_RM_PER_RSTCTRL_OFFSET);
        RSTCTRL(am33xx_gfx_hwmod, AM43XX_RM_GFX_RSTCTRL_OFFSET);
+       RSTST(am33xx_pruss_hwmod, AM43XX_RM_PER_RSTST_OFFSET);
        RSTST(am33xx_gfx_hwmod, AM43XX_RM_GFX_RSTST_OFFSET);
 }
 
index aff78d5198d21cad56f0986814ea161485374de3..131f8967589b723cbcb374159c756203b96d7e47 100644 (file)
@@ -723,8 +723,20 @@ static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
  * display serial interface controller
  */
 
+static struct omap_hwmod_class_sysconfig omap3xxx_dsi_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
 static struct omap_hwmod_class omap3xxx_dsi_hwmod_class = {
        .name = "dsi",
+       .sysc   = &omap3xxx_dsi_sysc,
 };
 
 static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
index 7c34c44eb0ae531b17a29f8bea872b59bde04c3d..babb5db5a3a407a4d0ba36bdd71dede87a240864 100644 (file)
@@ -39,6 +39,7 @@
 
 /* RM RSTST offsets */
 #define AM43XX_RM_GFX_RSTST_OFFSET                     0x0014
+#define AM43XX_RM_PER_RSTST_OFFSET                     0x0014
 #define AM43XX_RM_WKUP_RSTST_OFFSET                    0x0014
 
 /* CM instances */
index f6d02e4cbcda4e06954c1c960a54b945e28fe58b..5c87dff5d46ee04f9fe2060152f1ca12ab3f1d86 100644 (file)
@@ -83,7 +83,8 @@ static struct resource smc91x_resources[] = {
 };
 
 static struct smc91x_platdata smc91x_platdata = {
-       .flags = SMC91X_USE_32BIT | SMC91X_USE_DMA | SMC91X_NOWAIT,
+       .flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+                SMC91X_USE_DMA | SMC91X_NOWAIT,
 };
 
 static struct platform_device smc91x_device = {
index 2385052b0ce1326d9f1ae79959d16a9fea459361..e362f865fcd28dafa070c5bb3873e2cf54dbbc8c 100644 (file)
@@ -41,30 +41,35 @@ static irqreturn_t cplds_irq_handler(int in_irq, void *d)
        unsigned long pending;
        unsigned int bit;
 
-       pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
-       for_each_set_bit(bit, &pending, CPLDS_NB_IRQ)
-               generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit));
+       do {
+               pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
+               for_each_set_bit(bit, &pending, CPLDS_NB_IRQ) {
+                       generic_handle_irq(irq_find_mapping(fpga->irqdomain,
+                                                           bit));
+               }
+       } while (pending);
 
        return IRQ_HANDLED;
 }
 
-static void cplds_irq_mask_ack(struct irq_data *d)
+static void cplds_irq_mask(struct irq_data *d)
 {
        struct cplds *fpga = irq_data_get_irq_chip_data(d);
        unsigned int cplds_irq = irqd_to_hwirq(d);
-       unsigned int set, bit = BIT(cplds_irq);
+       unsigned int bit = BIT(cplds_irq);
 
        fpga->irq_mask &= ~bit;
        writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
-       set = readl(fpga->base + FPGA_IRQ_SET_CLR);
-       writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
 }
 
 static void cplds_irq_unmask(struct irq_data *d)
 {
        struct cplds *fpga = irq_data_get_irq_chip_data(d);
        unsigned int cplds_irq = irqd_to_hwirq(d);
-       unsigned int bit = BIT(cplds_irq);
+       unsigned int set, bit = BIT(cplds_irq);
+
+       set = readl(fpga->base + FPGA_IRQ_SET_CLR);
+       writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
 
        fpga->irq_mask |= bit;
        writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
@@ -72,7 +77,8 @@ static void cplds_irq_unmask(struct irq_data *d)
 
 static struct irq_chip cplds_irq_chip = {
        .name           = "pxa_cplds",
-       .irq_mask_ack   = cplds_irq_mask_ack,
+       .irq_ack        = cplds_irq_mask,
+       .irq_mask       = cplds_irq_mask,
        .irq_unmask     = cplds_irq_unmask,
        .flags          = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
 };
index 13b1d4586d7dedc7cee9d2754550a6d6eff28baf..9001312710f73eee85467b3f7ad255a3f79514ce 100644 (file)
@@ -120,7 +120,8 @@ static struct resource smc91x_resources[] = {
 };
 
 static struct smc91x_platdata xcep_smc91x_info = {
-       .flags  = SMC91X_USE_32BIT | SMC91X_NOWAIT | SMC91X_USE_DMA,
+       .flags  = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+                 SMC91X_NOWAIT | SMC91X_USE_DMA,
 };
 
 static struct platform_device smc91x_device = {
index 44575edc44b13d01c1f6db65245651f8be1c0074..cf0a7c2359f072d49aca95af6b4073da42ec7180 100644 (file)
@@ -95,7 +95,8 @@ static struct smsc911x_platform_config smsc911x_config = {
 };
 
 static struct smc91x_platdata smc91x_platdata = {
-       .flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+       .flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+                SMC91X_NOWAIT,
 };
 
 static struct platform_device realview_eth_device = {
index cbf53bb9c814dc328bb209ad3ee580da7f2f6a6f..0db46895c82a4729d40b6c94c62482cd00ae1c9b 100644 (file)
@@ -125,6 +125,8 @@ static unsigned long clk_36864_get_rate(struct clk *clk)
 }
 
 static struct clkops clk_36864_ops = {
+       .enable         = clk_cpu_enable,
+       .disable        = clk_cpu_disable,
        .get_rate       = clk_36864_get_rate,
 };
 
@@ -140,9 +142,8 @@ static struct clk_lookup sa11xx_clkregs[] = {
        CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864),
 };
 
-static int __init sa11xx_clk_init(void)
+int __init sa11xx_clk_init(void)
 {
        clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
        return 0;
 }
-core_initcall(sa11xx_clk_init);
index 345e63f4eb71f53d0038adc005c8a0f052714b2b..3e09beddb6e8f4e84e0863691c7d33c91bae404a 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
+#include <mach/reset.h>
 
 #include "generic.h"
 #include <clocksource/pxa.h>
@@ -95,6 +96,8 @@ static void sa1100_power_off(void)
 
 void sa11x0_restart(enum reboot_mode mode, const char *cmd)
 {
+       clear_reset_status(RESET_STATUS_ALL);
+
        if (mode == REBOOT_SOFT) {
                /* Jump into ROM at address 0 */
                soft_restart(0);
@@ -388,6 +391,7 @@ void __init sa1100_init_irq(void)
        sa11x0_init_irq_nodt(IRQ_GPIO0_SC, irq_resource.start);
 
        sa1100_init_gpio();
+       sa11xx_clk_init();
 }
 
 /*
index 0d92e119b36b13d28c2ab8036c21f23963a54ff8..68199b603ff717f7b5dfb514abd62c3b21704d1c 100644 (file)
@@ -44,3 +44,5 @@ int sa11x0_pm_init(void);
 #else
 static inline int sa11x0_pm_init(void) { return 0; }
 #endif
+
+int sa11xx_clk_init(void);
index 1525d7b5f1b74b6d06ac1276a56a45c23781e060..88149f85bc49dfa7a62c6b395bdf7a3e3f770e7b 100644 (file)
@@ -45,7 +45,7 @@ static struct resource smc91x_resources[] = {
 };
 
 static struct smc91x_platdata smc91x_platdata = {
-       .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+       .flags = SMC91X_USE_16BIT | SMC91X_USE_8BIT | SMC91X_NOWAIT,
 };
 
 static struct platform_device smc91x_device = {
index 62437b57813eab3c1cff4fc275386b37378dc9d8..73e3adbc133096eca9cdf652d37ff110f5e35850 100644 (file)
 
 #define REGULATOR_IRQ_MASK     BIT(2)  /* IRQ2, active low */
 
-static void __iomem *irqc;
-
-static const u8 da9063_mask_regs[] = {
-       DA9063_REG_IRQ_MASK_A,
-       DA9063_REG_IRQ_MASK_B,
-       DA9063_REG_IRQ_MASK_C,
-       DA9063_REG_IRQ_MASK_D,
-};
-
-/* DA9210 System Control and Event Registers */
+/* start of DA9210 System Control and Event Registers */
 #define DA9210_REG_MASK_A              0x54
-#define DA9210_REG_MASK_B              0x55
-
-static const u8 da9210_mask_regs[] = {
-       DA9210_REG_MASK_A,
-       DA9210_REG_MASK_B,
-};
-
-static void da9xxx_mask_irqs(struct i2c_client *client, const u8 regs[],
-                            unsigned int nregs)
-{
-       unsigned int i;
 
-       dev_info(&client->dev, "Masking %s interrupt sources\n", client->name);
+static void __iomem *irqc;
 
-       for (i = 0; i < nregs; i++) {
-               int error = i2c_smbus_write_byte_data(client, regs[i], ~0);
-               if (error) {
-                       dev_err(&client->dev, "i2c error %d\n", error);
-                       return;
-               }
-       }
-}
+/* first byte sets the memory pointer, following are consecutive reg values */
+static u8 da9063_irq_clr[] = { DA9063_REG_IRQ_MASK_A, 0xff, 0xff, 0xff, 0xff };
+static u8 da9210_irq_clr[] = { DA9210_REG_MASK_A, 0xff, 0xff };
+
+static struct i2c_msg da9xxx_msgs[2] = {
+       {
+               .addr = 0x58,
+               .len = ARRAY_SIZE(da9063_irq_clr),
+               .buf = da9063_irq_clr,
+       }, {
+               .addr = 0x68,
+               .len = ARRAY_SIZE(da9210_irq_clr),
+               .buf = da9210_irq_clr,
+       },
+};
 
 static int regulator_quirk_notify(struct notifier_block *nb,
                                  unsigned long action, void *data)
@@ -93,12 +80,15 @@ static int regulator_quirk_notify(struct notifier_block *nb,
        client = to_i2c_client(dev);
        dev_dbg(dev, "Detected %s\n", client->name);
 
-       if ((client->addr == 0x58 && !strcmp(client->name, "da9063")))
-               da9xxx_mask_irqs(client, da9063_mask_regs,
-                                ARRAY_SIZE(da9063_mask_regs));
-       else if (client->addr == 0x68 && !strcmp(client->name, "da9210"))
-               da9xxx_mask_irqs(client, da9210_mask_regs,
-                                ARRAY_SIZE(da9210_mask_regs));
+       if ((client->addr == 0x58 && !strcmp(client->name, "da9063")) ||
+           (client->addr == 0x68 && !strcmp(client->name, "da9210"))) {
+               int ret;
+
+               dev_info(&client->dev, "clearing da9063/da9210 interrupts\n");
+               ret = i2c_transfer(client->adapter, da9xxx_msgs, ARRAY_SIZE(da9xxx_msgs));
+               if (ret != ARRAY_SIZE(da9xxx_msgs))
+                       dev_err(&client->dev, "i2c error %d\n", ret);
+       }
 
        mon = ioread32(irqc + IRQC_MONITOR);
        if (mon & REGULATOR_IRQ_MASK)
index 4867f5daf82c99bdf4ee64ebb6b61613cd792a3e..de9f8921e4072b9e7db1fb3113548719913b3d61 100644 (file)
@@ -572,7 +572,7 @@ static void __init build_mem_type_table(void)
         * in the Short-descriptor translation table format descriptors.
         */
        if (cpu_arch == CPU_ARCH_ARMv7 &&
-               (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) == 4) {
+               (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) >= 4) {
                user_pmd_table |= PMD_PXNTABLE;
        }
 #endif
index eb4aa01ffccb06876bc50c2e99b9094c31a63cde..81ea0965f997eb2dc7e7da32c1ac45f05cfc68ed 100644 (file)
@@ -49,6 +49,7 @@ config ARM64
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_BITREVERSE
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_HUGE_VMAP
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48)
@@ -80,8 +81,11 @@ config ARM64
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
+       select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RCU_TABLE_FREE
        select HAVE_SYSCALL_TRACEPOINTS
+       select HAVE_KPROBES
+       select HAVE_KRETPROBES if HAVE_KPROBES
        select IOMMU_DMA if IOMMU_SUPPORT
        select IRQ_DOMAIN
        select IRQ_FORCED_THREADING
@@ -429,6 +433,15 @@ config CAVIUM_ERRATUM_22375
 
          If unsure, say Y.
 
+config CAVIUM_ERRATUM_23144
+       bool "Cavium erratum 23144: ITS SYNC hang on dual socket system"
+       depends on NUMA
+       default y
+       help
+         ITS SYNC command hang for cross node io and collections/cpu mapping.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_23154
        bool "Cavium erratum 23154: Access to ICC_IAR1_EL1 is not sync'ed"
        default y
@@ -439,6 +452,17 @@ config CAVIUM_ERRATUM_23154
 
          If unsure, say Y.
 
+config CAVIUM_ERRATUM_27456
+       bool "Cavium erratum 27456: Broadcast TLBI instructions may cause icache corruption"
+       default y
+       help
+         On ThunderX T88 pass 1.x through 2.1 parts, broadcast TLBI
+         instructions may cause the icache to become corrupted if it
+         contains data for a non-current ASID.  The fix is to
+         invalidate the icache when changing the mm context.
+
+         If unsure, say Y.
+
 endmenu
 
 
@@ -695,6 +719,14 @@ config SETEND_EMULATION
          If unsure, say Y
 endif
 
+config ARM64_SW_TTBR0_PAN
+       bool "Emulate Priviledged Access Never using TTBR0_EL1 switching"
+       help
+         Enabling this option prevents the kernel from accessing
+         user-space memory directly by pointing TTBR0_EL1 to a reserved
+         zeroed area and reserved ASID. The user access routines
+         restore the valid TTBR0_EL1 temporarily.
+
 menu "ARMv8.1 architectural features"
 
 config ARM64_HW_AFDBM
@@ -784,7 +816,7 @@ config RELOCATABLE
 
 config RANDOMIZE_BASE
        bool "Randomize the address of the kernel image"
-       select ARM64_MODULE_PLTS
+       select ARM64_MODULE_PLTS if MODULES
        select RELOCATABLE
        help
          Randomizes the virtual address at which the kernel image is
@@ -803,7 +835,7 @@ config RANDOMIZE_BASE
 
 config RANDOMIZE_MODULE_REGION_FULL
        bool "Randomize the module region independently from the core kernel"
-       depends on RANDOMIZE_BASE
+       depends on RANDOMIZE_BASE && !DYNAMIC_FTRACE
        default y
        help
          Randomizes the location of the module region without considering the
index 43260254d298ba026d1f14fe973f69d75b6d20df..85de2131537ecbdf73985288af03dfb2906d4fad 100644 (file)
@@ -16,7 +16,7 @@ OBJCOPYFLAGS  :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 GZFLAGS                :=-9
 
 ifneq ($(CONFIG_RELOCATABLE),)
-LDFLAGS_vmlinux                += -pie
+LDFLAGS_vmlinux                += -pie -Bsymbolic
 endif
 
 KBUILD_DEFCONFIG := defconfig
index 132765e7129db3a2ef274e3957c40fafca8af677..fd69e074c0252adb37b35bb0b96d74246307ef56 100644 (file)
                #io-channel-cells = <1>;
                clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
                clock-names = "saradc", "apb_pclk";
+               resets = <&cru SRST_SARADC>;
+               reset-names = "saradc-apb";
                status = "disabled";
        };
 
                #address-cells = <0>;
 
                reg = <0x0 0xffb71000 0x0 0x1000>,
-                     <0x0 0xffb72000 0x0 0x1000>,
+                     <0x0 0xffb72000 0x0 0x2000>,
                      <0x0 0xffb74000 0x0 0x2000>,
                      <0x0 0xffb76000 0x0 0x2000>;
                interrupts = <GIC_PPI 9
index 05d9e16c0dfdd81a8a6ffe141e5c6f5cc96b3e7e..6a51dfccfe71a1846c66e8b2b53580b489a3d90c 100644 (file)
@@ -211,7 +211,7 @@ static int ctr_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                err = blkcipher_walk_done(desc, &walk,
                                          walk.nbytes % AES_BLOCK_SIZE);
        }
-       if (nbytes) {
+       if (walk.nbytes % AES_BLOCK_SIZE) {
                u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
                u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE;
                u8 __aligned(8) tail[AES_BLOCK_SIZE];
index beccbdefa106a4ba0dd7d98537427a37d2c26517..8746ff6abd7782210abe56c56b549e0c4e67ac68 100644 (file)
@@ -95,13 +95,11 @@ void apply_alternatives(void *start, size_t length);
  * The code that follows this macro will be assembled and linked as
  * normal. There are no restrictions on this code.
  */
-.macro alternative_if_not cap, enable = 1
-       .if \enable
+.macro alternative_if_not cap
        .pushsection .altinstructions, "a"
        altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f
        .popsection
 661:
-       .endif
 .endm
 
 /*
@@ -118,27 +116,27 @@ void apply_alternatives(void *start, size_t length);
  *    alternative sequence it is defined in (branches into an
  *    alternative sequence are not fixed up).
  */
-.macro alternative_else, enable = 1
-       .if \enable
+.macro alternative_else
 662:   .pushsection .altinstr_replacement, "ax"
 663:
-       .endif
 .endm
 
 /*
  * Complete an alternative code sequence.
  */
-.macro alternative_endif, enable = 1
-       .if \enable
+.macro alternative_endif
 664:   .popsection
        .org    . - (664b-663b) + (662b-661b)
        .org    . - (662b-661b) + (664b-663b)
-       .endif
 .endm
 
 #define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...)  \
        alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
 
+.macro user_alt, label, oldinstr, newinstr, cond
+9999:  alternative_insn "\oldinstr", "\newinstr", \cond
+       _ASM_EXTABLE 9999b, \label
+.endm
 
 /*
  * Generate the assembly for UAO alternatives with exception table entries.
index 9ea846ded55cc6aee3532e392445c539245fe29f..aeb4554b3af386f215ba9fbe75f0be671b13d8eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Based on arch/arm/include/asm/assembler.h
+ * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
  *
  * Copyright (C) 1996-2000 Russell King
  * Copyright (C) 2012 ARM Ltd.
 #ifndef __ASM_ASSEMBLER_H
 #define __ASM_ASSEMBLER_H
 
+#include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
+#include <asm/page.h>
+#include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
 
        msr     daifclr, #2
        .endm
 
+       .macro  save_and_disable_irq, flags
+       mrs     \flags, daif
+       msr     daifset, #2
+       .endm
+
+       .macro  restore_irq, flags
+       msr     daif, \flags
+       .endm
+
 /*
  * Enable and disable debug exceptions.
  */
@@ -211,6 +224,111 @@ lr        .req    x30             // link register
        add     \reg, \reg, \tmp
        .endm
 
+/*
+ * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
+ */
+       .macro  vma_vm_mm, rd, rn
+       ldr     \rd, [\rn, #VMA_VM_MM]
+       .endm
+
+/*
+ * mmid - get context id from mm pointer (mm->context.id)
+ */
+       .macro  mmid, rd, rn
+       ldr     \rd, [\rn, #MM_CONTEXT_ID]
+       .endm
+
+/*
+ * dcache_line_size - get the minimum D-cache line size from the CTR register.
+ */
+       .macro  dcache_line_size, reg, tmp
+       mrs     \tmp, ctr_el0                   // read CTR
+       ubfm    \tmp, \tmp, #16, #19            // cache line size encoding
+       mov     \reg, #4                        // bytes per word
+       lsl     \reg, \reg, \tmp                // actual cache line size
+       .endm
+
+/*
+ * icache_line_size - get the minimum I-cache line size from the CTR register.
+ */
+       .macro  icache_line_size, reg, tmp
+       mrs     \tmp, ctr_el0                   // read CTR
+       and     \tmp, \tmp, #0xf                // cache line size encoding
+       mov     \reg, #4                        // bytes per word
+       lsl     \reg, \reg, \tmp                // actual cache line size
+       .endm
+
+/*
+ * tcr_set_idmap_t0sz - update TCR.T0SZ so that we can load the ID map
+ */
+       .macro  tcr_set_idmap_t0sz, valreg, tmpreg
+#ifndef CONFIG_ARM64_VA_BITS_48
+       ldr_l   \tmpreg, idmap_t0sz
+       bfi     \valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
+#endif
+       .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:
+       .if     (\op == cvau || \op == cvac)
+alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
+       dc      \op, \kaddr
+alternative_else
+       dc      civac, \kaddr
+alternative_endif
+       .else
+       dc      \op, \kaddr
+       .endif
+       add     \kaddr, \kaddr, \tmp1
+       cmp     \kaddr, \size
+       b.lo    9998b
+       dsb     \domain
+       .endm
+
+/*
+ * reset_pmuserenr_el0 - reset PMUSERENR_EL0 if PMUv3 present
+ */
+       .macro  reset_pmuserenr_el0, tmpreg
+       mrs     \tmpreg, id_aa64dfr0_el1        // Check ID_AA64DFR0_EL1 PMUVer
+       sbfx    \tmpreg, \tmpreg, #8, #4
+       cmp     \tmpreg, #1                     // Skip if no PMU present
+       b.lt    9000f
+       msr     pmuserenr_el0, xzr              // Disable PMU access from EL0
+9000:
+       .endm
+
+/*
+ * copy_page - copy src to dest using temp registers t1-t8
+ */
+       .macro copy_page dest:req src:req t1:req t2:req t3:req t4:req t5:req t6:req t7:req t8:req
+9998:  ldp     \t1, \t2, [\src]
+       ldp     \t3, \t4, [\src, #16]
+       ldp     \t5, \t6, [\src, #32]
+       ldp     \t7, \t8, [\src, #48]
+       add     \src, \src, #64
+       stnp    \t1, \t2, [\dest]
+       stnp    \t3, \t4, [\dest, #16]
+       stnp    \t5, \t6, [\dest, #32]
+       stnp    \t7, \t8, [\dest, #48]
+       add     \dest, \dest, #64
+       tst     \src, #(PAGE_SIZE - 1)
+       b.ne    9998b
+       .endm
+
 /*
  * Annotate a function as position independent, i.e., safe to be called before
  * the kernel virtual mapping is activated.
@@ -253,4 +371,28 @@ lr .req    x30             // link register
        movk    \reg, :abs_g0_nc:\val
        .endm
 
+/*
+ * Return the current thread_info.
+ */
+       .macro  get_thread_info, rd
+       mrs     \rd, sp_el0
+       .endm
+
+/*
+ * Errata workaround post TTBR0_EL1 update.
+ */
+       .macro  post_ttbr0_update_workaround
+#ifdef CONFIG_CAVIUM_ERRATUM_27456
+alternative_if_not ARM64_WORKAROUND_CAVIUM_27456
+       nop
+       nop
+       nop
+alternative_else
+       ic      iallu
+       dsb     nsh
+       isb
+alternative_endif
+#endif
+       .endm
+
 #endif /* __ASM_ASSEMBLER_H */
index 37a53fc6b384eadb7d5b755066ec9fe67717167c..d4c925ccc7dec8689b2ef891ae2e4ebd501fce94 100644 (file)
@@ -35,6 +35,8 @@
 #define ARM64_ALT_PAN_NOT_UAO                  10
 
 #define ARM64_NCAPS                            11
+#define ARM64_WORKAROUND_CAVIUM_27456          12      
+
 
 #ifndef __ASSEMBLY__
 
@@ -187,6 +189,12 @@ static inline bool system_supports_mixed_endian_el0(void)
        return id_aa64mmfr0_mixed_endian_el0(read_system_reg(SYS_ID_AA64MMFR0_EL1));
 }
 
+static inline bool system_uses_ttbr0_pan(void)
+{
+       return IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) &&
+               !cpus_have_cap(ARM64_HAS_PAN);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif
index 2fcb9b7c876c06d67c220f1eefcd0b61ef715a1c..4b6b3f72a2158a06e07f36529912c81c0b5fb43b 100644 (file)
 
 #define CACHE_FLUSH_IS_SAFE            1
 
+/* kprobes BRK opcodes with ESR encoding  */
+#define BRK64_ESR_MASK         0xFFFF
+#define BRK64_ESR_KPROBES      0x0004
+#define BRK64_OPCODE_KPROBES   (AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5))
+
 /* AArch32 */
 #define DBG_ESR_EVT_BKPT       0x4
 #define DBG_ESR_EVT_VECC       0x5
index ef572206f1c3eb6658618b40568e662f7e1865fc..932f5a56d1a60d47ffc7b8c05ce2e67ea7374e7a 100644 (file)
@@ -1,8 +1,11 @@
 #ifndef _ASM_EFI_H
 #define _ASM_EFI_H
 
+#include <asm/cpufeature.h>
 #include <asm/io.h>
+#include <asm/mmu_context.h>
 #include <asm/neon.h>
+#include <asm/tlbflush.h>
 
 #ifdef CONFIG_EFI
 extern void efi_init(void);
@@ -10,6 +13,8 @@ extern void efi_init(void);
 #define efi_init()
 #endif
 
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
 #define efi_call_virt(f, ...)                                          \
 ({                                                                     \
        efi_##f##_t *__f;                                               \
@@ -63,6 +68,34 @@ extern void efi_init(void);
  *   Services are enabled and the EFI_RUNTIME_SERVICES bit set.
  */
 
+static inline void efi_set_pgd(struct mm_struct *mm)
+{
+       __switch_mm(mm);
+
+       if (system_uses_ttbr0_pan()) {
+               if (mm != current->active_mm) {
+                       /*
+                        * Update the current thread's saved ttbr0 since it is
+                        * restored as part of a return from exception. Set
+                        * the hardware TTBR0_EL1 using cpu_switch_mm()
+                        * directly to enable potential errata workarounds.
+                        */
+                       update_saved_ttbr0(current, mm);
+                       cpu_switch_mm(mm->pgd, mm);
+               } else {
+                       /*
+                        * Defer the switch to the current thread's TTBR0_EL1
+                        * until uaccess_enable(). Restore the current
+                        * thread's saved ttbr0 corresponding to its active_mm
+                        * (if different from init_mm).
+                        */
+                       cpu_set_reserved_ttbr0();
+                       if (current->active_mm != &init_mm)
+                               update_saved_ttbr0(current, current->active_mm);
+               }
+       }
+}
+
 void efi_virtmap_load(void);
 void efi_virtmap_unload(void);
 
index 83d48a599f69cdf2917c0e76a5903244efbe1275..7875c886ad24226bea0617649b6e50a7944361bf 100644 (file)
@@ -140,6 +140,7 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 
 #define SET_PERSONALITY(ex)            clear_thread_flag(TIF_32BIT);
 
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO                                                    \
 do {                                                                   \
        NEW_AUX_ENT(AT_SYSINFO_EHDR,                                    \
index 77eeb2cc648fd79d28cfc452c7373b6ebe04071b..f772e15c47663f0aafa1b287e8b9ac6aa3a55d2c 100644 (file)
@@ -74,6 +74,7 @@
 
 #define ESR_ELx_EC_SHIFT       (26)
 #define ESR_ELx_EC_MASK                (UL(0x3F) << ESR_ELx_EC_SHIFT)
+#define ESR_ELx_EC(esr)                (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT)
 
 #define ESR_ELx_IL             (UL(1) << 25)
 #define ESR_ELx_ISS_MASK       (ESR_ELx_IL - 1)
index f2585cdd32c29832566718e99d7b5fd9c61d2322..71dfa3b4231364363e08bd474ea474cc7fffd89c 100644 (file)
@@ -27,9 +27,9 @@
 #include <asm/sysreg.h>
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg)                \
+do {                                                                   \
+       uaccess_enable();                                               \
        asm volatile(                                                   \
-       ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,            \
-                   CONFIG_ARM64_PAN)                                   \
 "      prfm    pstl1strm, %2\n"                                        \
 "1:    ldxr    %w1, %2\n"                                              \
        insn "\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)       \
        : "r" (oparg), "Ir" (-EFAULT)                                   \
-       : "memory")
+       : "memory");                                                    \
+       uaccess_disable();                                              \
+} while (0)
 
 static inline int
 futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
@@ -118,8 +118,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
+       uaccess_enable();
        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"
@@ -134,10 +134,10 @@ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
 "      .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");
+       uaccess_disable();
 
        *uval = val;
        return ret;
index 30e50eb54a6795aa9c504a2d22dfabd8b8db195a..1dbaa901d7e5d022f19f5bc3ee5e18fe6fa47a73 100644 (file)
@@ -120,6 +120,29 @@ enum aarch64_insn_register {
        AARCH64_INSN_REG_SP = 31  /* Stack pointer: as load/store base reg */
 };
 
+enum aarch64_insn_special_register {
+       AARCH64_INSN_SPCLREG_SPSR_EL1   = 0xC200,
+       AARCH64_INSN_SPCLREG_ELR_EL1    = 0xC201,
+       AARCH64_INSN_SPCLREG_SP_EL0     = 0xC208,
+       AARCH64_INSN_SPCLREG_SPSEL      = 0xC210,
+       AARCH64_INSN_SPCLREG_CURRENTEL  = 0xC212,
+       AARCH64_INSN_SPCLREG_DAIF       = 0xDA11,
+       AARCH64_INSN_SPCLREG_NZCV       = 0xDA10,
+       AARCH64_INSN_SPCLREG_FPCR       = 0xDA20,
+       AARCH64_INSN_SPCLREG_DSPSR_EL0  = 0xDA28,
+       AARCH64_INSN_SPCLREG_DLR_EL0    = 0xDA29,
+       AARCH64_INSN_SPCLREG_SPSR_EL2   = 0xE200,
+       AARCH64_INSN_SPCLREG_ELR_EL2    = 0xE201,
+       AARCH64_INSN_SPCLREG_SP_EL1     = 0xE208,
+       AARCH64_INSN_SPCLREG_SPSR_INQ   = 0xE218,
+       AARCH64_INSN_SPCLREG_SPSR_ABT   = 0xE219,
+       AARCH64_INSN_SPCLREG_SPSR_UND   = 0xE21A,
+       AARCH64_INSN_SPCLREG_SPSR_FIQ   = 0xE21B,
+       AARCH64_INSN_SPCLREG_SPSR_EL3   = 0xF200,
+       AARCH64_INSN_SPCLREG_ELR_EL3    = 0xF201,
+       AARCH64_INSN_SPCLREG_SP_EL2     = 0xF210
+};
+
 enum aarch64_insn_variant {
        AARCH64_INSN_VARIANT_32BIT,
        AARCH64_INSN_VARIANT_64BIT
@@ -223,8 +246,15 @@ static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
 static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
 { return (val); }
 
+__AARCH64_INSN_FUNCS(adr_adrp, 0x1F000000, 0x10000000)
+__AARCH64_INSN_FUNCS(prfm_lit, 0xFF000000, 0xD8000000)
 __AARCH64_INSN_FUNCS(str_reg,  0x3FE0EC00, 0x38206800)
 __AARCH64_INSN_FUNCS(ldr_reg,  0x3FE0EC00, 0x38606800)
+__AARCH64_INSN_FUNCS(ldr_lit,  0xBF000000, 0x18000000)
+__AARCH64_INSN_FUNCS(ldrsw_lit,        0xFF000000, 0x98000000)
+__AARCH64_INSN_FUNCS(exclusive,        0x3F800000, 0x08000000)
+__AARCH64_INSN_FUNCS(load_ex,  0x3F400000, 0x08400000)
+__AARCH64_INSN_FUNCS(store_ex, 0x3F400000, 0x08000000)
 __AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000)
 __AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000)
 __AARCH64_INSN_FUNCS(stp_pre,  0x7FC00000, 0x29800000)
@@ -273,10 +303,15 @@ __AARCH64_INSN_FUNCS(svc, 0xFFE0001F, 0xD4000001)
 __AARCH64_INSN_FUNCS(hvc,      0xFFE0001F, 0xD4000002)
 __AARCH64_INSN_FUNCS(smc,      0xFFE0001F, 0xD4000003)
 __AARCH64_INSN_FUNCS(brk,      0xFFE0001F, 0xD4200000)
+__AARCH64_INSN_FUNCS(exception,        0xFF000000, 0xD4000000)
 __AARCH64_INSN_FUNCS(hint,     0xFFFFF01F, 0xD503201F)
 __AARCH64_INSN_FUNCS(br,       0xFFFFFC1F, 0xD61F0000)
 __AARCH64_INSN_FUNCS(blr,      0xFFFFFC1F, 0xD63F0000)
 __AARCH64_INSN_FUNCS(ret,      0xFFFFFC1F, 0xD65F0000)
+__AARCH64_INSN_FUNCS(eret,     0xFFFFFFFF, 0xD69F03E0)
+__AARCH64_INSN_FUNCS(mrs,      0xFFF00000, 0xD5300000)
+__AARCH64_INSN_FUNCS(msr_imm,  0xFFF8F01F, 0xD500401F)
+__AARCH64_INSN_FUNCS(msr_reg,  0xFFF00000, 0xD5100000)
 
 #undef __AARCH64_INSN_FUNCS
 
@@ -286,6 +321,8 @@ bool aarch64_insn_is_branch_imm(u32 insn);
 int aarch64_insn_read(void *addr, u32 *insnp);
 int aarch64_insn_write(void *addr, u32 insn);
 enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
+bool aarch64_insn_uses_literal(u32 insn);
+bool aarch64_insn_is_branch(u32 insn);
 u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn);
 u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
                                  u32 insn, u64 imm);
@@ -367,9 +404,13 @@ bool aarch32_insn_is_wide(u32 insn);
 #define A32_RT_OFFSET  12
 #define A32_RT2_OFFSET  0
 
+u32 aarch64_insn_extract_system_reg(u32 insn);
 u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
 u32 aarch32_insn_mcr_extract_opc2(u32 insn);
 u32 aarch32_insn_mcr_extract_crm(u32 insn);
+
+typedef bool (pstate_check_t)(unsigned long);
+extern pstate_check_t * const aarch32_opcode_cond_checks[16];
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_INSN_H */
index 5c6375d8528bb8ddd313bfa2911f7a0d77819028..7803343e5881fbd7b2f635b25082d3e91d2583f8 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __ASM_KERNEL_PGTABLE_H
 #define __ASM_KERNEL_PGTABLE_H
 
+#include <asm/pgtable.h>
+#include <asm/sparsemem.h>
 
 /*
  * The linear mapping and the start of memory are both 2M aligned (per
 #define SWAPPER_DIR_SIZE       (SWAPPER_PGTABLE_LEVELS * PAGE_SIZE)
 #define IDMAP_DIR_SIZE         (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
 
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+#define RESERVED_TTBR0_SIZE    (PAGE_SIZE)
+#else
+#define RESERVED_TTBR0_SIZE    (0)
+#endif
+
 /* Initial memory map size */
 #if ARM64_SWAPPER_USES_SECTION_MAPS
 #define SWAPPER_BLOCK_SHIFT    SECTION_SHIFT
  * (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
+#if defined(CONFIG_ARM64_4K_PAGES)
+#define ARM64_MEMSTART_SHIFT           PUD_SHIFT
+#elif defined(CONFIG_ARM64_16K_PAGES)
+#define ARM64_MEMSTART_SHIFT           (PMD_SHIFT + 5)
+#else
+#define ARM64_MEMSTART_SHIFT           PMD_SHIFT
+#endif
+
+/*
+ * sparsemem vmemmap imposes an additional requirement on the alignment of
+ * memstart_addr, due to the fact that the base of the vmemmap region
+ * has a direct correspondence, and needs to appear sufficiently aligned
+ * in the virtual address space.
+ */
+#if defined(CONFIG_SPARSEMEM_VMEMMAP) && ARM64_MEMSTART_SHIFT < SECTION_SIZE_BITS
+#define ARM64_MEMSTART_ALIGN   (1UL << SECTION_SIZE_BITS)
 #else
-#define ARM64_MEMSTART_ALIGN   SZ_1G
+#define ARM64_MEMSTART_ALIGN   (1UL << ARM64_MEMSTART_SHIFT)
 #endif
 
 #endif /* __ASM_KERNEL_PGTABLE_H */
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
new file mode 100644 (file)
index 0000000..1737aec
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/arm64/include/asm/kprobes.h
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ARM_KPROBES_H
+#define _ARM_KPROBES_H
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/percpu.h>
+
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+#define MAX_INSN_SIZE                  1
+
+#define flush_insn_slot(p)             do { } while (0)
+#define kretprobe_blacklist_size       0
+
+#include <asm/probes.h>
+
+struct prev_kprobe {
+       struct kprobe *kp;
+       unsigned int status;
+};
+
+/* Single step context for kprobe */
+struct kprobe_step_ctx {
+       unsigned long ss_pending;
+       unsigned long match_addr;
+};
+
+/* per-cpu kprobe control block */
+struct kprobe_ctlblk {
+       unsigned int kprobe_status;
+       unsigned long saved_irqflag;
+       struct prev_kprobe prev_kprobe;
+       struct kprobe_step_ctx ss_ctx;
+       struct pt_regs jprobe_saved_regs;
+};
+
+void arch_remove_kprobe(struct kprobe *);
+int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
+int kprobe_exceptions_notify(struct notifier_block *self,
+                            unsigned long val, void *data);
+int kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr);
+int kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr);
+void kretprobe_trampoline(void);
+void __kprobes *trampoline_probe_handler(struct pt_regs *regs);
+
+#endif /* _ARM_KPROBES_H */
index 5e6857b6bdc45cc100d293cbdf1e3d683a4763e7..2d960f8588b0639f80c272f833c3796fd7c286b6 100644 (file)
 #define TCR_EL2_MASK   (TCR_EL2_TG0 | TCR_EL2_SH0 | \
                         TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ)
 
-#define TCR_EL2_FLAGS  (TCR_EL2_RES1 | TCR_EL2_PS_40B)
-
 /* VTCR_EL2 Registers bits */
 #define VTCR_EL2_RES1          (1 << 31)
 #define VTCR_EL2_PS_MASK       (7 << 16)
index 12f8a00fb3f1767a645a04358dcaca08fd4f6b43..ba1b3409d7edd1fc349ef474631d1fd263226e78 100644 (file)
@@ -193,7 +193,11 @@ static inline void *phys_to_virt(phys_addr_t x)
 #define ARCH_PFN_OFFSET                ((unsigned long)PHYS_PFN_OFFSET)
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define        virt_addr_valid(kaddr)  pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define _virt_addr_valid(kaddr)        pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+
+#define _virt_addr_is_linear(kaddr)    (((u64)(kaddr)) >= PAGE_OFFSET)
+#define virt_addr_valid(kaddr)         (_virt_addr_is_linear(kaddr) && \
+                                        _virt_addr_valid(kaddr))
 
 #endif
 
index a00f7cf35bbd4d80ce045bfeb0cbb6bd061aeaaa..4a32fd5f101dd5ec14f1fcc7d3e922c0cdd25c5f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sched.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/proc-fns.h>
 #include <asm-generic/mm_hooks.h>
 #include <asm/cputype.h>
@@ -113,7 +114,7 @@ static inline void cpu_uninstall_idmap(void)
        local_flush_tlb_all();
        cpu_set_default_tcr_t0sz();
 
-       if (mm != &init_mm)
+       if (mm != &init_mm && !system_uses_ttbr0_pan())
                cpu_switch_mm(mm->pgd, mm);
 }
 
@@ -173,20 +174,26 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 }
 
-/*
- * This is the actual mm switch as far as the scheduler
- * is concerned.  No registers are touched.  We avoid
- * calling the CPU specific function when the mm hasn't
- * actually changed.
- */
-static inline void
-switch_mm(struct mm_struct *prev, struct mm_struct *next,
-         struct task_struct *tsk)
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+static inline void update_saved_ttbr0(struct task_struct *tsk,
+                                     struct mm_struct *mm)
 {
-       unsigned int cpu = smp_processor_id();
+       if (system_uses_ttbr0_pan()) {
+               BUG_ON(mm->pgd == swapper_pg_dir);
+               task_thread_info(tsk)->ttbr0 =
+                       virt_to_phys(mm->pgd) | ASID(mm) << 48;
+       }
+}
+#else
+static inline void update_saved_ttbr0(struct task_struct *tsk,
+                                     struct mm_struct *mm)
+{
+}
+#endif
 
-       if (prev == next)
-               return;
+static inline void __switch_mm(struct mm_struct *next)
+{
+       unsigned int cpu = smp_processor_id();
 
        /*
         * init_mm.pgd does not contain any user mappings and it is always
@@ -200,7 +207,23 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
        check_and_switch_context(next, cpu);
 }
 
+static inline void
+switch_mm(struct mm_struct *prev, struct mm_struct *next,
+         struct task_struct *tsk)
+{
+       if (prev != next)
+               __switch_mm(next);
+
+       /*
+        * Update the saved TTBR0_EL1 of the scheduled-in task as the previous
+        * value may have not been initialised yet (activate_mm caller) or the
+        * ASID has changed since the last run (following the context switch
+        * of another thread of the same process).
+        */
+       update_saved_ttbr0(tsk, next);
+}
+
 #define deactivate_mm(tsk,mm)  do { } while (0)
-#define activate_mm(prev,next) switch_mm(prev, next, NULL)
+#define activate_mm(prev,next) switch_mm(prev, next, current)
 
 #endif
index e12af6754634b3d2aa031ae23ce25228dc766cfb..06ff7fd9e81feab27bb67f1a4af971ddc0ebf4cc 100644 (file)
@@ -17,6 +17,7 @@
 #define __ASM_MODULE_H
 
 #include <asm-generic/module.h>
+#include <asm/memory.h>
 
 #define MODULE_ARCH_VERMAGIC   "aarch64"
 
@@ -32,6 +33,10 @@ u64 module_emit_plt_entry(struct module *mod, const Elf64_Rela *rela,
                          Elf64_Sym *sym);
 
 #ifdef CONFIG_RANDOMIZE_BASE
+#ifdef CONFIG_MODVERSIONS
+#define ARCH_RELOCATES_KCRCTAB
+#define reloc_start            (kimage_vaddr - KIMAGE_VADDR)
+#endif
 extern u64 module_alloc_base;
 #else
 #define module_alloc_base      ((u64)_etext - MODULES_VSIZE)
index 0a456bef8c792d91a30a4c2caf24cb6fb96546e2..8a336852eeba051535b47821cd510bc709967586 100644 (file)
@@ -44,48 +44,44 @@ static inline unsigned long __percpu_##op(void *ptr,                        \
                                                                        \
        switch (size) {                                                 \
        case 1:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_1\n"                  \
-                       "ldxrb    %w[ret], %[ptr]\n"                    \
+               asm ("//__per_cpu_" #op "_1\n"                          \
+               "1:     ldxrb     %w[ret], %[ptr]\n"                    \
                        #asm_op " %w[ret], %w[ret], %w[val]\n"          \
-                       "stxrb    %w[loop], %w[ret], %[ptr]\n"          \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr] "+Q"(*(u8 *)ptr)                        \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxrb     %w[loop], %w[ret], %[ptr]\n"          \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr] "+Q"(*(u8 *)ptr)                                \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        case 2:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_2\n"                  \
-                       "ldxrh    %w[ret], %[ptr]\n"                    \
+               asm ("//__per_cpu_" #op "_2\n"                          \
+               "1:     ldxrh     %w[ret], %[ptr]\n"                    \
                        #asm_op " %w[ret], %w[ret], %w[val]\n"          \
-                       "stxrh    %w[loop], %w[ret], %[ptr]\n"          \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr]  "+Q"(*(u16 *)ptr)                      \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxrh     %w[loop], %w[ret], %[ptr]\n"          \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr]  "+Q"(*(u16 *)ptr)                              \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        case 4:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_4\n"                  \
-                       "ldxr     %w[ret], %[ptr]\n"                    \
+               asm ("//__per_cpu_" #op "_4\n"                          \
+               "1:     ldxr      %w[ret], %[ptr]\n"                    \
                        #asm_op " %w[ret], %w[ret], %w[val]\n"          \
-                       "stxr     %w[loop], %w[ret], %[ptr]\n"          \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr] "+Q"(*(u32 *)ptr)                       \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxr      %w[loop], %w[ret], %[ptr]\n"          \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr] "+Q"(*(u32 *)ptr)                               \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        case 8:                                                         \
-               do {                                                    \
-                       asm ("//__per_cpu_" #op "_8\n"                  \
-                       "ldxr     %[ret], %[ptr]\n"                     \
+               asm ("//__per_cpu_" #op "_8\n"                          \
+               "1:     ldxr      %[ret], %[ptr]\n"                     \
                        #asm_op " %[ret], %[ret], %[val]\n"             \
-                       "stxr     %w[loop], %[ret], %[ptr]\n"           \
-                       : [loop] "=&r" (loop), [ret] "=&r" (ret),       \
-                         [ptr] "+Q"(*(u64 *)ptr)                       \
-                       : [val] "Ir" (val));                            \
-               } while (loop);                                         \
+               "       stxr      %w[loop], %[ret], %[ptr]\n"           \
+               "       cbnz      %w[loop], 1b"                         \
+               : [loop] "=&r" (loop), [ret] "=&r" (ret),               \
+                 [ptr] "+Q"(*(u64 *)ptr)                               \
+               : [val] "Ir" (val));                                    \
                break;                                                  \
        default:                                                        \
                BUILD_BUG();                                            \
@@ -150,44 +146,40 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
 
        switch (size) {
        case 1:
-               do {
-                       asm ("//__percpu_xchg_1\n"
-                       "ldxrb %w[ret], %[ptr]\n"
-                       "stxrb %w[loop], %w[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u8 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_1\n"
+               "1:     ldxrb   %w[ret], %[ptr]\n"
+               "       stxrb   %w[loop], %w[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u8 *)ptr)
+               : [val] "r" (val));
                break;
        case 2:
-               do {
-                       asm ("//__percpu_xchg_2\n"
-                       "ldxrh %w[ret], %[ptr]\n"
-                       "stxrh %w[loop], %w[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u16 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_2\n"
+               "1:     ldxrh   %w[ret], %[ptr]\n"
+               "       stxrh   %w[loop], %w[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u16 *)ptr)
+               : [val] "r" (val));
                break;
        case 4:
-               do {
-                       asm ("//__percpu_xchg_4\n"
-                       "ldxr %w[ret], %[ptr]\n"
-                       "stxr %w[loop], %w[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u32 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_4\n"
+               "1:     ldxr    %w[ret], %[ptr]\n"
+               "       stxr    %w[loop], %w[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u32 *)ptr)
+               : [val] "r" (val));
                break;
        case 8:
-               do {
-                       asm ("//__percpu_xchg_8\n"
-                       "ldxr %[ret], %[ptr]\n"
-                       "stxr %w[loop], %[val], %[ptr]\n"
-                       : [loop] "=&r"(loop), [ret] "=&r"(ret),
-                         [ptr] "+Q"(*(u64 *)ptr)
-                       : [val] "r" (val));
-               } while (loop);
+               asm ("//__percpu_xchg_8\n"
+               "1:     ldxr    %[ret], %[ptr]\n"
+               "       stxr    %w[loop], %[val], %[ptr]\n"
+               "       cbnz    %w[loop], 1b"
+               : [loop] "=&r"(loop), [ret] "=&r"(ret),
+                 [ptr] "+Q"(*(u64 *)ptr)
+               : [val] "r" (val));
                break;
        default:
                BUILD_BUG();
diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h
new file mode 100644 (file)
index 0000000..5af574d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm64/include/asm/probes.h
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#ifndef _ARM_PROBES_H
+#define _ARM_PROBES_H
+
+#include <asm/opcodes.h>
+
+struct kprobe;
+struct arch_specific_insn;
+
+typedef u32 kprobe_opcode_t;
+typedef void (kprobes_handler_t) (u32 opcode, long addr, struct pt_regs *);
+
+/* architecture specific copy of original instruction */
+struct arch_specific_insn {
+       kprobe_opcode_t *insn;
+       pstate_check_t *pstate_cc;
+       kprobes_handler_t *handler;
+       /* restore address after step xol */
+       unsigned long restore;
+};
+
+#endif
index a307eb6e7fa8d75e536fe3cff56c5d4f978fe212..5eedfd83acc772ae0324e41ffc965093829f1a6f 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <uapi/asm/ptrace.h>
 
+#define _PSR_PAN_BIT           22
+
 /* Current Exception Level values, as contained in CurrentEL */
 #define CurrentEL_EL1          (1 << 2)
 #define CurrentEL_EL2          (2 << 2)
@@ -117,8 +119,12 @@ struct pt_regs {
        };
        u64 orig_x0;
        u64 syscallno;
+       u64 orig_addr_limit;
+       u64 unused;     // maintain 16 byte alignment
 };
 
+#define MAX_REG_OFFSET offsetof(struct pt_regs, pstate)
+
 #define arch_has_single_step() (1)
 
 #ifdef CONFIG_COMPAT
@@ -144,9 +150,57 @@ struct pt_regs {
 #define fast_interrupts_enabled(regs) \
        (!((regs)->pstate & PSR_F_BIT))
 
-#define user_stack_pointer(regs) \
+#define GET_USP(regs) \
        (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
 
+#define SET_USP(ptregs, value) \
+       (!compat_user_mode(regs) ? ((regs)->sp = value) : ((regs)->compat_sp = value))
+
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+                                              unsigned int n);
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:      pt_regs from which register value is gotten
+ * @offset:    offset of the register.
+ *
+ * regs_get_register returns the value of a register whose offset from @regs.
+ * The @offset is the offset of the register in struct pt_regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline u64 regs_get_register(struct pt_regs *regs, unsigned int offset)
+{
+       u64 val = 0;
+
+       offset >>= 3;
+       switch (offset) {
+       case 0 ... 30:
+               val = regs->regs[offset];
+               break;
+       case offsetof(struct pt_regs, sp) >> 3:
+               val = regs->sp;
+               break;
+       case offsetof(struct pt_regs, pc) >> 3:
+               val = regs->pc;
+               break;
+       case offsetof(struct pt_regs, pstate) >> 3:
+               val = regs->pstate;
+               break;
+       default:
+               val = 0;
+       }
+
+       return val;
+}
+
+/* Valid only for Kernel mode traps. */
+static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+{
+       return regs->sp;
+}
+
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
        return regs->regs[0];
@@ -156,8 +210,15 @@ static inline unsigned long regs_return_value(struct pt_regs *regs)
 struct task_struct;
 int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task);
 
-#define instruction_pointer(regs)      ((unsigned long)(regs)->pc)
+#define GET_IP(regs)           ((unsigned long)(regs)->pc)
+#define SET_IP(regs, value)    ((regs)->pc = ((u64) (value)))
+
+#define GET_FP(ptregs)         ((unsigned long)(ptregs)->regs[29])
+#define SET_FP(ptregs, value)  ((ptregs)->regs[29] = ((u64) (value)))
+
+#include <asm-generic/ptrace.h>
 
+#undef profile_pc
 extern unsigned long profile_pc(struct pt_regs *regs);
 
 #endif /* __ASSEMBLY__ */
index fc9682bfe0020caebf99412131fb760d5b8b870d..43a66881fd57c1b753639aee87958a6b347d4675 100644 (file)
@@ -37,13 +37,17 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
 "2:    ldaxr   %w0, %2\n"
 "      eor     %w1, %w0, %w0, ror #16\n"
 "      cbnz    %w1, 1b\n"
+       /* Serialise against any concurrent lockers */
        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")
+"      nop\n",
+       /* LSE atomics */
+"      mov     %w1, %w0\n"
+"      cas     %w0, %w0, %2\n"
+"      eor     %w1, %w1, %w0\n")
+"      cbnz    %w1, 2b\n"
        : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
        :
        : "memory");
@@ -331,4 +335,14 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
 #define arch_read_relax(lock)  cpu_relax()
 #define arch_write_relax(lock) cpu_relax()
 
+/*
+ * Accesses appearing in program order before a spin_lock() operation
+ * can be reordered with accesses inside the critical section, by virtue
+ * of arch_spin_lock being constructed using acquire semantics.
+ *
+ * In cases where this is problematic (e.g. try_to_wake_up), an
+ * smp_mb__before_spinlock() can restore the required ordering.
+ */
+#define smp_mb__before_spinlock()      smp_mb()
+
 #endif /* __ASM_SPINLOCK_H */
index b9fd8ec790336569ee8fdedb4573e25b3045c29b..1a78d6e2a78b58bf21113de3810785a81a35a29d 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __ASM_SYSREG_H
 #define __ASM_SYSREG_H
 
+#include <linux/stringify.h>
+
 #include <asm/opcodes.h>
 
 /*
 
 #else
 
+#include <linux/types.h>
+
 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    .L__reg_num_x\\num, \\num\n"
@@ -239,6 +243,23 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
        val |= set;
        asm volatile("msr sctlr_el1, %0" : : "r" (val));
 }
+
+/*
+ * Unlike read_cpuid, calls to read_sysreg are never expected to be
+ * optimized away or replaced with synthetic values.
+ */
+#define read_sysreg(r) ({                                      \
+       u64 __val;                                              \
+       asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+       __val;                                                  \
+})
+
+#define write_sysreg(v, r) do {                                        \
+       u64 __val = (u64)v;                                     \
+       asm volatile("msr " __stringify(r) ", %0"               \
+                    : : "r" (__val));                          \
+} while (0)
+
 #endif
 
 #endif /* __ASM_SYSREG_H */
index abd64bd1f6d9f0160a3122555cf23be1a30f87eb..b3325a9cb90fda6c9fb052e560a351d469c83fda 100644 (file)
@@ -47,6 +47,9 @@ typedef unsigned long mm_segment_t;
 struct thread_info {
        unsigned long           flags;          /* low level flags */
        mm_segment_t            addr_limit;     /* address limit */
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       u64                     ttbr0;          /* saved TTBR0_EL1 */
+#endif
        struct task_struct      *task;          /* main task structure */
        int                     preempt_count;  /* 0 => preemptable, <0 => bug */
        int                     cpu;            /* cpu */
index 0685d74572af788b05d44658c7dba7e4fc3742ba..c37c064d7cddd62ab5c3334ff89e3077db3ffa91 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef __ASM_UACCESS_H
 #define __ASM_UACCESS_H
 
+#ifndef __ASSEMBLY__
+
 /*
  * User space memory access functions
  */
@@ -26,6 +28,7 @@
 
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
+#include <asm/kernel-pgtable.h>
 #include <asm/ptrace.h>
 #include <asm/sysreg.h>
 #include <asm/errno.h>
@@ -123,6 +126,85 @@ static inline void set_fs(mm_segment_t fs)
        "       .long           (" #from " - .), (" #to " - .)\n"       \
        "       .popsection\n"
 
+/*
+ * User access enabling/disabling.
+ */
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+static inline void uaccess_ttbr0_disable(void)
+{
+       unsigned long ttbr;
+
+       /* reserved_ttbr0 placed at the end of swapper_pg_dir */
+       ttbr = read_sysreg(ttbr1_el1) + SWAPPER_DIR_SIZE;
+       write_sysreg(ttbr, ttbr0_el1);
+       isb();
+}
+
+static inline void uaccess_ttbr0_enable(void)
+{
+       unsigned long flags;
+
+       /*
+        * Disable interrupts to avoid preemption between reading the 'ttbr0'
+        * variable and the MSR. A context switch could trigger an ASID
+        * roll-over and an update of 'ttbr0'.
+        */
+       local_irq_save(flags);
+       write_sysreg(current_thread_info()->ttbr0, ttbr0_el1);
+       isb();
+       local_irq_restore(flags);
+}
+#else
+static inline void uaccess_ttbr0_disable(void)
+{
+}
+
+static inline void uaccess_ttbr0_enable(void)
+{
+}
+#endif
+
+#define __uaccess_disable(alt)                                         \
+do {                                                                   \
+       if (system_uses_ttbr0_pan())                                    \
+               uaccess_ttbr0_disable();                                \
+       else                                                            \
+               asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), alt,          \
+                               CONFIG_ARM64_PAN));                     \
+} while (0)
+
+#define __uaccess_enable(alt)                                          \
+do {                                                                   \
+       if (system_uses_ttbr0_pan())                                    \
+               uaccess_ttbr0_enable();                                 \
+       else                                                            \
+               asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), alt,          \
+                               CONFIG_ARM64_PAN));                     \
+} while (0)
+
+static inline void uaccess_disable(void)
+{
+       __uaccess_disable(ARM64_HAS_PAN);
+}
+
+static inline void uaccess_enable(void)
+{
+       __uaccess_enable(ARM64_HAS_PAN);
+}
+
+/*
+ * These functions are no-ops when UAO is present.
+ */
+static inline void uaccess_disable_not_uao(void)
+{
+       __uaccess_disable(ARM64_ALT_PAN_NOT_UAO);
+}
+
+static inline void uaccess_enable_not_uao(void)
+{
+       __uaccess_enable(ARM64_ALT_PAN_NOT_UAO);
+}
+
 /*
  * 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()"
@@ -150,8 +232,7 @@ 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_ALT_PAN_NOT_UAO,\
-                       CONFIG_ARM64_PAN));                             \
+       uaccess_enable_not_uao();                                       \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
                __get_user_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr),  \
@@ -172,9 +253,8 @@ do {                                                                        \
        default:                                                        \
                BUILD_BUG();                                            \
        }                                                               \
+       uaccess_disable_not_uao();                                      \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\
-                       CONFIG_ARM64_PAN));                             \
 } while (0)
 
 #define __get_user(x, ptr)                                             \
@@ -219,8 +299,7 @@ do {                                                                        \
 do {                                                                   \
        __typeof__(*(ptr)) __pu_val = (x);                              \
        __chk_user_ptr(ptr);                                            \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\
-                       CONFIG_ARM64_PAN));                             \
+       uaccess_enable_not_uao();                                       \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
                __put_user_asm("strb", "sttrb", "%w", __pu_val, (ptr),  \
@@ -241,8 +320,7 @@ do {                                                                        \
        default:                                                        \
                BUILD_BUG();                                            \
        }                                                               \
-       asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\
-                       CONFIG_ARM64_PAN));                             \
+       uaccess_disable_not_uao();                                      \
 } while (0)
 
 #define __put_user(x, ptr)                                             \
@@ -269,24 +347,39 @@ do {                                                                      \
                -EFAULT;                                                \
 })
 
-extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n);
-extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n);
+extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
+extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
 extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
 extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
 
+static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       check_object_size(to, n, false);
+       return __arch_copy_from_user(to, from, n);
+}
+
+static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       check_object_size(from, n, true);
+       return __arch_copy_to_user(to, from, n);
+}
+
 static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       if (access_ok(VERIFY_READ, from, n))
-               n = __copy_from_user(to, from, n);
-       else /* security hole - plug it */
+       if (access_ok(VERIFY_READ, from, n)) {
+               check_object_size(to, n, false);
+               n = __arch_copy_from_user(to, from, n);
+       } else /* security hole - plug it */
                memset(to, 0, n);
        return n;
 }
 
 static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       if (access_ok(VERIFY_WRITE, to, n))
-               n = __copy_to_user(to, from, n);
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               check_object_size(from, n, true);
+               n = __arch_copy_to_user(to, from, n);
+       }
        return n;
 }
 
@@ -312,4 +405,73 @@ extern long strncpy_from_user(char *dest, const char __user *src, long count);
 extern __must_check long strlen_user(const char __user *str);
 extern __must_check long strnlen_user(const char __user *str, long n);
 
+#else  /* __ASSEMBLY__ */
+
+#include <asm/alternative.h>
+#include <asm/assembler.h>
+#include <asm/kernel-pgtable.h>
+
+/*
+ * User access enabling/disabling macros.
+ */
+       .macro  uaccess_ttbr0_disable, tmp1
+       mrs     \tmp1, ttbr1_el1                // swapper_pg_dir
+       add     \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir
+       msr     ttbr0_el1, \tmp1                // set reserved TTBR0_EL1
+       isb
+       .endm
+
+       .macro  uaccess_ttbr0_enable, tmp1
+       get_thread_info \tmp1
+       ldr     \tmp1, [\tmp1, #TI_TTBR0]       // load saved TTBR0_EL1
+       msr     ttbr0_el1, \tmp1                // set the non-PAN TTBR0_EL1
+       isb
+       .endm
+
+/*
+ * These macros are no-ops when UAO is present.
+ */
+       .macro  uaccess_disable_not_uao, tmp1
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+alternative_if_not ARM64_HAS_PAN
+       uaccess_ttbr0_disable \tmp1
+alternative_else
+       nop
+       nop
+       nop
+       nop
+alternative_endif
+#endif
+alternative_if_not ARM64_ALT_PAN_NOT_UAO
+       nop
+alternative_else
+       SET_PSTATE_PAN(1)
+alternative_endif
+       .endm
+
+       .macro  uaccess_enable_not_uao, tmp1, tmp2
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+alternative_if_not ARM64_HAS_PAN
+       save_and_disable_irq \tmp2              // avoid preemption
+       uaccess_ttbr0_enable \tmp1
+       restore_irq \tmp2
+alternative_else
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+alternative_endif
+#endif
+alternative_if_not ARM64_ALT_PAN_NOT_UAO
+       nop
+alternative_else
+       SET_PSTATE_PAN(0)
+alternative_endif
+       .endm
+
+#endif /* __ASSEMBLY__ */
+
 #endif /* __ASM_UACCESS_H */
index 22d6d8885854da569ce033209d623149e40b4a67..4cf0c17787a84a0f996454e2131b426487b7da65 100644 (file)
@@ -19,4 +19,6 @@
 /* vDSO location */
 #define AT_SYSINFO_EHDR        33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif
index 0b004144ee7120dcc8cd915d835c871107f7bf44..212a8c647218aeafca73f77b546a609a86769dd6 100644 (file)
@@ -26,8 +26,7 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE
        $(call if_changed,objcopy)
 
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
-                                          sys_compat.o entry32.o               \
-                                          ../../arm/kernel/opcodes.o
+                                          sys_compat.o entry32.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
@@ -45,7 +44,7 @@ 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-y                                  += $(arm64-obj-y) vdso/ probes/
 obj-m                                  += $(arm64-obj-m)
 head-y                                 := head.o
 extra-y                                        += $(head-y) vmlinux.lds
index 678f30b05a45580a7805b42a8cea235431b93bda..78f368039c79a76d45d7256ed64dd7535f198ed6 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/arm-smccc.h>
+#include <linux/kprobes.h>
 
 #include <asm/checksum.h>
 
@@ -34,8 +35,8 @@ EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(clear_page);
 
        /* user mem (segment) */
-EXPORT_SYMBOL(__copy_from_user);
-EXPORT_SYMBOL(__copy_to_user);
+EXPORT_SYMBOL(__arch_copy_from_user);
+EXPORT_SYMBOL(__arch_copy_to_user);
 EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(__copy_in_user);
 
@@ -68,6 +69,7 @@ EXPORT_SYMBOL(test_and_change_bit);
 
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
+NOKPROBE_SYMBOL(_mcount);
 #endif
 
        /* arm-smccc */
index c37202c0c838d01a71d56b05d114cd0b419ff480..a0a0f2b20608bad8b9e92e23102c0a93913dc388 100644 (file)
@@ -281,9 +281,9 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
  * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
  */
 #define __user_swpX_asm(data, addr, res, temp, B)              \
+do {                                                           \
+       uaccess_enable();                                       \
        __asm__ __volatile__(                                   \
-       ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,    \
-                   CONFIG_ARM64_PAN)                           \
        "0:     ldxr"B"         %w2, [%3]\n"                    \
        "1:     stxr"B"         %w0, %w1, [%3]\n"               \
        "       cbz             %w0, 2f\n"                      \
@@ -299,11 +299,11 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
        "       .popsection"                                    \
        _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)                \
        : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)              \
-       : "memory")
+       : "memory");                                            \
+       uaccess_disable();                                      \
+} while (0)
 
 #define __user_swp_asm(data, addr, res, temp) \
        __user_swpX_asm(data, addr, res, temp, "")
@@ -366,6 +366,21 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
        return res;
 }
 
+#define        ARM_OPCODE_CONDITION_UNCOND     0xf
+
+static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr)
+{
+       u32 cc_bits  = opcode >> 28;
+
+       if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
+               if ((*aarch32_opcode_cond_checks[cc_bits])(psr))
+                       return ARM_OPCODE_CONDTEST_PASS;
+               else
+                       return ARM_OPCODE_CONDTEST_FAIL;
+       }
+       return ARM_OPCODE_CONDTEST_UNCOND;
+}
+
 /*
  * swp_handler logs the id of calling process, dissects the instruction, sanity
  * checks the memory location, calls emulate_swpX for the actual operation and
@@ -380,7 +395,7 @@ static int swp_handler(struct pt_regs *regs, u32 instr)
 
        type = instr & TYPE_SWPB;
 
-       switch (arm_check_condition(instr, regs->pstate)) {
+       switch (aarch32_check_condition(instr, regs->pstate)) {
        case ARM_OPCODE_CONDTEST_PASS:
                break;
        case ARM_OPCODE_CONDTEST_FAIL:
@@ -461,7 +476,7 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
 {
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
 
-       switch (arm_check_condition(instr, regs->pstate)) {
+       switch (aarch32_check_condition(instr, regs->pstate)) {
        case ARM_OPCODE_CONDTEST_PASS:
                break;
        case ARM_OPCODE_CONDTEST_FAIL:
index bb493d44445f47f8318915bd030e0e21c062b812..956d9529af7a7cc6e243e9b063c79746d8a0cfe1 100644 (file)
@@ -37,6 +37,9 @@ int main(void)
   DEFINE(TI_FLAGS,             offsetof(struct thread_info, flags));
   DEFINE(TI_PREEMPT,           offsetof(struct thread_info, preempt_count));
   DEFINE(TI_ADDR_LIMIT,                offsetof(struct thread_info, addr_limit));
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+  DEFINE(TI_TTBR0,             offsetof(struct thread_info, ttbr0));
+#endif
   DEFINE(TI_TASK,              offsetof(struct thread_info, task));
   DEFINE(TI_CPU,               offsetof(struct thread_info, cpu));
   BLANK();
@@ -50,6 +53,17 @@ int main(void)
   DEFINE(S_X5,                 offsetof(struct pt_regs, regs[5]));
   DEFINE(S_X6,                 offsetof(struct pt_regs, regs[6]));
   DEFINE(S_X7,                 offsetof(struct pt_regs, regs[7]));
+  DEFINE(S_X8,                 offsetof(struct pt_regs, regs[8]));
+  DEFINE(S_X10,                        offsetof(struct pt_regs, regs[10]));
+  DEFINE(S_X12,                        offsetof(struct pt_regs, regs[12]));
+  DEFINE(S_X14,                        offsetof(struct pt_regs, regs[14]));
+  DEFINE(S_X16,                        offsetof(struct pt_regs, regs[16]));
+  DEFINE(S_X18,                        offsetof(struct pt_regs, regs[18]));
+  DEFINE(S_X20,                        offsetof(struct pt_regs, regs[20]));
+  DEFINE(S_X22,                        offsetof(struct pt_regs, regs[22]));
+  DEFINE(S_X24,                        offsetof(struct pt_regs, regs[24]));
+  DEFINE(S_X26,                        offsetof(struct pt_regs, regs[26]));
+  DEFINE(S_X28,                        offsetof(struct pt_regs, regs[28]));
   DEFINE(S_LR,                 offsetof(struct pt_regs, regs[30]));
   DEFINE(S_SP,                 offsetof(struct pt_regs, sp));
 #ifdef CONFIG_COMPAT
@@ -59,6 +73,7 @@ int main(void)
   DEFINE(S_PC,                 offsetof(struct pt_regs, pc));
   DEFINE(S_ORIG_X0,            offsetof(struct pt_regs, orig_x0));
   DEFINE(S_SYSCALLNO,          offsetof(struct pt_regs, syscallno));
+  DEFINE(S_ORIG_ADDR_LIMIT,    offsetof(struct pt_regs, orig_addr_limit));
   DEFINE(S_FRAME_SIZE,         sizeof(struct pt_regs));
   BLANK();
   DEFINE(MM_CONTEXT_ID,                offsetof(struct mm_struct, context.id.counter));
index e6bc988e8dbf0f69fc4b1a48f9a7b4a89ee713f3..06afd04e02c0d05f1e0546230a5d446b8bb06b60 100644 (file)
@@ -87,6 +87,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .capability = ARM64_WORKAROUND_CAVIUM_23154,
                MIDR_RANGE(MIDR_THUNDERX, 0x00, 0x01),
        },
+#endif
+#ifdef CONFIG_CAVIUM_ERRATUM_27456
+       {
+       /* Cavium ThunderX, T88 pass 1.x - 2.1 */
+               .desc = "Cavium erratum 27456",
+               .capability = ARM64_WORKAROUND_CAVIUM_27456,
+               MIDR_RANGE(MIDR_THUNDERX, 0x00,
+                          (1 << MIDR_VARIANT_SHIFT) | 1),
+       },
 #endif
        {
        }
index 7566cad9fa1da5a882ada85b5801a8ae33f4da0c..40ee3f2933e78dffe011e4d2e5615f0d42222e53 100644 (file)
@@ -43,6 +43,7 @@ unsigned int compat_elf_hwcap2 __read_mostly;
 #endif
 
 DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
+EXPORT_SYMBOL(cpu_hwcaps);
 
 #define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
        {                                               \
index c1492ba1f6d14e71c263fa26904fab9980439b4f..6de6d9f43b959fd1cbb45a16bdc33bba524fccd6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/ptrace.h>
+#include <linux/kprobes.h>
 #include <linux/stat.h>
 #include <linux/uaccess.h>
 
@@ -48,6 +49,7 @@ static void mdscr_write(u32 mdscr)
        asm volatile("msr mdscr_el1, %0" :: "r" (mdscr));
        local_dbg_restore(flags);
 }
+NOKPROBE_SYMBOL(mdscr_write);
 
 static u32 mdscr_read(void)
 {
@@ -55,6 +57,7 @@ static u32 mdscr_read(void)
        asm volatile("mrs %0, mdscr_el1" : "=r" (mdscr));
        return mdscr;
 }
+NOKPROBE_SYMBOL(mdscr_read);
 
 /*
  * Allow root to disable self-hosted debug from userspace.
@@ -103,6 +106,7 @@ void enable_debug_monitors(enum dbg_active_el el)
                mdscr_write(mdscr);
        }
 }
+NOKPROBE_SYMBOL(enable_debug_monitors);
 
 void disable_debug_monitors(enum dbg_active_el el)
 {
@@ -123,6 +127,7 @@ void disable_debug_monitors(enum dbg_active_el el)
                mdscr_write(mdscr);
        }
 }
+NOKPROBE_SYMBOL(disable_debug_monitors);
 
 /*
  * OS lock clearing.
@@ -152,7 +157,6 @@ static int debug_monitors_init(void)
        /* Clear the OS lock. */
        on_each_cpu(clear_os_lock, NULL, 1);
        isb();
-       local_dbg_enable();
 
        /* Register hotplug handler. */
        __register_cpu_notifier(&os_lock_nb);
@@ -174,6 +178,7 @@ static void set_regs_spsr_ss(struct pt_regs *regs)
        spsr |= DBG_SPSR_SS;
        regs->pstate = spsr;
 }
+NOKPROBE_SYMBOL(set_regs_spsr_ss);
 
 static void clear_regs_spsr_ss(struct pt_regs *regs)
 {
@@ -183,6 +188,7 @@ static void clear_regs_spsr_ss(struct pt_regs *regs)
        spsr &= ~DBG_SPSR_SS;
        regs->pstate = spsr;
 }
+NOKPROBE_SYMBOL(clear_regs_spsr_ss);
 
 /* EL1 Single Step Handler hooks */
 static LIST_HEAD(step_hook);
@@ -226,6 +232,7 @@ static int call_step_hook(struct pt_regs *regs, unsigned int esr)
 
        return retval;
 }
+NOKPROBE_SYMBOL(call_step_hook);
 
 static int single_step_handler(unsigned long addr, unsigned int esr,
                               struct pt_regs *regs)
@@ -254,6 +261,10 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
                 */
                user_rewind_single_step(current);
        } else {
+#ifdef CONFIG_KPROBES
+               if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
+                       return 0;
+#endif
                if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
                        return 0;
 
@@ -267,6 +278,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
 
        return 0;
 }
+NOKPROBE_SYMBOL(single_step_handler);
 
 /*
  * Breakpoint handler is re-entrant as another breakpoint can
@@ -304,6 +316,7 @@ static int call_break_hook(struct pt_regs *regs, unsigned int esr)
 
        return fn ? fn(regs, esr) : DBG_HOOK_ERROR;
 }
+NOKPROBE_SYMBOL(call_break_hook);
 
 static int brk_handler(unsigned long addr, unsigned int esr,
                       struct pt_regs *regs)
@@ -319,13 +332,21 @@ static int brk_handler(unsigned long addr, unsigned int esr,
                };
 
                force_sig_info(SIGTRAP, &info, current);
-       } else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
-               pr_warning("Unexpected kernel BRK exception at EL1\n");
+       }
+#ifdef CONFIG_KPROBES
+       else if ((esr & BRK64_ESR_MASK) == BRK64_ESR_KPROBES) {
+               if (kprobe_breakpoint_handler(regs, esr) != DBG_HOOK_HANDLED)
+                       return -EFAULT;
+       }
+#endif
+       else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
+               pr_warn("Unexpected kernel BRK exception at EL1\n");
                return -EFAULT;
        }
 
        return 0;
 }
+NOKPROBE_SYMBOL(brk_handler);
 
 int aarch32_break_handler(struct pt_regs *regs)
 {
@@ -370,6 +391,7 @@ int aarch32_break_handler(struct pt_regs *regs)
        force_sig_info(SIGTRAP, &info, current);
        return 0;
 }
+NOKPROBE_SYMBOL(aarch32_break_handler);
 
 static int __init debug_traps_init(void)
 {
@@ -391,6 +413,7 @@ void user_rewind_single_step(struct task_struct *task)
        if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
                set_regs_spsr_ss(task_pt_regs(task));
 }
+NOKPROBE_SYMBOL(user_rewind_single_step);
 
 void user_fastforward_single_step(struct task_struct *task)
 {
@@ -406,6 +429,7 @@ void kernel_enable_single_step(struct pt_regs *regs)
        mdscr_write(mdscr_read() | DBG_MDSCR_SS);
        enable_debug_monitors(DBG_ACTIVE_EL1);
 }
+NOKPROBE_SYMBOL(kernel_enable_single_step);
 
 void kernel_disable_single_step(void)
 {
@@ -413,21 +437,27 @@ void kernel_disable_single_step(void)
        mdscr_write(mdscr_read() & ~DBG_MDSCR_SS);
        disable_debug_monitors(DBG_ACTIVE_EL1);
 }
+NOKPROBE_SYMBOL(kernel_disable_single_step);
 
 int kernel_active_single_step(void)
 {
        WARN_ON(!irqs_disabled());
        return mdscr_read() & DBG_MDSCR_SS;
 }
+NOKPROBE_SYMBOL(kernel_active_single_step);
 
 /* ptrace API */
 void user_enable_single_step(struct task_struct *task)
 {
-       set_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
-       set_regs_spsr_ss(task_pt_regs(task));
+       struct thread_info *ti = task_thread_info(task);
+
+       if (!test_and_set_ti_thread_flag(ti, TIF_SINGLESTEP))
+               set_regs_spsr_ss(task_pt_regs(task));
 }
+NOKPROBE_SYMBOL(user_enable_single_step);
 
 void user_disable_single_step(struct task_struct *task)
 {
        clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
 }
+NOKPROBE_SYMBOL(user_disable_single_step);
index 4eeb17198cfaf598fd403b1e4040c77f5ee3068a..b6abc852f2a142123150662bc6dd6bf5c3de62af 100644 (file)
  *
  */
 
-#include <linux/atomic.h>
 #include <linux/dmi.h>
 #include <linux/efi.h>
-#include <linux/export.h>
-#include <linux/memblock.h>
-#include <linux/mm_types.h>
-#include <linux/bootmem.h>
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/preempt.h>
-#include <linux/rbtree.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
 
-#include <asm/cacheflush.h>
 #include <asm/efi.h>
-#include <asm/tlbflush.h>
-#include <asm/mmu_context.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
 
-struct efi_memory_map memmap;
-
-static u64 efi_system_table;
-
-static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
-
-static struct mm_struct efi_mm = {
-       .mm_rb                  = RB_ROOT,
-       .pgd                    = efi_pgd,
-       .mm_users               = ATOMIC_INIT(2),
-       .mm_count               = ATOMIC_INIT(1),
-       .mmap_sem               = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
-       .page_table_lock        = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
-       .mmlist                 = LIST_HEAD_INIT(efi_mm.mmlist),
-};
-
-static int __init is_normal_ram(efi_memory_desc_t *md)
-{
-       if (md->attribute & EFI_MEMORY_WB)
-               return 1;
-       return 0;
-}
-
-/*
- * Translate a EFI virtual address into a physical address: this is necessary,
- * as some data members of the EFI system table are virtually remapped after
- * SetVirtualAddressMap() has been called.
- */
-static phys_addr_t efi_to_phys(unsigned long addr)
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
 {
-       efi_memory_desc_t *md;
-
-       for_each_efi_memory_desc(&memmap, md) {
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
-                       continue;
-               if (md->virt_addr == 0)
-                       /* no virtual mapping has been installed by the stub */
-                       break;
-               if (md->virt_addr <= addr &&
-                   (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
-                       return md->phys_addr + addr - md->virt_addr;
-       }
-       return addr;
-}
-
-static int __init uefi_init(void)
-{
-       efi_char16_t *c16;
-       void *config_tables;
-       u64 table_size;
-       char vendor[100] = "unknown";
-       int i, retval;
-
-       efi.systab = early_memremap(efi_system_table,
-                                   sizeof(efi_system_table_t));
-       if (efi.systab == NULL) {
-               pr_warn("Unable to map EFI system table.\n");
-               return -ENOMEM;
-       }
-
-       set_bit(EFI_BOOT, &efi.flags);
-       set_bit(EFI_64BIT, &efi.flags);
+       pteval_t prot_val;
 
        /*
-        * Verify the EFI Table
+        * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
+        * executable, everything else can be mapped with the XN bits
+        * set.
         */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
-               pr_err("System table signature incorrect\n");
-               retval = -EINVAL;
-               goto out;
-       }
-       if ((efi.systab->hdr.revision >> 16) < 2)
-               pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
-                       efi.systab->hdr.revision >> 16,
-                       efi.systab->hdr.revision & 0xffff);
-
-       /* Show what we know for posterity */
-       c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
-                            sizeof(vendor) * sizeof(efi_char16_t));
-       if (c16) {
-               for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = c16[i];
-               vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-       }
-
-       pr_info("EFI v%u.%.02u by %s\n",
-               efi.systab->hdr.revision >> 16,
-               efi.systab->hdr.revision & 0xffff, vendor);
-
-       table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
-       config_tables = early_memremap(efi_to_phys(efi.systab->tables),
-                                      table_size);
-       if (config_tables == NULL) {
-               pr_warn("Unable to map EFI config table array.\n");
-               retval = -ENOMEM;
-               goto out;
-       }
-       retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-                                        sizeof(efi_config_table_64_t), NULL);
-
-       early_memunmap(config_tables, table_size);
-out:
-       early_memunmap(efi.systab,  sizeof(efi_system_table_t));
-       return retval;
-}
-
-/*
- * Return true for RAM regions we want to permanently reserve.
- */
-static __init int is_reserve_region(efi_memory_desc_t *md)
-{
-       switch (md->type) {
-       case EFI_LOADER_CODE:
-       case EFI_LOADER_DATA:
-       case EFI_BOOT_SERVICES_CODE:
-       case EFI_BOOT_SERVICES_DATA:
-       case EFI_CONVENTIONAL_MEMORY:
-       case EFI_PERSISTENT_MEMORY:
-               return 0;
-       default:
-               break;
-       }
-       return is_normal_ram(md);
-}
-
-static __init void reserve_regions(void)
-{
-       efi_memory_desc_t *md;
-       u64 paddr, npages, size;
-
-       if (efi_enabled(EFI_DBG))
-               pr_info("Processing EFI memory map:\n");
-
-       for_each_efi_memory_desc(&memmap, md) {
-               paddr = md->phys_addr;
-               npages = md->num_pages;
-
-               if (efi_enabled(EFI_DBG)) {
-                       char buf[64];
-
-                       pr_info("  0x%012llx-0x%012llx %s",
-                               paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
-                               efi_md_typeattr_format(buf, sizeof(buf), md));
-               }
-
-               memrange_efi_to_native(&paddr, &npages);
-               size = npages << PAGE_SHIFT;
-
-               if (is_normal_ram(md))
-                       early_init_dt_add_memory_arch(paddr, size);
-
-               if (is_reserve_region(md)) {
-                       memblock_reserve(paddr, size);
-                       if (efi_enabled(EFI_DBG))
-                               pr_cont("*");
-               }
-
-               if (efi_enabled(EFI_DBG))
-                       pr_cont("\n");
-       }
-
-       set_bit(EFI_MEMMAP, &efi.flags);
-}
-
-void __init efi_init(void)
-{
-       struct efi_fdt_params params;
-
-       /* Grab UEFI information placed in FDT by stub */
-       if (!efi_get_fdt_params(&params))
-               return;
-
-       efi_system_table = params.system_table;
-
-       memblock_reserve(params.mmap & PAGE_MASK,
-                        PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
-       memmap.phys_map = params.mmap;
-       memmap.map = early_memremap(params.mmap, params.mmap_size);
-       if (memmap.map == NULL) {
-               /*
-               * If we are booting via UEFI, the UEFI memory map is the only
-               * description of memory we have, so there is little point in
-               * proceeding if we cannot access it.
-               */
-               panic("Unable to map EFI memory map.\n");
-       }
-       memmap.map_end = memmap.map + params.mmap_size;
-       memmap.desc_size = params.desc_size;
-       memmap.desc_version = params.desc_ver;
-
-       if (uefi_init() < 0)
-               return;
-
-       reserve_regions();
-       early_memunmap(memmap.map, params.mmap_size);
-}
-
-static bool __init efi_virtmap_init(void)
-{
-       efi_memory_desc_t *md;
-
-       init_new_context(NULL, &efi_mm);
-
-       for_each_efi_memory_desc(&memmap, md) {
-               pgprot_t prot;
-
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
-                       continue;
-               if (md->virt_addr == 0)
-                       return false;
-
-               pr_info("  EFI remap 0x%016llx => %p\n",
-                       md->phys_addr, (void *)md->virt_addr);
-
-               /*
-                * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
-                * executable, everything else can be mapped with the XN bits
-                * set.
-                */
-               if (!is_normal_ram(md))
-                       prot = __pgprot(PROT_DEVICE_nGnRE);
-               else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
-                        !PAGE_ALIGNED(md->phys_addr))
-                       prot = PAGE_KERNEL_EXEC;
-               else
-                       prot = PAGE_KERNEL;
-
-               create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr,
-                                  md->num_pages << EFI_PAGE_SHIFT, 
-                                  __pgprot(pgprot_val(prot) | PTE_NG));
-       }
-       return true;
-}
-
-/*
- * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
- * non-early mapping of the UEFI system table and virtual mappings for all
- * EFI_MEMORY_RUNTIME regions.
- */
-static int __init arm64_enable_runtime_services(void)
-{
-       u64 mapsize;
-
-       if (!efi_enabled(EFI_BOOT)) {
-               pr_info("EFI services will not be available.\n");
-               return 0;
-       }
-
-       if (efi_runtime_disabled()) {
-               pr_info("EFI runtime services will be disabled.\n");
-               return 0;
-       }
-
-       pr_info("Remapping and enabling EFI services.\n");
-
-       mapsize = memmap.map_end - memmap.map;
-       memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
-                                                  mapsize);
-       if (!memmap.map) {
-               pr_err("Failed to remap EFI memory map\n");
-               return -ENOMEM;
-       }
-       memmap.map_end = memmap.map + mapsize;
-       efi.memmap = &memmap;
-
-       efi.systab = (__force void *)ioremap_cache(efi_system_table,
-                                                  sizeof(efi_system_table_t));
-       if (!efi.systab) {
-               pr_err("Failed to remap EFI System Table\n");
-               return -ENOMEM;
-       }
-       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
-
-       if (!efi_virtmap_init()) {
-               pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
-               return -ENOMEM;
-       }
-
-       /* Set up runtime services function pointers */
-       efi_native_runtime_setup();
-       set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-
-       efi.runtime_version = efi.systab->hdr.revision;
-
+       if ((md->attribute & EFI_MEMORY_WB) == 0)
+               prot_val = PROT_DEVICE_nGnRE;
+       else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
+                !PAGE_ALIGNED(md->phys_addr))
+               prot_val = pgprot_val(PAGE_KERNEL_EXEC);
+       else
+               prot_val = pgprot_val(PAGE_KERNEL);
+
+       create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
+                          md->num_pages << EFI_PAGE_SHIFT,
+                          __pgprot(prot_val | PTE_NG));
        return 0;
 }
-early_initcall(arm64_enable_runtime_services);
 
 static int __init arm64_dmi_init(void)
 {
@@ -337,23 +54,6 @@ static int __init arm64_dmi_init(void)
 }
 core_initcall(arm64_dmi_init);
 
-static void efi_set_pgd(struct mm_struct *mm)
-{
-       switch_mm(NULL, mm, NULL);
-}
-
-void efi_virtmap_load(void)
-{
-       preempt_disable();
-       efi_set_pgd(&efi_mm);
-}
-
-void efi_virtmap_unload(void)
-{
-       efi_set_pgd(current->active_mm);
-       preempt_enable();
-}
-
 /*
  * UpdateCapsule() depends on the system being shutdown via
  * ResetSystem().
index 1f7f5a2b61bf0de999d80e6ced16bec120f716b6..8606895240bab606c806267aa815e43fc66318db 100644 (file)
 #include <asm/errno.h>
 #include <asm/esr.h>
 #include <asm/irq.h>
+#include <asm/memory.h>
+#include <asm/ptrace.h>
 #include <asm/thread_info.h>
+#include <asm/uaccess.h>
 #include <asm/unistd.h>
 
 /*
        mov     x29, xzr                        // fp pointed to user-space
        .else
        add     x21, sp, #S_FRAME_SIZE
-       .endif
+       get_thread_info tsk
+       /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
+       ldr     x20, [tsk, #TI_ADDR_LIMIT]
+       str     x20, [sp, #S_ORIG_ADDR_LIMIT]
+       mov     x20, #TASK_SIZE_64
+       str     x20, [tsk, #TI_ADDR_LIMIT]
+       .endif /* \el == 0 */
        mrs     x22, elr_el1
        mrs     x23, spsr_el1
        stp     lr, x21, [sp, #S_LR]
+
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       /*
+        * Set the TTBR0 PAN bit in SPSR. When the exception is taken from
+        * EL0, there is no need to check the state of TTBR0_EL1 since
+        * accesses are always enabled.
+        * Note that the meaning of this bit differs from the ARMv8.1 PAN
+        * feature as all TTBR0_EL1 accesses are disabled, not just those to
+        * user mappings.
+        */
+alternative_if_not ARM64_HAS_PAN
+       nop
+alternative_else
+       b       1f                              // skip TTBR0 PAN
+alternative_endif
+
+       .if     \el != 0
+       mrs     x21, ttbr0_el1
+       tst     x21, #0xffff << 48              // Check for the reserved ASID
+       orr     x23, x23, #PSR_PAN_BIT          // Set the emulated PAN in the saved SPSR
+       b.eq    1f                              // TTBR0 access already disabled
+       and     x23, x23, #~PSR_PAN_BIT         // Clear the emulated PAN in the saved SPSR
+       .endif
+
+       uaccess_ttbr0_disable x21
+1:
+#endif
+
        stp     x22, x23, [sp, #S_PC]
 
        /*
        .endm
 
        .macro  kernel_exit, el
+       .if     \el != 0
+       /* Restore the task's original addr_limit. */
+       ldr     x20, [sp, #S_ORIG_ADDR_LIMIT]
+       str     x20, [tsk, #TI_ADDR_LIMIT]
+       .endif
+
        ldp     x21, x22, [sp, #S_PC]           // load ELR, SPSR
        .if     \el == 0
        ct_user_enter
+       .endif
+
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       /*
+        * Restore access to TTBR0_EL1. If returning to EL0, no need for SPSR
+        * PAN bit checking.
+        */
+alternative_if_not ARM64_HAS_PAN
+       nop
+alternative_else
+       b       2f                              // skip TTBR0 PAN
+alternative_endif
+
+       .if     \el != 0
+       tbnz    x22, #_PSR_PAN_BIT, 1f          // Skip re-enabling TTBR0 access if previously disabled
+       .endif
+
+       uaccess_ttbr0_enable x0
+
+       .if     \el == 0
+       /*
+        * Enable errata workarounds only if returning to user. The only
+        * workaround currently required for TTBR0_EL1 changes are for the
+        * Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache
+        * corruption).
+        */
+       post_ttbr0_update_workaround
+       .endif
+1:
+       .if     \el != 0
+       and     x22, x22, #~PSR_PAN_BIT         // ARMv8.0 CPUs do not understand this bit
+       .endif
+2:
+#endif
+
+       .if     \el == 0
        ldr     x23, [sp, #S_SP]                // load return stack pointer
        msr     sp_el0, x23
 #ifdef CONFIG_ARM64_ERRATUM_845719
@@ -152,6 +231,7 @@ alternative_else
 alternative_endif
 #endif
        .endif
+
        msr     elr_el1, x21                    // set up the return data
        msr     spsr_el1, x22
        ldp     x0, x1, [sp, #16 * 0]
@@ -174,10 +254,6 @@ alternative_endif
        eret                                    // return to kernel
        .endm
 
-       .macro  get_thread_info, rd
-       mrs     \rd, sp_el0
-       .endm
-
        .macro  irq_stack_entry
        mov     x19, sp                 // preserve the original sp
 
@@ -242,6 +318,7 @@ tsk .req    x28             // current thread_info
 /*
  * Exception vectors.
  */
+       .pushsection ".entry.text", "ax"
 
        .align  11
 ENTRY(vectors)
@@ -277,7 +354,7 @@ END(vectors)
  * Invalid mode handlers
  */
        .macro  inv_entry, el, reason, regsize = 64
-       kernel_entry el, \regsize
+       kernel_entry \el, \regsize
        mov     x0, sp
        mov     x1, #\reason
        mrs     x2, esr_el1
@@ -336,6 +413,8 @@ el1_sync:
        lsr     x24, x1, #ESR_ELx_EC_SHIFT      // exception class
        cmp     x24, #ESR_ELx_EC_DABT_CUR       // data abort in EL1
        b.eq    el1_da
+       cmp     x24, #ESR_ELx_EC_IABT_CUR       // instruction abort in EL1
+       b.eq    el1_ia
        cmp     x24, #ESR_ELx_EC_SYS64          // configurable trap
        b.eq    el1_undef
        cmp     x24, #ESR_ELx_EC_SP_ALIGN       // stack alignment exception
@@ -347,6 +426,11 @@ el1_sync:
        cmp     x24, #ESR_ELx_EC_BREAKPT_CUR    // debug exception in EL1
        b.ge    el1_dbg
        b       el1_inv
+
+el1_ia:
+       /*
+        * Fall through to the Data abort case
+        */
 el1_da:
        /*
         * Data abort handling
@@ -532,7 +616,7 @@ el0_ia:
        enable_dbg_and_irq
        ct_user_exit
        mov     x0, x26
-       orr     x1, x25, #1 << 24               // use reserved ISS bit for instruction aborts
+       mov     x1, x25
        mov     x2, sp
        bl      do_mem_abort
        b       ret_to_user
@@ -774,6 +858,8 @@ __ni_sys_trace:
        bl      do_ni_syscall
        b       __sys_trace_return
 
+       .popsection                             // .entry.text
+
 /*
  * Special system call wrappers.
  */
index 491ad4124615903e6ebc98f5e063e5aa395236f2..c54df6d8d8fe8e52f7b261c0ca0ed6f2cb1fd21e 100644 (file)
@@ -321,14 +321,14 @@ __create_page_tables:
         * dirty cache lines being evicted.
         */
        mov     x0, x25
-       add     x1, x26, #SWAPPER_DIR_SIZE
+       add     x1, x26, #SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE
        bl      __inval_cache_range
 
        /*
         * Clear the idmap and swapper page tables.
         */
        mov     x0, x25
-       add     x6, x26, #SWAPPER_DIR_SIZE
+       add     x6, x26, #SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE
 1:     stp     xzr, xzr, [x0], #16
        stp     xzr, xzr, [x0], #16
        stp     xzr, xzr, [x0], #16
@@ -407,7 +407,7 @@ __create_page_tables:
         * tables again to remove any speculatively loaded cache lines.
         */
        mov     x0, x25
-       add     x1, x26, #SWAPPER_DIR_SIZE
+       add     x1, x26, #SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE
        dmb     sy
        bl      __inval_cache_range
 
@@ -551,8 +551,9 @@ CPU_LE(     movk    x0, #0x30d0, lsl #16    )       // Clear EE and E0E on LE systems
        b.lt    4f                              // Skip if no PMU present
        mrs     x0, pmcr_el0                    // Disable debug access traps
        ubfx    x0, x0, #11, #5                 // to EL2 and allow access to
-       msr     mdcr_el2, x0                    // all PMU counters from EL1
 4:
+       csel    x0, xzr, x0, lt                 // all PMU counters from EL1
+       msr     mdcr_el2, x0                    // (if they exist)
 
        /* Stage-2 translation */
        msr     vttbr_el2, xzr
@@ -697,6 +698,9 @@ __enable_mmu:
        isb
        bl      __create_page_tables            // recreate kernel mapping
 
+       tlbi    vmalle1                         // Remove any stale TLB entries
+       dsb     nsh
+
        msr     sctlr_el1, x19                  // re-enable the MMU
        isb
        ic      iallu                           // flush instructions fetched
@@ -717,40 +721,25 @@ __primary_switch:
         * Iterate over each entry in the relocation table, and apply the
         * relocations in place.
         */
-       ldr     w8, =__dynsym_offset            // offset to symbol table
        ldr     w9, =__rela_offset              // offset to reloc table
        ldr     w10, =__rela_size               // size of reloc table
 
        mov_q   x11, KIMAGE_VADDR               // default virtual offset
        add     x11, x11, x23                   // actual virtual offset
-       add     x8, x8, x11                     // __va(.dynsym)
        add     x9, x9, x11                     // __va(.rela)
        add     x10, x9, x10                    // __va(.rela) + sizeof(.rela)
 
 0:     cmp     x9, x10
-       b.hs    2f
+       b.hs    1f
        ldp     x11, x12, [x9], #24
        ldr     x13, [x9, #-8]
        cmp     w12, #R_AARCH64_RELATIVE
-       b.ne    1f
+       b.ne    0b
        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:
+1:
 #endif
        ldr     x8, =__primary_switched
        br      x8
index b45c95d34b8323e74992e0a4a56e6da0e1257c60..367a954f9937979c574a805bab2e3cbad706d202 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/cpu_pm.h>
 #include <linux/errno.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/kprobes.h>
 #include <linux/perf_event.h>
 #include <linux/ptrace.h>
 #include <linux/smp.h>
@@ -127,6 +128,7 @@ static u64 read_wb_reg(int reg, int n)
 
        return val;
 }
+NOKPROBE_SYMBOL(read_wb_reg);
 
 static void write_wb_reg(int reg, int n, u64 val)
 {
@@ -140,6 +142,7 @@ static void write_wb_reg(int reg, int n, u64 val)
        }
        isb();
 }
+NOKPROBE_SYMBOL(write_wb_reg);
 
 /*
  * Convert a breakpoint privilege level to the corresponding exception
@@ -157,6 +160,7 @@ static enum dbg_active_el debug_exception_level(int privilege)
                return -EINVAL;
        }
 }
+NOKPROBE_SYMBOL(debug_exception_level);
 
 enum hw_breakpoint_ops {
        HW_BREAKPOINT_INSTALL,
@@ -575,6 +579,7 @@ static void toggle_bp_registers(int reg, enum dbg_active_el el, int enable)
                write_wb_reg(reg, i, ctrl);
        }
 }
+NOKPROBE_SYMBOL(toggle_bp_registers);
 
 /*
  * Debug exception handlers.
@@ -654,6 +659,7 @@ unlock:
 
        return 0;
 }
+NOKPROBE_SYMBOL(breakpoint_handler);
 
 static int watchpoint_handler(unsigned long addr, unsigned int esr,
                              struct pt_regs *regs)
@@ -756,6 +762,7 @@ unlock:
 
        return 0;
 }
+NOKPROBE_SYMBOL(watchpoint_handler);
 
 /*
  * Handle single-step exception.
@@ -813,6 +820,7 @@ int reinstall_suspended_bps(struct pt_regs *regs)
 
        return !handled_exception;
 }
+NOKPROBE_SYMBOL(reinstall_suspended_bps);
 
 /*
  * Context-switcher for restoring suspended breakpoints.
index c08b9ad6f42931e8766d0186daa51a6cce8dbe39..750f422f3f2c263a4a13cc59d20baa12b304a835 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/cacheflush.h>
 #include <asm/debug-monitors.h>
 #include <asm/fixmap.h>
+#include <asm/opcodes.h>
 #include <asm/insn.h>
 
 #define AARCH64_INSN_SF_BIT    BIT(31)
@@ -162,6 +163,32 @@ static bool __kprobes __aarch64_insn_hotpatch_safe(u32 insn)
                aarch64_insn_is_nop(insn);
 }
 
+bool __kprobes aarch64_insn_uses_literal(u32 insn)
+{
+       /* ldr/ldrsw (literal), prfm */
+
+       return aarch64_insn_is_ldr_lit(insn) ||
+               aarch64_insn_is_ldrsw_lit(insn) ||
+               aarch64_insn_is_adr_adrp(insn) ||
+               aarch64_insn_is_prfm_lit(insn);
+}
+
+bool __kprobes aarch64_insn_is_branch(u32 insn)
+{
+       /* b, bl, cb*, tb*, b.cond, br, blr */
+
+       return aarch64_insn_is_b(insn) ||
+               aarch64_insn_is_bl(insn) ||
+               aarch64_insn_is_cbz(insn) ||
+               aarch64_insn_is_cbnz(insn) ||
+               aarch64_insn_is_tbz(insn) ||
+               aarch64_insn_is_tbnz(insn) ||
+               aarch64_insn_is_ret(insn) ||
+               aarch64_insn_is_br(insn) ||
+               aarch64_insn_is_blr(insn) ||
+               aarch64_insn_is_bcond(insn);
+}
+
 /*
  * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a
  * Section B2.6.5 "Concurrent modification and execution of instructions":
@@ -1116,6 +1143,14 @@ u32 aarch64_set_branch_offset(u32 insn, s32 offset)
        BUG();
 }
 
+/*
+ * Extract the Op/CR data from a msr/mrs instruction.
+ */
+u32 aarch64_insn_extract_system_reg(u32 insn)
+{
+       return (insn & 0x1FFFE0) >> 5;
+}
+
 bool aarch32_insn_is_wide(u32 insn)
 {
        return insn >= 0xe800;
@@ -1141,3 +1176,101 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn)
 {
        return insn & CRM_MASK;
 }
+
+static bool __kprobes __check_eq(unsigned long pstate)
+{
+       return (pstate & PSR_Z_BIT) != 0;
+}
+
+static bool __kprobes __check_ne(unsigned long pstate)
+{
+       return (pstate & PSR_Z_BIT) == 0;
+}
+
+static bool __kprobes __check_cs(unsigned long pstate)
+{
+       return (pstate & PSR_C_BIT) != 0;
+}
+
+static bool __kprobes __check_cc(unsigned long pstate)
+{
+       return (pstate & PSR_C_BIT) == 0;
+}
+
+static bool __kprobes __check_mi(unsigned long pstate)
+{
+       return (pstate & PSR_N_BIT) != 0;
+}
+
+static bool __kprobes __check_pl(unsigned long pstate)
+{
+       return (pstate & PSR_N_BIT) == 0;
+}
+
+static bool __kprobes __check_vs(unsigned long pstate)
+{
+       return (pstate & PSR_V_BIT) != 0;
+}
+
+static bool __kprobes __check_vc(unsigned long pstate)
+{
+       return (pstate & PSR_V_BIT) == 0;
+}
+
+static bool __kprobes __check_hi(unsigned long pstate)
+{
+       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (pstate & PSR_C_BIT) != 0;
+}
+
+static bool __kprobes __check_ls(unsigned long pstate)
+{
+       pstate &= ~(pstate >> 1);       /* PSR_C_BIT &= ~PSR_Z_BIT */
+       return (pstate & PSR_C_BIT) == 0;
+}
+
+static bool __kprobes __check_ge(unsigned long pstate)
+{
+       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
+       return (pstate & PSR_N_BIT) == 0;
+}
+
+static bool __kprobes __check_lt(unsigned long pstate)
+{
+       pstate ^= (pstate << 3);        /* PSR_N_BIT ^= PSR_V_BIT */
+       return (pstate & PSR_N_BIT) != 0;
+}
+
+static bool __kprobes __check_gt(unsigned long pstate)
+{
+       /*PSR_N_BIT ^= PSR_V_BIT */
+       unsigned long temp = pstate ^ (pstate << 3);
+
+       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
+       return (temp & PSR_N_BIT) == 0;
+}
+
+static bool __kprobes __check_le(unsigned long pstate)
+{
+       /*PSR_N_BIT ^= PSR_V_BIT */
+       unsigned long temp = pstate ^ (pstate << 3);
+
+       temp |= (pstate << 1);  /*PSR_N_BIT |= PSR_Z_BIT */
+       return (temp & PSR_N_BIT) != 0;
+}
+
+static bool __kprobes __check_al(unsigned long pstate)
+{
+       return true;
+}
+
+/*
+ * Note that the ARMv8 ARM calls condition code 0b1111 "nv", but states that
+ * it behaves identically to 0b1110 ("al").
+ */
+pstate_check_t * const aarch32_opcode_cond_checks[16] = {
+       __check_eq, __check_ne, __check_cs, __check_cc,
+       __check_mi, __check_pl, __check_vs, __check_vc,
+       __check_hi, __check_ls, __check_ge, __check_lt,
+       __check_gt, __check_le, __check_al, __check_al
+};
index bcac81e600b9af09341cffdd80d83880626f77b2..814d0c51b2f91b2e2e696ad81ec8066f3ed0d5be 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
+#include <linux/kprobes.h>
 #include <asm/traps.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
@@ -218,6 +219,7 @@ static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
        kgdb_handle_exception(1, SIGTRAP, 0, regs);
        return 0;
 }
+NOKPROBE_SYMBOL(kgdb_brk_fn)
 
 static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
@@ -226,12 +228,14 @@ static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
 
        return 0;
 }
+NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
        kgdb_handle_exception(1, SIGTRAP, 0, regs);
        return 0;
 }
+NOKPROBE_SYMBOL(kgdb_step_brk_fn);
 
 static struct break_hook kgdb_brkpt_hook = {
        .esr_mask       = 0xffffffff,
diff --git a/arch/arm64/kernel/probes/Makefile b/arch/arm64/kernel/probes/Makefile
new file mode 100644 (file)
index 0000000..ce06312
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_KPROBES)          += kprobes.o decode-insn.o      \
+                                  kprobes_trampoline.o         \
+                                  simulate-insn.o
diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c
new file mode 100644 (file)
index 0000000..f7931d9
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * arch/arm64/kernel/probes/decode-insn.c
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <asm/kprobes.h>
+#include <asm/insn.h>
+#include <asm/sections.h>
+
+#include "decode-insn.h"
+#include "simulate-insn.h"
+
+static bool __kprobes aarch64_insn_is_steppable(u32 insn)
+{
+       /*
+        * Branch instructions will write a new value into the PC which is
+        * likely to be relative to the XOL address and therefore invalid.
+        * Deliberate generation of an exception during stepping is also not
+        * currently safe. Lastly, MSR instructions can do any number of nasty
+        * things we can't handle during single-stepping.
+        */
+       if (aarch64_get_insn_class(insn) == AARCH64_INSN_CLS_BR_SYS) {
+               if (aarch64_insn_is_branch(insn) ||
+                   aarch64_insn_is_msr_imm(insn) ||
+                   aarch64_insn_is_msr_reg(insn) ||
+                   aarch64_insn_is_exception(insn) ||
+                   aarch64_insn_is_eret(insn))
+                       return false;
+
+               /*
+                * The MRS instruction may not return a correct value when
+                * executing in the single-stepping environment. We do make one
+                * exception, for reading the DAIF bits.
+                */
+               if (aarch64_insn_is_mrs(insn))
+                       return aarch64_insn_extract_system_reg(insn)
+                            != AARCH64_INSN_SPCLREG_DAIF;
+
+               /*
+                * The HINT instruction is is problematic when single-stepping,
+                * except for the NOP case.
+                */
+               if (aarch64_insn_is_hint(insn))
+                       return aarch64_insn_is_nop(insn);
+
+               return true;
+       }
+
+       /*
+        * Instructions which load PC relative literals are not going to work
+        * when executed from an XOL slot. Instructions doing an exclusive
+        * load/store are not going to complete successfully when single-step
+        * exception handling happens in the middle of the sequence.
+        */
+       if (aarch64_insn_uses_literal(insn) ||
+           aarch64_insn_is_exclusive(insn))
+               return false;
+
+       return true;
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ */
+static enum kprobe_insn __kprobes
+arm_probe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+       /*
+        * Instructions reading or modifying the PC won't work from the XOL
+        * slot.
+        */
+       if (aarch64_insn_is_steppable(insn))
+               return INSN_GOOD;
+
+       if (aarch64_insn_is_bcond(insn)) {
+               asi->handler = simulate_b_cond;
+       } else if (aarch64_insn_is_cbz(insn) ||
+           aarch64_insn_is_cbnz(insn)) {
+               asi->handler = simulate_cbz_cbnz;
+       } else if (aarch64_insn_is_tbz(insn) ||
+           aarch64_insn_is_tbnz(insn)) {
+               asi->handler = simulate_tbz_tbnz;
+       } else if (aarch64_insn_is_adr_adrp(insn)) {
+               asi->handler = simulate_adr_adrp;
+       } else if (aarch64_insn_is_b(insn) ||
+           aarch64_insn_is_bl(insn)) {
+               asi->handler = simulate_b_bl;
+       } else if (aarch64_insn_is_br(insn) ||
+           aarch64_insn_is_blr(insn) ||
+           aarch64_insn_is_ret(insn)) {
+               asi->handler = simulate_br_blr_ret;
+       } else if (aarch64_insn_is_ldr_lit(insn)) {
+               asi->handler = simulate_ldr_literal;
+       } else if (aarch64_insn_is_ldrsw_lit(insn)) {
+               asi->handler = simulate_ldrsw_literal;
+       } else {
+               /*
+                * Instruction cannot be stepped out-of-line and we don't
+                * (yet) simulate it.
+                */
+               return INSN_REJECTED;
+       }
+
+       return INSN_GOOD_NO_SLOT;
+}
+
+static bool __kprobes
+is_probed_address_atomic(kprobe_opcode_t *scan_start, kprobe_opcode_t *scan_end)
+{
+       while (scan_start > scan_end) {
+               /*
+                * atomic region starts from exclusive load and ends with
+                * exclusive store.
+                */
+               if (aarch64_insn_is_store_ex(le32_to_cpu(*scan_start)))
+                       return false;
+               else if (aarch64_insn_is_load_ex(le32_to_cpu(*scan_start)))
+                       return true;
+               scan_start--;
+       }
+
+       return false;
+}
+
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi)
+{
+       enum kprobe_insn decoded;
+       kprobe_opcode_t insn = le32_to_cpu(*addr);
+       kprobe_opcode_t *scan_start = addr - 1;
+       kprobe_opcode_t *scan_end = addr - MAX_ATOMIC_CONTEXT_SIZE;
+#if defined(CONFIG_MODULES) && defined(MODULES_VADDR)
+       struct module *mod;
+#endif
+
+       if (addr >= (kprobe_opcode_t *)_text &&
+           scan_end < (kprobe_opcode_t *)_text)
+               scan_end = (kprobe_opcode_t *)_text;
+#if defined(CONFIG_MODULES) && defined(MODULES_VADDR)
+       else {
+               preempt_disable();
+               mod = __module_address((unsigned long)addr);
+               if (mod && within_module_init((unsigned long)addr, mod) &&
+                       !within_module_init((unsigned long)scan_end, mod))
+                       scan_end = (kprobe_opcode_t *)mod->module_init;
+               else if (mod && within_module_core((unsigned long)addr, mod) &&
+                       !within_module_core((unsigned long)scan_end, mod))
+                       scan_end = (kprobe_opcode_t *)mod->module_core;
+               preempt_enable();
+       }
+#endif
+       decoded = arm_probe_decode_insn(insn, asi);
+
+       if (decoded == INSN_REJECTED ||
+                       is_probed_address_atomic(scan_start, scan_end))
+               return INSN_REJECTED;
+
+       return decoded;
+}
diff --git a/arch/arm64/kernel/probes/decode-insn.h b/arch/arm64/kernel/probes/decode-insn.h
new file mode 100644 (file)
index 0000000..d438289
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm64/kernel/probes/decode-insn.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ARM_KERNEL_KPROBES_ARM64_H
+#define _ARM_KERNEL_KPROBES_ARM64_H
+
+/*
+ * ARM strongly recommends a limit of 128 bytes between LoadExcl and
+ * StoreExcl instructions in a single thread of execution. So keep the
+ * max atomic context size as 32.
+ */
+#define MAX_ATOMIC_CONTEXT_SIZE        (128 / sizeof(kprobe_opcode_t))
+
+enum kprobe_insn {
+       INSN_REJECTED,
+       INSN_GOOD_NO_SLOT,
+       INSN_GOOD,
+};
+
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi);
+
+#endif /* _ARM_KERNEL_KPROBES_ARM64_H */
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
new file mode 100644 (file)
index 0000000..1ee93c7
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * arch/arm64/kernel/probes/kprobes.c
+ *
+ * Kprobes support for ARM64
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ * Author: Sandeepa Prabhu <sandeepa.prabhu@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include <linux/kasan.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/stop_machine.h>
+#include <linux/stringify.h>
+#include <asm/traps.h>
+#include <asm/ptrace.h>
+#include <asm/cacheflush.h>
+#include <asm/debug-monitors.h>
+#include <asm/system_misc.h>
+#include <asm/insn.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm-generic/sections.h>
+
+#include "decode-insn.h"
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+static void __kprobes
+post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
+
+static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
+{
+       /* prepare insn slot */
+       p->ainsn.insn[0] = cpu_to_le32(p->opcode);
+
+       flush_icache_range((uintptr_t) (p->ainsn.insn),
+                          (uintptr_t) (p->ainsn.insn) +
+                          MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+
+       /*
+        * Needs restoring of return address after stepping xol.
+        */
+       p->ainsn.restore = (unsigned long) p->addr +
+         sizeof(kprobe_opcode_t);
+}
+
+static void __kprobes arch_prepare_simulate(struct kprobe *p)
+{
+       /* This instructions is not executed xol. No need to adjust the PC */
+       p->ainsn.restore = 0;
+}
+
+static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
+{
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       if (p->ainsn.handler)
+               p->ainsn.handler((u32)p->opcode, (long)p->addr, regs);
+
+       /* single step simulated, now go for post processing */
+       post_kprobe_handler(kcb, regs);
+}
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+       unsigned long probe_addr = (unsigned long)p->addr;
+       extern char __start_rodata[];
+       extern char __end_rodata[];
+
+       if (probe_addr & 0x3)
+               return -EINVAL;
+
+       /* copy instruction */
+       p->opcode = le32_to_cpu(*p->addr);
+
+       if (in_exception_text(probe_addr))
+               return -EINVAL;
+       if (probe_addr >= (unsigned long) __start_rodata &&
+           probe_addr <= (unsigned long) __end_rodata)
+               return -EINVAL;
+
+       /* decode instruction */
+       switch (arm_kprobe_decode_insn(p->addr, &p->ainsn)) {
+       case INSN_REJECTED:     /* insn not supported */
+               return -EINVAL;
+
+       case INSN_GOOD_NO_SLOT: /* insn need simulation */
+               p->ainsn.insn = NULL;
+               break;
+
+       case INSN_GOOD: /* instruction uses slot */
+               p->ainsn.insn = get_insn_slot();
+               if (!p->ainsn.insn)
+                       return -ENOMEM;
+               break;
+       };
+
+       /* prepare the instruction */
+       if (p->ainsn.insn)
+               arch_prepare_ss_slot(p);
+       else
+               arch_prepare_simulate(p);
+
+       return 0;
+}
+
+static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
+{
+       void *addrs[1];
+       u32 insns[1];
+
+       addrs[0] = (void *)addr;
+       insns[0] = (u32)opcode;
+
+       return aarch64_insn_patch_text(addrs, insns, 1);
+}
+
+/* arm kprobe: install breakpoint in text */
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+       patch_text(p->addr, BRK64_OPCODE_KPROBES);
+}
+
+/* disarm kprobe: remove breakpoint from text */
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+       patch_text(p->addr, p->opcode);
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+       if (p->ainsn.insn) {
+               free_insn_slot(p->ainsn.insn, 0);
+               p->ainsn.insn = NULL;
+       }
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+       kcb->prev_kprobe.kp = kprobe_running();
+       kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+       __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
+       kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p)
+{
+       __this_cpu_write(current_kprobe, p);
+}
+
+/*
+ * The D-flag (Debug mask) is set (masked) upon debug exception entry.
+ * Kprobes needs to clear (unmask) D-flag -ONLY- in case of recursive
+ * probe i.e. when probe hit from kprobe handler context upon
+ * executing the pre/post handlers. In this case we return with
+ * D-flag clear so that single-stepping can be carried-out.
+ *
+ * Leave D-flag set in all other cases.
+ */
+static void __kprobes
+spsr_set_debug_flag(struct pt_regs *regs, int mask)
+{
+       unsigned long spsr = regs->pstate;
+
+       if (mask)
+               spsr |= PSR_D_BIT;
+       else
+               spsr &= ~PSR_D_BIT;
+
+       regs->pstate = spsr;
+}
+
+/*
+ * Interrupts need to be disabled before single-step mode is set, and not
+ * reenabled until after single-step mode ends.
+ * Without disabling interrupt on local CPU, there is a chance of
+ * interrupt occurrence in the period of exception return and  start of
+ * out-of-line single-step, that result in wrongly single stepping
+ * into the interrupt handler.
+ */
+static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
+                                               struct pt_regs *regs)
+{
+       kcb->saved_irqflag = regs->pstate;
+       regs->pstate |= PSR_I_BIT;
+}
+
+static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
+                                               struct pt_regs *regs)
+{
+       if (kcb->saved_irqflag & PSR_I_BIT)
+               regs->pstate |= PSR_I_BIT;
+       else
+               regs->pstate &= ~PSR_I_BIT;
+}
+
+static void __kprobes
+set_ss_context(struct kprobe_ctlblk *kcb, unsigned long addr)
+{
+       kcb->ss_ctx.ss_pending = true;
+       kcb->ss_ctx.match_addr = addr + sizeof(kprobe_opcode_t);
+}
+
+static void __kprobes clear_ss_context(struct kprobe_ctlblk *kcb)
+{
+       kcb->ss_ctx.ss_pending = false;
+       kcb->ss_ctx.match_addr = 0;
+}
+
+static void __kprobes setup_singlestep(struct kprobe *p,
+                                      struct pt_regs *regs,
+                                      struct kprobe_ctlblk *kcb, int reenter)
+{
+       unsigned long slot;
+
+       if (reenter) {
+               save_previous_kprobe(kcb);
+               set_current_kprobe(p);
+               kcb->kprobe_status = KPROBE_REENTER;
+       } else {
+               kcb->kprobe_status = KPROBE_HIT_SS;
+       }
+
+
+       if (p->ainsn.insn) {
+               /* prepare for single stepping */
+               slot = (unsigned long)p->ainsn.insn;
+
+               set_ss_context(kcb, slot);      /* mark pending ss */
+
+               if (kcb->kprobe_status == KPROBE_REENTER)
+                       spsr_set_debug_flag(regs, 0);
+               else
+                       WARN_ON(regs->pstate & PSR_D_BIT);
+
+               /* IRQs and single stepping do not mix well. */
+               kprobes_save_local_irqflag(kcb, regs);
+               kernel_enable_single_step(regs);
+               instruction_pointer_set(regs, slot);
+       } else {
+               /* insn simulation */
+               arch_simulate_insn(p, regs);
+       }
+}
+
+static int __kprobes reenter_kprobe(struct kprobe *p,
+                                   struct pt_regs *regs,
+                                   struct kprobe_ctlblk *kcb)
+{
+       switch (kcb->kprobe_status) {
+       case KPROBE_HIT_SSDONE:
+       case KPROBE_HIT_ACTIVE:
+               kprobes_inc_nmissed_count(p);
+               setup_singlestep(p, regs, kcb, 1);
+               break;
+       case KPROBE_HIT_SS:
+       case KPROBE_REENTER:
+               pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr);
+               dump_kprobe(p);
+               BUG();
+               break;
+       default:
+               WARN_ON(1);
+               return 0;
+       }
+
+       return 1;
+}
+
+static void __kprobes
+post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
+{
+       struct kprobe *cur = kprobe_running();
+
+       if (!cur)
+               return;
+
+       /* return addr restore if non-branching insn */
+       if (cur->ainsn.restore != 0)
+               instruction_pointer_set(regs, cur->ainsn.restore);
+
+       /* restore back original saved kprobe variables and continue */
+       if (kcb->kprobe_status == KPROBE_REENTER) {
+               restore_previous_kprobe(kcb);
+               return;
+       }
+       /* call post handler */
+       kcb->kprobe_status = KPROBE_HIT_SSDONE;
+       if (cur->post_handler)  {
+               /* post_handler can hit breakpoint and single step
+                * again, so we enable D-flag for recursive exception.
+                */
+               cur->post_handler(cur, regs, 0);
+       }
+
+       reset_current_kprobe();
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
+{
+       struct kprobe *cur = kprobe_running();
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       switch (kcb->kprobe_status) {
+       case KPROBE_HIT_SS:
+       case KPROBE_REENTER:
+               /*
+                * We are here because the instruction being single
+                * stepped caused a page fault. We reset the current
+                * kprobe and the ip points back to the probe address
+                * and allow the page fault handler to continue as a
+                * normal page fault.
+                */
+               instruction_pointer_set(regs, (unsigned long) cur->addr);
+               if (!instruction_pointer(regs))
+                       BUG();
+
+               kernel_disable_single_step();
+               if (kcb->kprobe_status == KPROBE_REENTER)
+                       spsr_set_debug_flag(regs, 1);
+
+               if (kcb->kprobe_status == KPROBE_REENTER)
+                       restore_previous_kprobe(kcb);
+               else
+                       reset_current_kprobe();
+
+               break;
+       case KPROBE_HIT_ACTIVE:
+       case KPROBE_HIT_SSDONE:
+               /*
+                * We increment the nmissed count for accounting,
+                * we can also use npre/npostfault count for accounting
+                * these specific fault cases.
+                */
+               kprobes_inc_nmissed_count(cur);
+
+               /*
+                * We come here because instructions in the pre/post
+                * handler caused the page_fault, this could happen
+                * if handler tries to access user space by
+                * copy_from_user(), get_user() etc. Let the
+                * user-specified handler try to fix it first.
+                */
+               if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
+                       return 1;
+
+               /*
+                * In case the user-specified fault handler returned
+                * zero, try to fix up.
+                */
+               if (fixup_exception(regs))
+                       return 1;
+       }
+       return 0;
+}
+
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
+{
+       return NOTIFY_DONE;
+}
+
+static void __kprobes kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p, *cur_kprobe;
+       struct kprobe_ctlblk *kcb;
+       unsigned long addr = instruction_pointer(regs);
+
+       kcb = get_kprobe_ctlblk();
+       cur_kprobe = kprobe_running();
+
+       p = get_kprobe((kprobe_opcode_t *) addr);
+
+       if (p) {
+               if (cur_kprobe) {
+                       if (reenter_kprobe(p, regs, kcb))
+                               return;
+               } else {
+                       /* Probe hit */
+                       set_current_kprobe(p);
+                       kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+                       /*
+                        * If we have no pre-handler or it returned 0, we
+                        * continue with normal processing.  If we have a
+                        * pre-handler and it returned non-zero, it prepped
+                        * for calling the break_handler below on re-entry,
+                        * so get out doing nothing more here.
+                        *
+                        * pre_handler can hit a breakpoint and can step thru
+                        * before return, keep PSTATE D-flag enabled until
+                        * pre_handler return back.
+                        */
+                       if (!p->pre_handler || !p->pre_handler(p, regs)) {
+                               setup_singlestep(p, regs, kcb, 0);
+                               return;
+                       }
+               }
+       } else if ((le32_to_cpu(*(kprobe_opcode_t *) addr) ==
+           BRK64_OPCODE_KPROBES) && cur_kprobe) {
+               /* We probably hit a jprobe.  Call its break handler. */
+               if (cur_kprobe->break_handler  &&
+                    cur_kprobe->break_handler(cur_kprobe, regs)) {
+                       setup_singlestep(cur_kprobe, regs, kcb, 0);
+                       return;
+               }
+       }
+       /*
+        * The breakpoint instruction was removed right
+        * after we hit it.  Another cpu has removed
+        * either a probepoint or a debugger breakpoint
+        * at this address.  In either case, no further
+        * handling of this interrupt is appropriate.
+        * Return back to original instruction, and continue.
+        */
+}
+
+static int __kprobes
+kprobe_ss_hit(struct kprobe_ctlblk *kcb, unsigned long addr)
+{
+       if ((kcb->ss_ctx.ss_pending)
+           && (kcb->ss_ctx.match_addr == addr)) {
+               clear_ss_context(kcb);  /* clear pending ss */
+               return DBG_HOOK_HANDLED;
+       }
+       /* not ours, kprobes should ignore it */
+       return DBG_HOOK_ERROR;
+}
+
+int __kprobes
+kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
+{
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       int retval;
+
+       /* return error if this is not our step */
+       retval = kprobe_ss_hit(kcb, instruction_pointer(regs));
+
+       if (retval == DBG_HOOK_HANDLED) {
+               kprobes_restore_local_irqflag(kcb, regs);
+               kernel_disable_single_step();
+
+               if (kcb->kprobe_status == KPROBE_REENTER)
+                       spsr_set_debug_flag(regs, 1);
+
+               post_kprobe_handler(kcb, regs);
+       }
+
+       return retval;
+}
+
+int __kprobes
+kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr)
+{
+       kprobe_handler(regs);
+       return DBG_HOOK_HANDLED;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       kcb->jprobe_saved_regs = *regs;
+       /*
+        * Since we can't be sure where in the stack frame "stacked"
+        * pass-by-value arguments are stored we just don't try to
+        * duplicate any of the stack. Do not use jprobes on functions that
+        * use more than 64 bytes (after padding each to an 8 byte boundary)
+        * of arguments, or pass individual arguments larger than 16 bytes.
+        */
+
+       instruction_pointer_set(regs, (unsigned long) jp->entry);
+       preempt_disable();
+       pause_graph_tracing();
+       return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+       /*
+        * Jprobe handler return by entering break exception,
+        * encoded same as kprobe, but with following conditions
+        * -a special PC to identify it from the other kprobes.
+        * -restore stack addr to original saved pt_regs
+        */
+       asm volatile("                          mov sp, %0      \n"
+                    "jprobe_return_break:      brk %1          \n"
+                    :
+                    : "r" (kcb->jprobe_saved_regs.sp),
+                      "I" (BRK64_ESR_KPROBES)
+                    : "memory");
+
+       unreachable();
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       long stack_addr = kcb->jprobe_saved_regs.sp;
+       long orig_sp = kernel_stack_pointer(regs);
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       extern const char jprobe_return_break[];
+
+       if (instruction_pointer(regs) != (u64) jprobe_return_break)
+               return 0;
+
+       if (orig_sp != stack_addr) {
+               struct pt_regs *saved_regs =
+                   (struct pt_regs *)kcb->jprobe_saved_regs.sp;
+               pr_err("current sp %lx does not match saved sp %lx\n",
+                      orig_sp, stack_addr);
+               pr_err("Saved registers for jprobe %p\n", jp);
+               show_regs(saved_regs);
+               pr_err("Current registers\n");
+               show_regs(regs);
+               BUG();
+       }
+       unpause_graph_tracing();
+       *regs = kcb->jprobe_saved_regs;
+       preempt_enable_no_resched();
+       return 1;
+}
+
+bool arch_within_kprobe_blacklist(unsigned long addr)
+{
+       extern char __idmap_text_start[], __idmap_text_end[];
+
+       if ((addr >= (unsigned long)__kprobes_text_start &&
+           addr < (unsigned long)__kprobes_text_end) ||
+           (addr >= (unsigned long)__entry_text_start &&
+           addr < (unsigned long)__entry_text_end) ||
+           (addr >= (unsigned long)__idmap_text_start &&
+           addr < (unsigned long)__idmap_text_end) ||
+           !!search_exception_tables(addr))
+               return true;
+
+
+       return false;
+}
+
+void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
+{
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_head *head, empty_rp;
+       struct hlist_node *tmp;
+       unsigned long flags, orig_ret_address = 0;
+       unsigned long trampoline_address =
+               (unsigned long)&kretprobe_trampoline;
+       kprobe_opcode_t *correct_ret_addr = NULL;
+
+       INIT_HLIST_HEAD(&empty_rp);
+       kretprobe_hash_lock(current, &head, &flags);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because multiple functions in the call path have
+        * return probes installed on them, and/or more than one
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always pushed into the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the (chronologically) first instance's ret_addr
+        *       will be the real return address, and all the rest will
+        *       point to kretprobe_trampoline.
+        */
+       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+       correct_ret_addr = ri->ret_addr;
+       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               if (ri->rp && ri->rp->handler) {
+                       __this_cpu_write(current_kprobe, &ri->rp->kp);
+                       get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+                       ri->ret_addr = correct_ret_addr;
+                       ri->rp->handler(ri, regs);
+                       __this_cpu_write(current_kprobe, NULL);
+               }
+
+               recycle_rp_inst(ri, &empty_rp);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       kretprobe_hash_unlock(current, &flags);
+
+       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
+               hlist_del(&ri->hlist);
+               kfree(ri);
+       }
+       return (void *)orig_ret_address;
+}
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+                                     struct pt_regs *regs)
+{
+       ri->ret_addr = (kprobe_opcode_t *)regs->regs[30];
+
+       /* replace return addr (x30) with trampoline */
+       regs->regs[30] = (long)&kretprobe_trampoline;
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+       return 0;
+}
+
+int __init arch_init_kprobes(void)
+{
+       return 0;
+}
diff --git a/arch/arm64/kernel/probes/kprobes_trampoline.S b/arch/arm64/kernel/probes/kprobes_trampoline.S
new file mode 100644 (file)
index 0000000..5d6e7f1
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * trampoline entry and return code for kretprobes.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+
+       .text
+
+       .macro  save_all_base_regs
+       stp x0, x1, [sp, #S_X0]
+       stp x2, x3, [sp, #S_X2]
+       stp x4, x5, [sp, #S_X4]
+       stp x6, x7, [sp, #S_X6]
+       stp x8, x9, [sp, #S_X8]
+       stp x10, x11, [sp, #S_X10]
+       stp x12, x13, [sp, #S_X12]
+       stp x14, x15, [sp, #S_X14]
+       stp x16, x17, [sp, #S_X16]
+       stp x18, x19, [sp, #S_X18]
+       stp x20, x21, [sp, #S_X20]
+       stp x22, x23, [sp, #S_X22]
+       stp x24, x25, [sp, #S_X24]
+       stp x26, x27, [sp, #S_X26]
+       stp x28, x29, [sp, #S_X28]
+       add x0, sp, #S_FRAME_SIZE
+       stp lr, x0, [sp, #S_LR]
+       /*
+        * Construct a useful saved PSTATE
+        */
+       mrs x0, nzcv
+       mrs x1, daif
+       orr x0, x0, x1
+       mrs x1, CurrentEL
+       orr x0, x0, x1
+       mrs x1, SPSel
+       orr x0, x0, x1
+       stp xzr, x0, [sp, #S_PC]
+       .endm
+
+       .macro  restore_all_base_regs
+       ldr x0, [sp, #S_PSTATE]
+       and x0, x0, #(PSR_N_BIT | PSR_Z_BIT | PSR_C_BIT | PSR_V_BIT)
+       msr nzcv, x0
+       ldp x0, x1, [sp, #S_X0]
+       ldp x2, x3, [sp, #S_X2]
+       ldp x4, x5, [sp, #S_X4]
+       ldp x6, x7, [sp, #S_X6]
+       ldp x8, x9, [sp, #S_X8]
+       ldp x10, x11, [sp, #S_X10]
+       ldp x12, x13, [sp, #S_X12]
+       ldp x14, x15, [sp, #S_X14]
+       ldp x16, x17, [sp, #S_X16]
+       ldp x18, x19, [sp, #S_X18]
+       ldp x20, x21, [sp, #S_X20]
+       ldp x22, x23, [sp, #S_X22]
+       ldp x24, x25, [sp, #S_X24]
+       ldp x26, x27, [sp, #S_X26]
+       ldp x28, x29, [sp, #S_X28]
+       .endm
+
+ENTRY(kretprobe_trampoline)
+       sub sp, sp, #S_FRAME_SIZE
+
+       save_all_base_regs
+
+       mov x0, sp
+       bl trampoline_probe_handler
+       /*
+        * Replace trampoline address in lr with actual orig_ret_addr return
+        * address.
+        */
+       mov lr, x0
+
+       restore_all_base_regs
+
+       add sp, sp, #S_FRAME_SIZE
+       ret
+
+ENDPROC(kretprobe_trampoline)
diff --git a/arch/arm64/kernel/probes/simulate-insn.c b/arch/arm64/kernel/probes/simulate-insn.c
new file mode 100644 (file)
index 0000000..8977ce9
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * arch/arm64/kernel/probes/simulate-insn.c
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+
+#include "simulate-insn.h"
+
+#define sign_extend(x, signbit)                \
+       ((x) | (0 - ((x) & (1 << (signbit)))))
+
+#define bbl_displacement(insn)         \
+       sign_extend(((insn) & 0x3ffffff) << 2, 27)
+
+#define bcond_displacement(insn)       \
+       sign_extend(((insn >> 5) & 0x7ffff) << 2, 20)
+
+#define cbz_displacement(insn) \
+       sign_extend(((insn >> 5) & 0x7ffff) << 2, 20)
+
+#define tbz_displacement(insn) \
+       sign_extend(((insn >> 5) & 0x3fff) << 2, 15)
+
+#define ldr_displacement(insn) \
+       sign_extend(((insn >> 5) & 0x7ffff) << 2, 20)
+
+static inline void set_x_reg(struct pt_regs *regs, int reg, u64 val)
+{
+       if (reg < 31)
+               regs->regs[reg] = val;
+}
+
+static inline void set_w_reg(struct pt_regs *regs, int reg, u64 val)
+{
+       if (reg < 31)
+               regs->regs[reg] = lower_32_bits(val);
+}
+
+static inline u64 get_x_reg(struct pt_regs *regs, int reg)
+{
+       if (reg < 31)
+               return regs->regs[reg];
+       else
+               return 0;
+}
+
+static inline u32 get_w_reg(struct pt_regs *regs, int reg)
+{
+       if (reg < 31)
+               return lower_32_bits(regs->regs[reg]);
+       else
+               return 0;
+}
+
+static bool __kprobes check_cbz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+
+       return (opcode & (1 << 31)) ?
+           (get_x_reg(regs, xn) == 0) : (get_w_reg(regs, xn) == 0);
+}
+
+static bool __kprobes check_cbnz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+
+       return (opcode & (1 << 31)) ?
+           (get_x_reg(regs, xn) != 0) : (get_w_reg(regs, xn) != 0);
+}
+
+static bool __kprobes check_tbz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+       int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+       return ((get_x_reg(regs, xn) >> bit_pos) & 0x1) == 0;
+}
+
+static bool __kprobes check_tbnz(u32 opcode, struct pt_regs *regs)
+{
+       int xn = opcode & 0x1f;
+       int bit_pos = ((opcode & (1 << 31)) >> 26) | ((opcode >> 19) & 0x1f);
+
+       return ((get_x_reg(regs, xn) >> bit_pos) & 0x1) != 0;
+}
+
+/*
+ * instruction simulation functions
+ */
+void __kprobes
+simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs)
+{
+       long imm, xn, val;
+
+       xn = opcode & 0x1f;
+       imm = ((opcode >> 3) & 0x1ffffc) | ((opcode >> 29) & 0x3);
+       imm = sign_extend(imm, 20);
+       if (opcode & 0x80000000)
+               val = (imm<<12) + (addr & 0xfffffffffffff000);
+       else
+               val = imm + addr;
+
+       set_x_reg(regs, xn, val);
+
+       instruction_pointer_set(regs, instruction_pointer(regs) + 4);
+}
+
+void __kprobes
+simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = bbl_displacement(opcode);
+
+       /* Link register is x30 */
+       if (opcode & (1 << 31))
+               set_x_reg(regs, 30, addr + 4);
+
+       instruction_pointer_set(regs, addr + disp);
+}
+
+void __kprobes
+simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = 4;
+
+       if (aarch32_opcode_cond_checks[opcode & 0xf](regs->pstate & 0xffffffff))
+               disp = bcond_displacement(opcode);
+
+       instruction_pointer_set(regs, addr + disp);
+}
+
+void __kprobes
+simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int xn = (opcode >> 5) & 0x1f;
+
+       /* update pc first in case we're doing a "blr lr" */
+       instruction_pointer_set(regs, get_x_reg(regs, xn));
+
+       /* Link register is x30 */
+       if (((opcode >> 21) & 0x3) == 1)
+               set_x_reg(regs, 30, addr + 4);
+}
+
+void __kprobes
+simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = 4;
+
+       if (opcode & (1 << 24)) {
+               if (check_cbnz(opcode, regs))
+                       disp = cbz_displacement(opcode);
+       } else {
+               if (check_cbz(opcode, regs))
+                       disp = cbz_displacement(opcode);
+       }
+       instruction_pointer_set(regs, addr + disp);
+}
+
+void __kprobes
+simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs)
+{
+       int disp = 4;
+
+       if (opcode & (1 << 24)) {
+               if (check_tbnz(opcode, regs))
+                       disp = tbz_displacement(opcode);
+       } else {
+               if (check_tbz(opcode, regs))
+                       disp = tbz_displacement(opcode);
+       }
+       instruction_pointer_set(regs, addr + disp);
+}
+
+void __kprobes
+simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs)
+{
+       u64 *load_addr;
+       int xn = opcode & 0x1f;
+       int disp;
+
+       disp = ldr_displacement(opcode);
+       load_addr = (u64 *) (addr + disp);
+
+       if (opcode & (1 << 30)) /* x0-x30 */
+               set_x_reg(regs, xn, *load_addr);
+       else                    /* w0-w30 */
+               set_w_reg(regs, xn, *load_addr);
+
+       instruction_pointer_set(regs, instruction_pointer(regs) + 4);
+}
+
+void __kprobes
+simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs)
+{
+       s32 *load_addr;
+       int xn = opcode & 0x1f;
+       int disp;
+
+       disp = ldr_displacement(opcode);
+       load_addr = (s32 *) (addr + disp);
+
+       set_x_reg(regs, xn, *load_addr);
+
+       instruction_pointer_set(regs, instruction_pointer(regs) + 4);
+}
diff --git a/arch/arm64/kernel/probes/simulate-insn.h b/arch/arm64/kernel/probes/simulate-insn.h
new file mode 100644 (file)
index 0000000..050bde6
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/arm64/kernel/probes/simulate-insn.h
+ *
+ * Copyright (C) 2013 Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _ARM_KERNEL_KPROBES_SIMULATE_INSN_H
+#define _ARM_KERNEL_KPROBES_SIMULATE_INSN_H
+
+void simulate_adr_adrp(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_b_bl(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_b_cond(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_br_blr_ret(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs);
+void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs);
+
+#endif /* _ARM_KERNEL_KPROBES_SIMULATE_INSN_H */
index fc779ec6f051fcacf52c793f37961a75db832fab..df4707380e6656722ccd2901413d387bc79cf965 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <trace/events/syscalls.h>
 
+struct pt_regs_offset {
+       const char *name;
+       int offset;
+};
+
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+#define GPR_OFFSET_NAME(r) \
+       {.name = "x" #r, .offset = offsetof(struct pt_regs, regs[r])}
+
+static const struct pt_regs_offset regoffset_table[] = {
+       GPR_OFFSET_NAME(0),
+       GPR_OFFSET_NAME(1),
+       GPR_OFFSET_NAME(2),
+       GPR_OFFSET_NAME(3),
+       GPR_OFFSET_NAME(4),
+       GPR_OFFSET_NAME(5),
+       GPR_OFFSET_NAME(6),
+       GPR_OFFSET_NAME(7),
+       GPR_OFFSET_NAME(8),
+       GPR_OFFSET_NAME(9),
+       GPR_OFFSET_NAME(10),
+       GPR_OFFSET_NAME(11),
+       GPR_OFFSET_NAME(12),
+       GPR_OFFSET_NAME(13),
+       GPR_OFFSET_NAME(14),
+       GPR_OFFSET_NAME(15),
+       GPR_OFFSET_NAME(16),
+       GPR_OFFSET_NAME(17),
+       GPR_OFFSET_NAME(18),
+       GPR_OFFSET_NAME(19),
+       GPR_OFFSET_NAME(20),
+       GPR_OFFSET_NAME(21),
+       GPR_OFFSET_NAME(22),
+       GPR_OFFSET_NAME(23),
+       GPR_OFFSET_NAME(24),
+       GPR_OFFSET_NAME(25),
+       GPR_OFFSET_NAME(26),
+       GPR_OFFSET_NAME(27),
+       GPR_OFFSET_NAME(28),
+       GPR_OFFSET_NAME(29),
+       GPR_OFFSET_NAME(30),
+       {.name = "lr", .offset = offsetof(struct pt_regs, regs[30])},
+       REG_OFFSET_NAME(sp),
+       REG_OFFSET_NAME(pc),
+       REG_OFFSET_NAME(pstate),
+       REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:      the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+       const struct pt_regs_offset *roff;
+
+       for (roff = regoffset_table; roff->name != NULL; roff++)
+               if (!strcmp(roff->name, name))
+                       return roff->offset;
+       return -EINVAL;
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @addr:      address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
+{
+       return ((addr & ~(THREAD_SIZE - 1))  ==
+               (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:      pt_regs which contains kernel stack pointer.
+ * @n:         stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
+{
+       unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+
+       addr += n;
+       if (regs_within_kernel_stack(regs, (unsigned long)addr))
+               return *addr;
+       else
+               return 0;
+}
+
 /*
  * TODO: does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
index 42371f69def3a3afc68a7f1a28d0e819e83c7837..6591bf23422b3471fa8fb83d04445aac33dd808d 100644 (file)
@@ -202,7 +202,7 @@ static void __init request_standard_resources(void)
        struct resource *res;
 
        kernel_code.start   = virt_to_phys(_text);
-       kernel_code.end     = virt_to_phys(_etext - 1);
+       kernel_code.end     = virt_to_phys(__init_begin - 1);
        kernel_data.start   = virt_to_phys(_sdata);
        kernel_data.end     = virt_to_phys(_end - 1);
 
@@ -347,6 +347,15 @@ void __init setup_arch(char **cmdline_p)
        smp_init_cpus();
        smp_build_mpidr_hash();
 
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       /*
+        * Make sure init_thread_info.ttbr0 always generates translation
+        * faults in case uaccess_enable() is inadvertently called by the init
+        * thread.
+        */
+       init_thread_info.ttbr0 = virt_to_phys(empty_zero_page);
+#endif
+
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
        conswitchp = &vga_con;
index 24cb4f800033bc2b9d5ad49144f915ca4506e6dc..a84623d91410d17daf444995c6c8ec1baceae939 100644 (file)
@@ -187,7 +187,6 @@ asmlinkage void secondary_start_kernel(void)
        set_cpu_online(cpu, true);
        complete(&cpu_running);
 
-       local_dbg_enable();
        local_irq_enable();
        local_async_enable();
 
@@ -333,8 +332,8 @@ void __init smp_cpus_done(unsigned int max_cpus)
 
 void __init smp_prepare_boot_cpu(void)
 {
-       cpuinfo_store_boot_cpu();
        set_my_cpu_offset(per_cpu_offset(smp_processor_id()));
+       cpuinfo_store_boot_cpu();
 }
 
 static u64 __init of_get_cpu_mpidr(struct device_node *dn)
index c5392081b49ba4ac4f48d9a0782442ac888ed222..29d7b68f63f091a0d4266ed64501ab35a41b2d5c 100644 (file)
@@ -64,8 +64,7 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
 
        /*
         * We need to switch to kernel mode so that we can use __get_user
-        * to safely read from kernel space.  Note that we now dump the
-        * code first, just in case the backtrace kills us.
+        * to safely read from kernel space.
         */
        fs = get_fs();
        set_fs(KERNEL_DS);
@@ -111,21 +110,12 @@ static void dump_backtrace_entry(unsigned long where)
        print_ip_sym(where);
 }
 
-static void dump_instr(const char *lvl, struct pt_regs *regs)
+static void __dump_instr(const char *lvl, struct pt_regs *regs)
 {
        unsigned long addr = instruction_pointer(regs);
-       mm_segment_t fs;
        char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
        int i;
 
-       /*
-        * We need to switch to kernel mode so that we can use __get_user
-        * to safely read from kernel space.  Note that we now dump the
-        * code first, just in case the backtrace kills us.
-        */
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-
        for (i = -4; i < 1; i++) {
                unsigned int val, bad;
 
@@ -139,8 +129,18 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
                }
        }
        printk("%sCode: %s\n", lvl, str);
+}
 
-       set_fs(fs);
+static void dump_instr(const char *lvl, struct pt_regs *regs)
+{
+       if (!user_mode(regs)) {
+               mm_segment_t fs = get_fs();
+               set_fs(KERNEL_DS);
+               __dump_instr(lvl, regs);
+               set_fs(fs);
+       } else {
+               __dump_instr(lvl, regs);
+       }
 }
 
 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
@@ -465,7 +465,7 @@ static const char *esr_class_str[] = {
 
 const char *esr_get_class_string(u32 esr)
 {
-       return esr_class_str[esr >> ESR_ELx_EC_SHIFT];
+       return esr_class_str[ESR_ELx_EC(esr)];
 }
 
 /*
index ab2c6df55a0af689d4b848ecf19f4be97d839919..9d25a1058c65d7b22b9ccadf0c2fec1989580beb 100644 (file)
@@ -93,6 +93,7 @@ SECTIONS
                *(.discard)
                *(.discard.*)
                *(.interp .dynamic)
+               *(.dynsym .dynstr .hash)
        }
 
        . = KIMAGE_VADDR + TEXT_OFFSET;
@@ -107,9 +108,11 @@ SECTIONS
                        *(.exception.text)
                        __exception_text_end = .;
                        IRQENTRY_TEXT
+                       ENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
                        LOCK_TEXT
+                       KPROBES_TEXT
                        HYPERVISOR_TEXT
                        IDMAP_TEXT
                        *(.fixup)
@@ -119,12 +122,13 @@ SECTIONS
        }
 
        . = ALIGN(SEGMENT_ALIGN);
-       RO_DATA(PAGE_SIZE)              /* everything from this point to */
-       EXCEPTION_TABLE(8)              /* _etext will be marked RO NX   */
+       _etext = .;                     /* End of text section */
+
+       RO_DATA(PAGE_SIZE)              /* everything from this point to     */
+       EXCEPTION_TABLE(8)              /* __init_begin will be marked RO NX */
        NOTES
 
        . = ALIGN(SEGMENT_ALIGN);
-       _etext = .;                     /* End of text and rodata section */
        __init_begin = .;
 
        INIT_TEXT_SECTION(8)
@@ -158,19 +162,9 @@ SECTIONS
        .rela : ALIGN(8) {
                *(.rela .rela*)
        }
-       .dynsym : ALIGN(8) {
-               *(.dynsym)
-       }
-       .dynstr : {
-               *(.dynstr)
-       }
-       .hash : {
-               *(.hash)
-       }
 
-       __rela_offset   = ADDR(.rela) - KIMAGE_VADDR;
+       __rela_offset   = ABSOLUTE(ADDR(.rela) - KIMAGE_VADDR);
        __rela_size     = SIZEOF(.rela);
-       __dynsym_offset = ADDR(.dynsym) - KIMAGE_VADDR;
 
        . = ALIGN(SEGMENT_ALIGN);
        __init_end = .;
@@ -189,6 +183,11 @@ SECTIONS
        swapper_pg_dir = .;
        . += SWAPPER_DIR_SIZE;
 
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       reserved_ttbr0 = .;
+       . += RESERVED_TTBR0_SIZE;
+#endif
+
        _end = .;
 
        STABS_DEBUG
index 178ba2248a9804b82157f392e16026b010cb76b6..84c338f017b2121b0000484bbca981cbabc49abb 100644 (file)
@@ -64,7 +64,7 @@ __do_hyp_init:
        mrs     x4, tcr_el1
        ldr     x5, =TCR_EL2_MASK
        and     x4, x4, x5
-       ldr     x5, =TCR_EL2_FLAGS
+       mov     x5, #TCR_EL2_RES1
        orr     x4, x4, x5
 
 #ifndef CONFIG_ARM64_VA_BITS_48
@@ -85,15 +85,18 @@ __do_hyp_init:
        ldr_l   x5, idmap_t0sz
        bfi     x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
 #endif
-       msr     tcr_el2, x4
-
-       ldr     x4, =VTCR_EL2_FLAGS
        /*
         * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
-        * VTCR_EL2.
+        * TCR_EL2 and VTCR_EL2.
         */
        mrs     x5, ID_AA64MMFR0_EL1
        bfi     x4, x5, #16, #3
+
+       msr     tcr_el2, x4
+
+       ldr     x4, =VTCR_EL2_FLAGS
+       bfi     x4, x5, #16, #3
+
        msr     vtcr_el2, x4
 
        mrs     x4, mair_el1
index 5d1cad3ce6d601aa474ae9c9b8ef4c76a785912e..08b5f18ba604f99461f1c879bbecef8cdb1f53c5 100644 (file)
  */
 #include <linux/linkage.h>
 
-#include <asm/alternative.h>
 #include <asm/assembler.h>
 #include <asm/cpufeature.h>
 #include <asm/sysreg.h>
+#include <asm/uaccess.h>
 
        .text
 
@@ -33,8 +33,7 @@
  * Alignment fixed up by hardware.
  */
 ENTRY(__clear_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+       uaccess_enable_not_uao x2, x3
        mov     x2, x1                  // save the size for fixup return
        subs    x1, x1, #8
        b.mi    2f
@@ -54,8 +53,7 @@ uao_user_alternative 9f, strh, sttrh, wzr, x0, 2
        b.mi    5f
 uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
 5:     mov     x0, #0
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+       uaccess_disable_not_uao x2
        ret
 ENDPROC(__clear_user)
 
index 17e8306dca294ecf37fc27355956eb6bcfc5d92e..6505ec81f1da18ac52427db04821259135c7fbd2 100644 (file)
 
 #include <linux/linkage.h>
 
-#include <asm/alternative.h>
 #include <asm/assembler.h>
 #include <asm/cache.h>
 #include <asm/cpufeature.h>
 #include <asm/sysreg.h>
+#include <asm/uaccess.h>
 
 /*
  * Copy from user space to a kernel buffer (alignment handled by the hardware)
        .endm
 
 end    .req    x5
-ENTRY(__copy_from_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+ENTRY(__arch_copy_from_user)
+       uaccess_enable_not_uao x3, x4
        add     end, x0, x2
 #include "copy_template.S"
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+       uaccess_disable_not_uao x3
        mov     x0, #0                          // Nothing to copy
        ret
-ENDPROC(__copy_from_user)
+ENDPROC(__arch_copy_from_user)
 
        .section .fixup,"ax"
        .align  2
index f7292dd08c840f27d39874fe7cc08aa89bdfb66d..9b04ff3ab6101d29ef8b6be48453260f9d3ffced 100644 (file)
 
 #include <linux/linkage.h>
 
-#include <asm/alternative.h>
 #include <asm/assembler.h>
 #include <asm/cache.h>
 #include <asm/cpufeature.h>
 #include <asm/sysreg.h>
+#include <asm/uaccess.h>
 
 /*
  * Copy from user space to user space (alignment handled by the hardware)
 
 end    .req    x5
 ENTRY(__copy_in_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+       uaccess_enable_not_uao x3, x4
        add     end, x0, x2
 #include "copy_template.S"
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+       uaccess_disable_not_uao x3
        mov     x0, #0
        ret
 ENDPROC(__copy_in_user)
index 21faae60f9887ecbbfccb7ba1fb918839d47a291..8077e4f34d56b7f5b2b9a1ed9c5b53f23f573547 100644 (file)
 
 #include <linux/linkage.h>
 
-#include <asm/alternative.h>
 #include <asm/assembler.h>
 #include <asm/cache.h>
 #include <asm/cpufeature.h>
 #include <asm/sysreg.h>
+#include <asm/uaccess.h>
 
 /*
  * Copy to user space from a kernel buffer (alignment handled by the hardware)
        .endm
 
 end    .req    x5
-ENTRY(__copy_to_user)
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+ENTRY(__arch_copy_to_user)
+       uaccess_enable_not_uao x3, x4
        add     end, x0, x2
 #include "copy_template.S"
-ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \
-           CONFIG_ARM64_PAN)
+       uaccess_disable_not_uao x3
        mov     x0, #0
        ret
-ENDPROC(__copy_to_user)
+ENDPROC(__arch_copy_to_user)
 
        .section .fixup,"ax"
        .align  2
index 6df07069a0253013e254dbb1206debaa939a3526..07d7352d7c3896cb70d1640bb3215d09b3dc1ad6 100644 (file)
@@ -24,8 +24,6 @@
 #include <asm/cpufeature.h>
 #include <asm/alternative.h>
 
-#include "proc-macros.S"
-
 /*
  *     flush_icache_range(start,end)
  *
@@ -54,7 +52,7 @@ ENTRY(__flush_cache_user_range)
        sub     x3, x2, #1
        bic     x4, x0, x3
 1:
-USER(9f, dc    cvau, x4        )               // clean D line to PoU
+user_alt 9f, "dc cvau, x4",  "dc civac, x4",  ARM64_WORKAROUND_CLEAN_CACHE
        add     x4, x4, x2
        cmp     x4, x1
        b.lo    1b
index 7275628ba59f663489f6f9403d46ca8a5050c6f7..25128089c386b72298d913105f67c9ddd3da3892 100644 (file)
@@ -182,7 +182,12 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
        raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
 
 switch_mm_fastpath:
-       cpu_switch_mm(mm->pgd, mm);
+       /*
+        * Defer TTBR0_EL1 setting for user threads to uaccess_enable() when
+        * emulating PAN.
+        */
+       if (!system_uses_ttbr0_pan())
+               cpu_switch_mm(mm->pgd, mm);
 }
 
 static int asids_init(void)
index edc3e20f7ba9371be929052730b02eb2aa4a07c6..7e4423d22d2823e68a4f12f85fc12b297ae2f867 100644 (file)
 
 static const char *fault_name(unsigned int esr);
 
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+{
+       int ret = 0;
+
+       /* kprobe_running() needs smp_processor_id() */
+       if (!user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, esr))
+                       ret = 1;
+               preempt_enable();
+       }
+
+       return ret;
+}
+#else
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
+{
+       return 0;
+}
+#endif
+
 /*
  * Dump out the page tables associated with 'addr' in mm 'mm'.
  */
@@ -131,6 +153,11 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
 }
 #endif
 
+static bool is_el1_instruction_abort(unsigned int esr)
+{
+       return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_CUR;
+}
+
 /*
  * The kernel tried to access some page that wasn't present.
  */
@@ -139,8 +166,9 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
 {
        /*
         * Are we prepared to handle this kernel fault?
+        * We are almost certainly not prepared to handle instruction faults.
         */
-       if (fixup_exception(regs))
+       if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
                return;
 
        /*
@@ -202,8 +230,6 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
 #define VM_FAULT_BADMAP                0x010000
 #define VM_FAULT_BADACCESS     0x020000
 
-#define ESR_LNX_EXEC           (1 << 24)
-
 static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
                           unsigned int mm_flags, unsigned long vm_flags,
                           struct task_struct *tsk)
@@ -242,12 +268,24 @@ out:
        return fault;
 }
 
-static inline int permission_fault(unsigned int esr)
+static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs)
 {
-       unsigned int ec       = (esr & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT;
+       unsigned int ec       = ESR_ELx_EC(esr);
        unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
 
-       return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM);
+       if (ec != ESR_ELx_EC_DABT_CUR && ec != ESR_ELx_EC_IABT_CUR)
+               return false;
+
+       if (system_uses_ttbr0_pan())
+               return fsc_type == ESR_ELx_FSC_FAULT &&
+                       (regs->pstate & PSR_PAN_BIT);
+       else
+               return fsc_type == ESR_ELx_FSC_PERM;
+}
+
+static bool is_el0_instruction_abort(unsigned int esr)
+{
+       return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW;
 }
 
 static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
@@ -259,6 +297,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
        unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
+       if (notify_page_fault(regs, esr))
+               return 0;
+
        tsk = current;
        mm  = tsk->mm;
 
@@ -276,17 +317,20 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        if (user_mode(regs))
                mm_flags |= FAULT_FLAG_USER;
 
-       if (esr & ESR_LNX_EXEC) {
+       if (is_el0_instruction_abort(esr)) {
                vm_flags = VM_EXEC;
        } else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) {
                vm_flags = VM_WRITE;
                mm_flags |= FAULT_FLAG_WRITE;
        }
 
-       if (permission_fault(esr) && (addr < USER_DS)) {
+       if (addr < USER_DS && is_permission_fault(esr, regs)) {
                if (get_fs() == KERNEL_DS)
                        die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
 
+               if (is_el1_instruction_abort(esr))
+                       die("Attempting to execute userspace memory", regs, esr);
+
                if (!search_exception_tables(regs->pc))
                        die("Accessing user space memory outside uaccess.h routines", regs, esr);
        }
@@ -438,7 +482,7 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
        return 1;
 }
 
-static struct fault_info {
+static const struct fault_info {
        int     (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs);
        int     sig;
        int     code;
@@ -464,10 +508,10 @@ static struct fault_info {
        { do_bad,               SIGBUS,  0,             "unknown 17"                    },
        { do_bad,               SIGBUS,  0,             "unknown 18"                    },
        { do_bad,               SIGBUS,  0,             "unknown 19"                    },
-       { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
-       { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
-       { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
-       { do_bad,               SIGBUS,  0,             "synchronous abort (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous external abort (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous external abort (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous external abort (translation table walk)" },
+       { do_bad,               SIGBUS,  0,             "synchronous external abort (translation table walk)" },
        { do_bad,               SIGBUS,  0,             "synchronous parity error"      },
        { do_bad,               SIGBUS,  0,             "unknown 25"                    },
        { do_bad,               SIGBUS,  0,             "unknown 26"                    },
@@ -613,6 +657,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
 
        return 0;
 }
+NOKPROBE_SYMBOL(do_debug_exception);
 
 #ifdef CONFIG_ARM64_PAN
 void cpu_enable_pan(void *__unused)
index f001d40eaaa730ad2112089dabcbc8f5091937e2..6788780779963d078c3ec611b1f870d500b1737f 100644 (file)
@@ -131,7 +131,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
 int pfn_valid(unsigned long pfn)
 {
-       return (pfn & PFN_MASK) == pfn && memblock_is_memory(pfn << PAGE_SHIFT);
+       return (pfn & PFN_MASK) == pfn && memblock_is_map_memory(pfn << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(pfn_valid);
 #endif
@@ -192,8 +192,12 @@ void __init arm64_memblock_init(void)
         */
        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);
+       if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) {
+               /* ensure that memstart_addr remains sufficiently aligned */
+               memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size,
+                                        ARM64_MEMSTART_ALIGN);
+               memblock_remove(0, memstart_addr);
+       }
 
        /*
         * Apply the memory limit if it was set. Since the kernel may be loaded
@@ -387,8 +391,8 @@ void __init mem_init(void)
                  MLM(MODULES_VADDR, MODULES_END),
                  MLG(VMALLOC_START, VMALLOC_END),
                  MLK_ROUNDUP(__init_begin, __init_end),
-                 MLK_ROUNDUP(_text, __start_rodata),
-                 MLK_ROUNDUP(__start_rodata, _etext),
+                 MLK_ROUNDUP(_text, _etext),
+                 MLK_ROUNDUP(__start_rodata, __init_begin),
                  MLK_ROUNDUP(_sdata, _edata),
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
                  MLG(VMEMMAP_START,
index cd4177a1781d8e86c99269091995a7f3090f37bc..1cab2703f5a87e7074dbdbe8c932ff2317cf4bfe 100644 (file)
@@ -386,14 +386,14 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
 static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
 {
        unsigned long kernel_start = __pa(_text);
-       unsigned long kernel_end = __pa(_etext);
+       unsigned long kernel_end = __pa(__init_begin);
 
        /*
         * Take care not to create a writable alias for the
         * read-only text and rodata sections of the kernel image.
         */
 
-       /* No overlap with the kernel text */
+       /* No overlap with the kernel text/rodata */
        if (end < kernel_start || start >= kernel_end) {
                __create_pgd_mapping(pgd, start, __phys_to_virt(start),
                                     end - start, PAGE_KERNEL,
@@ -402,7 +402,7 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
        }
 
        /*
-        * This block overlaps the kernel text mapping.
+        * This block overlaps the kernel text/rodata mappings.
         * Map the portion(s) which don't overlap.
         */
        if (start < kernel_start)
@@ -417,7 +417,7 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
                                     early_pgtable_alloc);
 
        /*
-        * Map the linear alias of the [_text, _etext) interval as
+        * Map the linear alias of the [_text, __init_begin) 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.
@@ -438,6 +438,8 @@ static void __init map_mem(pgd_t *pgd)
 
                if (start >= end)
                        break;
+               if (memblock_is_nomap(reg))
+                       continue;
 
                __map_memblock(pgd, start, end);
        }
@@ -447,14 +449,14 @@ void mark_rodata_ro(void)
 {
        unsigned long section_size;
 
-       section_size = (unsigned long)__start_rodata - (unsigned long)_text;
+       section_size = (unsigned long)_etext - (unsigned long)_text;
        create_mapping_late(__pa(_text), (unsigned long)_text,
                            section_size, PAGE_KERNEL_ROX);
        /*
-        * mark .rodata as read only. Use _etext rather than __end_rodata to
-        * cover NOTES and EXCEPTION_TABLE.
+        * mark .rodata as read only. Use __init_begin rather than __end_rodata
+        * to cover NOTES and EXCEPTION_TABLE.
         */
-       section_size = (unsigned long)_etext - (unsigned long)__start_rodata;
+       section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
        create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata,
                            section_size, PAGE_KERNEL_RO);
 }
@@ -497,8 +499,8 @@ static void __init map_kernel(pgd_t *pgd)
 {
        static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_init, vmlinux_data;
 
-       map_kernel_segment(pgd, _text, __start_rodata, PAGE_KERNEL_EXEC, &vmlinux_text);
-       map_kernel_segment(pgd, __start_rodata, _etext, PAGE_KERNEL, &vmlinux_rodata);
+       map_kernel_segment(pgd, _text, _etext, PAGE_KERNEL_EXEC, &vmlinux_text);
+       map_kernel_segment(pgd, __start_rodata, __init_begin, PAGE_KERNEL, &vmlinux_rodata);
        map_kernel_segment(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC,
                           &vmlinux_init);
        map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data);
@@ -748,9 +750,9 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
        /*
         * Check whether the physical FDT address is set and meets the minimum
         * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
-        * at least 8 bytes so that we can always access the size field of the
-        * FDT header after mapping the first chunk, double check here if that
-        * is indeed the case.
+        * at least 8 bytes so that we can always access the magic and size
+        * fields of the FDT header after mapping the first chunk, double check
+        * here if that is indeed the case.
         */
        BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
        if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
@@ -778,7 +780,7 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t 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)
+       if (fdt_magic(dt_virt) != FDT_MAGIC)
                return NULL;
 
        *size = fdt_totalsize(dt_virt);
diff --git a/arch/arm64/mm/proc-macros.S b/arch/arm64/mm/proc-macros.S
deleted file mode 100644 (file)
index 984edcd..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Based on arch/arm/mm/proc-macros.S
- *
- * 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.
- *
- * 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 <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-
-/*
- * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
- */
-       .macro  vma_vm_mm, rd, rn
-       ldr     \rd, [\rn, #VMA_VM_MM]
-       .endm
-
-/*
- * mmid - get context id from mm pointer (mm->context.id)
- */
-       .macro  mmid, rd, rn
-       ldr     \rd, [\rn, #MM_CONTEXT_ID]
-       .endm
-
-/*
- * dcache_line_size - get the minimum D-cache line size from the CTR register.
- */
-       .macro  dcache_line_size, reg, tmp
-       mrs     \tmp, ctr_el0                   // read CTR
-       ubfm    \tmp, \tmp, #16, #19            // cache line size encoding
-       mov     \reg, #4                        // bytes per word
-       lsl     \reg, \reg, \tmp                // actual cache line size
-       .endm
-
-/*
- * icache_line_size - get the minimum I-cache line size from the CTR register.
- */
-       .macro  icache_line_size, reg, tmp
-       mrs     \tmp, ctr_el0                   // read CTR
-       and     \tmp, \tmp, #0xf                // cache line size encoding
-       mov     \reg, #4                        // bytes per word
-       lsl     \reg, \reg, \tmp                // actual cache line size
-       .endm
-
-/*
- * tcr_set_idmap_t0sz - update TCR.T0SZ so that we can load the ID map
- */
-       .macro  tcr_set_idmap_t0sz, valreg, tmpreg
-#ifndef CONFIG_ARM64_VA_BITS_48
-       ldr_l   \tmpreg, idmap_t0sz
-       bfi     \valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
-#endif
-       .endm
-
-/*
- * reset_pmuserenr_el0 - reset PMUSERENR_EL0 if PMUv3 present
- */
-       .macro  reset_pmuserenr_el0, tmpreg
-       mrs     \tmpreg, id_aa64dfr0_el1        // Check ID_AA64DFR0_EL1 PMUVer
-       sbfx    \tmpreg, \tmpreg, #8, #4
-       cmp     \tmpreg, #1                     // Skip if no PMU present
-       b.lt    9000f
-       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 0c19534a901e616ecc5fe508ce205dc0de8fe0f4..85a542b2157521da47b39e2b2bff0180cf5b665a 100644 (file)
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
 #include <asm/hwcap.h>
-#include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
-
-#include "proc-macros.S"
+#include <asm/cpufeature.h>
+#include <asm/alternative.h>
 
 #ifdef CONFIG_ARM64_64K_PAGES
 #define TCR_TG_FLAGS   TCR_TG0_64K | TCR_TG1_64K
@@ -137,6 +136,7 @@ ENTRY(cpu_do_switch_mm)
        bfi     x0, x1, #48, #16                // set the ASID
        msr     ttbr0_el1, x0                   // set TTBR0
        isb
+       post_ttbr0_update_workaround
        ret
 ENDPROC(cpu_do_switch_mm)
 
@@ -182,6 +182,8 @@ ENTRY(__cpu_setup)
        msr     cpacr_el1, x0                   // Enable FP/ASIMD
        mov     x0, #1 << 12                    // Reset mdscr_el1 and disable
        msr     mdscr_el1, x0                   // access to the DCC from EL0
+       isb                                     // Unmask debug exceptions now,
+       enable_dbg                              // since this is per-cpu
        reset_pmuserenr_el0 x0                  // Disable PMU access from EL0
        /*
         * Memory region attributes for LPAE:
index 8bbe9401f4f011d3239adcd2d6f5251d5fe37ff0..6d6e4af1a4bfb2e6354a242c0638a813d3f173d0 100644 (file)
@@ -49,6 +49,7 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/uaccess.h>
 #include <xen/interface/xen.h>
 
 
@@ -89,6 +90,24 @@ ENTRY(privcmd_call)
        mov x2, x3
        mov x3, x4
        mov x4, x5
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       /*
+        * Privcmd calls are issued by the userspace. The kernel needs to
+        * enable access to TTBR0_EL1 as the hypervisor would issue stage 1
+        * translations to user memory via AT instructions. Since AT
+        * instructions are not affected by the PAN bit (ARMv8.1), we only
+        * need the explicit uaccess_enable/disable if the TTBR0 PAN emulation
+        * is enabled (it implies that hardware UAO and PAN disabled).
+        */
+       uaccess_enable_not_uao x6, x7
+#endif
        hvc XEN_IMM
+
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+       /*
+        * Disable userspace access from kernel once the hyp call completed.
+        */
+       uaccess_disable_not_uao x6
+#endif
        ret
 ENDPROC(privcmd_call);
index 68cf638faf4867aef2d92b91f9ab48770100f132..b1ec1fa064632258ac1a4bb50b3b22416bd43c0f 100644 (file)
@@ -74,7 +74,7 @@ extern __kernel_size_t __copy_user(void *to, const void *from,
 
 extern __kernel_size_t copy_to_user(void __user *to, const void *from,
                                    __kernel_size_t n);
-extern __kernel_size_t copy_from_user(void *to, const void __user *from,
+extern __kernel_size_t ___copy_from_user(void *to, const void __user *from,
                                      __kernel_size_t n);
 
 static inline __kernel_size_t __copy_to_user(void __user *to, const void *from,
@@ -88,6 +88,15 @@ static inline __kernel_size_t __copy_from_user(void *to,
 {
        return __copy_user(to, (const void __force *)from, n);
 }
+static inline __kernel_size_t copy_from_user(void *to,
+                                              const void __user *from,
+                                              __kernel_size_t n)
+{
+       size_t res = ___copy_from_user(to, from, n);
+       if (unlikely(res))
+               memset(to + (n - res), 0, res);
+       return res;
+}
 
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
index d93ead02daeda4635e772268b328dc652f1d86df..7c6cf14f09854aacd6f31cafedc39a88d451d18a 100644 (file)
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(copy_page);
 /*
  * Userspace access stuff.
  */
-EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(___copy_from_user);
 EXPORT_SYMBOL(copy_to_user);
 EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(strncpy_from_user);
index ea59c04b07de8e3a09ed486b8c48a9ffe25ad5c1..075373471da11d011871ab4681e7ded58732ddfb 100644 (file)
         */
        .text
        .align  1
-       .global copy_from_user
-       .type   copy_from_user, @function
-copy_from_user:
+       .global ___copy_from_user
+       .type   ___copy_from_user, @function
+___copy_from_user:
        branch_if_kernel r8, __copy_user
        ret_if_privileged r8, r11, r10, r10
        rjmp    __copy_user
-       .size   copy_from_user, . - copy_from_user
+       .size   ___copy_from_user, . - ___copy_from_user
 
        .global copy_to_user
        .type   copy_to_user, @function
index 4f61378c3453792af416dae65ffa1e9a8c70f4ff..456128174b1794e7b2806d4f7ed135a481f9b8ac 100644 (file)
@@ -435,7 +435,7 @@ void __init at32_init_pio(struct platform_device *pdev)
        struct resource *regs;
        struct pio_device *pio;
 
-       if (pdev->id > MAX_NR_PIO_DEVICES) {
+       if (pdev->id >= MAX_NR_PIO_DEVICES) {
                dev_err(&pdev->dev, "only %d PIO devices supported\n",
                        MAX_NR_PIO_DEVICES);
                return;
index 90612a7f2cf32f0872af2651b608cd56eb0fff26..8cd0184ea9efbd517f97d8b0fcd90659ee66c0fe 100644 (file)
@@ -177,11 +177,12 @@ static inline int bad_user_access_length(void)
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       if (access_ok(VERIFY_READ, from, n))
+       if (likely(access_ok(VERIFY_READ, from, n))) {
                memcpy(to, (const void __force *)from, n);
-       else
-               return n;
-       return 0;
+               return 0;
+       }
+       memset(to, 0, n);
+       return n;
 }
 
 static inline unsigned long __must_check
index c6db52ba3a06653e8b6a22a277c607d82c69de46..10c57771822d5d8f25eed0ccc64ceacfb2dca5ca 100644 (file)
@@ -146,7 +146,8 @@ static struct platform_device hitachi_fb_device = {
 #include <linux/smc91x.h>
 
 static struct smc91x_platdata smc91x_info = {
-       .flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+       .flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+                SMC91X_NOWAIT,
        .leda = RPC_LED_100_10,
        .ledb = RPC_LED_TX_RX,
 };
index 2de71e8c104b1e2233c7eba47c42ad28d2ab60c9..93c22468cc141a6ab302b1c9f7c54a51704c422b 100644 (file)
@@ -134,7 +134,8 @@ static struct platform_device net2272_bfin_device = {
 #include <linux/smc91x.h>
 
 static struct smc91x_platdata smc91x_info = {
-       .flags = SMC91X_USE_32BIT | SMC91X_NOWAIT,
+       .flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
+                SMC91X_NOWAIT,
        .leda = RPC_LED_100_10,
        .ledb = RPC_LED_TX_RX,
 };
index e3530d0f13ee74e9c4b2bdfbaf10e226499af2e9..56c7d5750abd66c0b75e7af2d6f0738a18236b6e 100644 (file)
@@ -194,30 +194,6 @@ extern unsigned long __copy_user(void __user *to, const void *from, unsigned lon
 extern unsigned long __copy_user_zeroing(void *to, const void __user *from, unsigned long n);
 extern unsigned long __do_clear_user(void __user *to, unsigned long n);
 
-static inline unsigned long
-__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       if (access_ok(VERIFY_WRITE, to, n))
-               return __copy_user(to, from, n);
-       return n;
-}
-
-static inline unsigned long
-__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       if (access_ok(VERIFY_READ, from, n))
-               return __copy_user_zeroing(to, from, n);
-       return n;
-}
-
-static inline unsigned long
-__generic_clear_user(void __user *to, unsigned long n)
-{
-       if (access_ok(VERIFY_WRITE, to, n))
-               return __do_clear_user(to, n);
-       return n;
-}
-
 static inline long
 __strncpy_from_user(char *dst, const char __user *src, long count)
 {
@@ -282,7 +258,7 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
        else if (n == 24)
                __asm_copy_from_user_24(to, from, ret);
        else
-               ret = __generic_copy_from_user(to, from, n);
+               ret = __copy_user_zeroing(to, from, n);
 
        return ret;
 }
@@ -333,7 +309,7 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
        else if (n == 24)
                __asm_copy_to_user_24(to, from, ret);
        else
-               ret = __generic_copy_to_user(to, from, n);
+               ret = __copy_user(to, from, n);
 
        return ret;
 }
@@ -366,26 +342,43 @@ __constant_clear_user(void __user *to, unsigned long n)
        else if (n == 24)
                __asm_clear_24(to, ret);
        else
-               ret = __generic_clear_user(to, n);
+               ret = __do_clear_user(to, n);
 
        return ret;
 }
 
 
-#define clear_user(to, n)                              \
-       (__builtin_constant_p(n) ?                      \
-        __constant_clear_user(to, n) :                 \
-        __generic_clear_user(to, n))
+static inline size_t clear_user(void __user *to, size_t n)
+{
+       if (unlikely(!access_ok(VERIFY_WRITE, to, n)))
+               return n;
+       if (__builtin_constant_p(n))
+               return __constant_clear_user(to, n);
+       else
+               return __do_clear_user(to, n);
+}
 
-#define copy_from_user(to, from, n)                    \
-       (__builtin_constant_p(n) ?                      \
-        __constant_copy_from_user(to, from, n) :       \
-        __generic_copy_from_user(to, from, n))
+static inline size_t copy_from_user(void *to, const void __user *from, size_t n)
+{
+       if (unlikely(!access_ok(VERIFY_READ, from, n))) {
+               memset(to, 0, n);
+               return n;
+       }
+       if (__builtin_constant_p(n))
+               return __constant_copy_from_user(to, from, n);
+       else
+               return __copy_user_zeroing(to, from, n);
+}
 
-#define copy_to_user(to, from, n)                      \
-       (__builtin_constant_p(n) ?                      \
-        __constant_copy_to_user(to, from, n) :         \
-        __generic_copy_to_user(to, from, n))
+static inline size_t copy_to_user(void __user *to, const void *from, size_t n)
+{
+       if (unlikely(!access_ok(VERIFY_WRITE, to, n)))
+               return n;
+       if (__builtin_constant_p(n))
+               return __constant_copy_to_user(to, from, n);
+       else
+               return __copy_user(to, from, n);
+}
 
 /* We let the __ versions of copy_from/to_user inline, because they're often
  * used in fast paths and have only a small space overhead.
index 3ac9a59d65d4129142d06ba9516455e0c5dc96db..87d9e34c5df866072ced6de336ea07e3755853eb 100644 (file)
@@ -263,19 +263,25 @@ do {                                                      \
 extern long __memset_user(void *dst, unsigned long count);
 extern long __memcpy_user(void *dst, const void *src, unsigned long count);
 
-#define clear_user(dst,count)                  __memset_user(____force(dst), (count))
+#define __clear_user(dst,count)                        __memset_user(____force(dst), (count))
 #define __copy_from_user_inatomic(to, from, n) __memcpy_user((to), ____force(from), (n))
 #define __copy_to_user_inatomic(to, from, n)   __memcpy_user(____force(to), (from), (n))
 
 #else
 
-#define clear_user(dst,count)                  (memset(____force(dst), 0, (count)), 0)
+#define __clear_user(dst,count)                        (memset(____force(dst), 0, (count)), 0)
 #define __copy_from_user_inatomic(to, from, n) (memcpy((to), ____force(from), (n)), 0)
 #define __copy_to_user_inatomic(to, from, n)   (memcpy(____force(to), (from), (n)), 0)
 
 #endif
 
-#define __clear_user clear_user
+static inline unsigned long __must_check
+clear_user(void __user *to, unsigned long n)
+{
+       if (likely(__access_ok(to, n)))
+               n = __clear_user(to, n);
+       return n;
+}
 
 static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
index f000a382bc7f62f28dfe980ab184904c70681914..f61cfb28e9f283800f968c2953705851da429e68 100644 (file)
@@ -103,7 +103,8 @@ static inline long hexagon_strncpy_from_user(char *dst, const char __user *src,
 {
        long res = __strnlen_user(src, n);
 
-       /* return from strnlen can't be zero -- that would be rubbish. */
+       if (unlikely(!res))
+               return -EFAULT;
 
        if (res > n) {
                copy_from_user(dst, src, n);
index eb0249e3798112615fd5774d6f30229aa6241e53..2c86a4ef67424c0495c5438854d1794198a74b3f 100644 (file)
@@ -53,6 +53,7 @@ config IA64
        select MODULES_USE_ELF_RELA
        select ARCH_USE_CMPXCHG_LOCKREF
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_HARDENED_USERCOPY
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
diff --git a/arch/ia64/include/asm/early_ioremap.h b/arch/ia64/include/asm/early_ioremap.h
new file mode 100644 (file)
index 0000000..eec9e1d
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _ASM_IA64_EARLY_IOREMAP_H
+#define _ASM_IA64_EARLY_IOREMAP_H
+
+extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
+#define early_memremap(phys_addr, size)        early_ioremap(phys_addr, size)
+
+extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
+#define early_memunmap(addr, size)             early_iounmap(addr, size)
+
+#endif
index 8fdb9c7eeb6641c7c538116f48bd69fec5ce2930..5de673ac9cb13602dc6e8cc31d9a78b38448bbf5 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <asm/unaligned.h>
+#include <asm/early_ioremap.h>
 
 /* We don't use IO slowdowns on the ia64, but.. */
 #define __SLOW_DOWN_IO do { } while (0)
@@ -427,10 +428,6 @@ __writeq (unsigned long val, volatile void __iomem *addr)
 extern void __iomem * ioremap(unsigned long offset, unsigned long size);
 extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
 extern void iounmap (volatile void __iomem *addr);
-extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
-#define early_memremap(phys_addr, size)        early_ioremap(phys_addr, size)
-extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
-#define early_memunmap(addr, size)             early_iounmap(addr, size)
 static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size)
 {
        return ioremap(phys_addr, size);
index 4f3fb6ccbf2139b3e23798df6615e34ec5e4d09a..71e8c6f45a1d2e233e0978d677d5b4f2106882e1 100644 (file)
@@ -241,12 +241,16 @@ extern unsigned long __must_check __copy_user (void __user *to, const void __use
 static inline unsigned long
 __copy_to_user (void __user *to, const void *from, unsigned long count)
 {
+       check_object_size(from, count, true);
+
        return __copy_user(to, (__force void __user *) from, count);
 }
 
 static inline unsigned long
 __copy_from_user (void *to, const void __user *from, unsigned long count)
 {
+       check_object_size(to, count, false);
+
        return __copy_user((__force void __user *) to, from, count);
 }
 
@@ -258,22 +262,22 @@ __copy_from_user (void *to, const void __user *from, unsigned long count)
        const void *__cu_from = (from);                                                 \
        long __cu_len = (n);                                                            \
                                                                                        \
-       if (__access_ok(__cu_to, __cu_len, get_fs()))                                   \
-               __cu_len = __copy_user(__cu_to, (__force void __user *) __cu_from, __cu_len);   \
+       if (__access_ok(__cu_to, __cu_len, get_fs())) {                                 \
+               check_object_size(__cu_from, __cu_len, true);                   \
+               __cu_len = __copy_user(__cu_to, (__force void __user *)  __cu_from, __cu_len);  \
+       }                                                                               \
        __cu_len;                                                                       \
 })
 
-#define copy_from_user(to, from, n)                                                    \
-({                                                                                     \
-       void *__cu_to = (to);                                                           \
-       const void __user *__cu_from = (from);                                          \
-       long __cu_len = (n);                                                            \
-                                                                                       \
-       __chk_user_ptr(__cu_from);                                                      \
-       if (__access_ok(__cu_from, __cu_len, get_fs()))                                 \
-               __cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len);   \
-       __cu_len;                                                                       \
-})
+static inline unsigned long
+copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       if (likely(__access_ok(from, n, get_fs())))
+               n = __copy_user((__force void __user *) to, from, n);
+       else
+               memset(to, 0, n);
+       return n;
+}
 
 #define __copy_in_user(to, from, size) __copy_user((to), (from), (size))
 
index cac7014daef3aa6949d17a72824a757dfdbee5b4..6f8982157a75849b491c8461c0c3b34d4c7c4088 100644 (file)
@@ -219,7 +219,7 @@ extern int fixup_exception(struct pt_regs *regs);
 #define __get_user_nocheck(x, ptr, size)                               \
 ({                                                                     \
        long __gu_err = 0;                                              \
-       unsigned long __gu_val;                                         \
+       unsigned long __gu_val = 0;                                     \
        might_fault();                                                  \
        __get_user_size(__gu_val, (ptr), (size), __gu_err);             \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
index 470e365f04ea4ee3f4503c060e8dacbd1e9dd0da..8ff0a70865f65cc9f9f71d9b9f126dd7fb820793 100644 (file)
 #define atomic_dec(v) atomic_sub(1, (v))
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_if_positive(v)       atomic_sub_if_positive(1, v)
 
 #endif
 
-#define atomic_dec_if_positive(v)       atomic_sub_if_positive(1, v)
-
 #include <asm-generic/atomic64.h>
 
 #endif /* __ASM_METAG_ATOMIC_H */
index a62581815624787a57881f50057e57a9fb2957cc..88fa25fae8bd9ca3065558df052891c1d68d45cd 100644 (file)
@@ -61,7 +61,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v)            \
                "       CMPT    %0, #HI(0x02000000)\n"                  \
                "       BNZ 1b\n"                                       \
                : "=&d" (temp), "=&da" (result)                         \
-               : "da" (&v->counter), "bd" (i)                          \
+               : "da" (&v->counter), "br" (i)                          \
                : "cc");                                                \
                                                                        \
        smp_mb();                                                       \
index 0154e2807ebb59b1c6720f140782fc247f4fea2e..2369ad39487607c26ebc5c1f2bb3c61765bd67c1 100644 (file)
@@ -73,7 +73,7 @@ static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old,
                      " DCACHE  [%2], %0\n"
 #endif
                      "2:\n"
-                     : "=&d" (temp), "=&da" (retval)
+                     : "=&d" (temp), "=&d" (retval)
                      : "da" (m), "bd" (old), "da" (new)
                      : "cc"
                      );
index 8282cbce7e399a84488e675af0751341d24f0205..273e61225c277ae67ba28dfae4ef9123e3ef34a9 100644 (file)
@@ -204,8 +204,9 @@ extern unsigned long __must_check __copy_user_zeroing(void *to,
 static inline unsigned long
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       if (access_ok(VERIFY_READ, from, n))
+       if (likely(access_ok(VERIFY_READ, from, n)))
                return __copy_user_zeroing(to, from, n);
+       memset(to, 0, n);
        return n;
 }
 
index 331b0d35f89ce301ad9ba876be7322f417d7c909..826676778094f23a8ced8264b5c448184c0fa006 100644 (file)
@@ -227,7 +227,7 @@ extern long __user_bad(void);
 
 #define __get_user(x, ptr)                                             \
 ({                                                                     \
-       unsigned long __gu_val;                                         \
+       unsigned long __gu_val = 0;                                     \
        /*unsigned long __gu_ptr = (unsigned long)(ptr);*/              \
        long __gu_err;                                                  \
        switch (sizeof(*(ptr))) {                                       \
@@ -373,10 +373,13 @@ extern long __user_bad(void);
 static inline long copy_from_user(void *to,
                const void __user *from, unsigned long n)
 {
+       unsigned long res = n;
        might_fault();
-       if (access_ok(VERIFY_READ, from, n))
-               return __copy_from_user(to, from, n);
-       return n;
+       if (likely(access_ok(VERIFY_READ, from, n)))
+               res = __copy_from_user(to, from, n);
+       if (unlikely(res))
+               memset(to + (n - res), 0, res);
+       return res;
 }
 
 #define __copy_to_user(to, from, n)    \
index f0e314ceb8baa84d36ea6664772f71df46ad003f..7f975b20b20c713e6225d14e3984013f57fe5026 100644 (file)
@@ -113,42 +113,6 @@ config SPINLOCK_TEST
        help
          Add several files to the debugfs to test spinlock speed.
 
-if CPU_MIPSR6
-
-choice
-       prompt "Compact branch policy"
-       default MIPS_COMPACT_BRANCHES_OPTIMAL
-
-config MIPS_COMPACT_BRANCHES_NEVER
-       bool "Never (force delay slot branches)"
-       help
-         Pass the -mcompact-branches=never flag to the compiler in order to
-         force it to always emit branches with delay slots, and make no use
-         of the compact branch instructions introduced by MIPSr6. This is
-         useful if you suspect there may be an issue with compact branches in
-         either the compiler or the CPU.
-
-config MIPS_COMPACT_BRANCHES_OPTIMAL
-       bool "Optimal (use where beneficial)"
-       help
-         Pass the -mcompact-branches=optimal flag to the compiler in order for
-         it to make use of compact branch instructions where it deems them
-         beneficial, and use branches with delay slots elsewhere. This is the
-         default compiler behaviour, and should be used unless you have a
-         reason to choose otherwise.
-
-config MIPS_COMPACT_BRANCHES_ALWAYS
-       bool "Always (force compact branches)"
-       help
-         Pass the -mcompact-branches=always flag to the compiler in order to
-         force it to always emit compact branches, making no use of branch
-         instructions with delay slots. This can result in more compact code
-         which may be beneficial in some scenarios.
-
-endchoice
-
-endif # CPU_MIPSR6
-
 config SCACHE_DEBUGFS
        bool "L2 cache debugfs entries"
        depends on DEBUG_FS
index 3f70ba54ae21e909973ad9913eb71151fcc50492..252e347958f383354a597323078512846f592d52 100644 (file)
@@ -204,10 +204,6 @@ toolchain-msa                              := $(call cc-option-yn,$(mips-cflags) -mhard-float -mfp64 -Wa$(
 cflags-$(toolchain-msa)                        += -DTOOLCHAIN_SUPPORTS_MSA
 endif
 
-cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_NEVER)   += -mcompact-branches=never
-cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_OPTIMAL) += -mcompact-branches=optimal
-cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_ALWAYS)  += -mcompact-branches=always
-
 #
 # Firmware support
 #
index e689b894353c451b806b6429f3242db0486ff22a..8dedee1def8398a14cc2059568278940842906de 100644 (file)
        ldc1    $f28, THREAD_FPR28(\thread)
        ldc1    $f30, THREAD_FPR30(\thread)
        ctc1    \tmp, fcr31
+       .set    pop
        .endm
 
        .macro  fpu_restore_16odd thread
index 2f82bfa3a77347155a1526dde873387d01dcf138..c9f5769dfc8fca9d10c1ce4fe12ff62d3c4c8c66 100644 (file)
 #define CP0_EBASE $15, 1
 
        .macro  kernel_entry_setup
+#ifdef CONFIG_SMP
        mfc0    t0, CP0_EBASE
        andi    t0, t0, 0x3ff           # CPUNum
        beqz    t0, 1f
        # CPUs other than zero goto smp_bootstrap
        j       smp_bootstrap
+#endif /* CONFIG_SMP */
 
 1:
        .endm
index f6fc6aac54963fcebcf7a55e094ec32689923ea7..b6578611dddbfc37e9a7bea36886affe93d87411 100644 (file)
@@ -152,7 +152,7 @@ static inline int is_syscall_success(struct pt_regs *regs)
 
 static inline long regs_return_value(struct pt_regs *regs)
 {
-       if (is_syscall_success(regs))
+       if (is_syscall_success(regs) || !user_mode(regs))
                return regs->regs[2];
        else
                return -regs->regs[2];
index 095ecafe6bd3525444c27812937e2d085bf69b2a..c74c32ccc647200ec7941bac172a8ab1dfbe1236 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/thread_info.h>
+#include <linux/string.h>
 #include <asm/asm-eva.h>
 
 /*
@@ -1170,6 +1171,8 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
                        __cu_len = __invoke_copy_from_user(__cu_to,     \
                                                           __cu_from,   \
                                                           __cu_len);   \
+               } else {                                                \
+                       memset(__cu_to, 0, __cu_len);                   \
                }                                                       \
        }                                                               \
        __cu_len;                                                       \
index 34c325c674c445306667ece3d7c422a51ff686c4..70a4a2f173ffca76cb05d078190e875ed6a06d95 100644 (file)
@@ -36,7 +36,6 @@ struct arch_uprobe {
        unsigned long   resume_epc;
        u32     insn[2];
        u32     ixol[2];
-       union   mips_instruction orig_inst[MAX_UINSN_BYTES / 4];
 };
 
 struct arch_uprobe_task {
index 1f910563fdf60b3be0b4dcdca024837638818bf8..d76275da54cb89df684a9575dd33461fd22da3d8 100644 (file)
@@ -23,7 +23,7 @@ static struct clocksource clocksource_mips = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static u64 notrace r4k_read_sched_clock(void)
+static u64 __maybe_unused notrace r4k_read_sched_clock(void)
 {
        return read_c0_count();
 }
@@ -82,7 +82,9 @@ int __init init_r4k_clocksource(void)
 
        clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
+#ifndef CONFIG_CPU_FREQ
        sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
+#endif
 
        return 0;
 }
index 4674a74a08b5491783ffcd83f4dad8a947e61233..af27334d6809b7a7d2e9918da1ed7a28575c53c7 100644 (file)
@@ -1164,7 +1164,9 @@ fpu_emul:
                regs->regs[31] = r31;
                regs->cp0_epc = epc;
                if (!used_math()) {     /* First time FPU user.  */
+                       preempt_disable();
                        err = init_fpu();
+                       preempt_enable();
                        set_used_math();
                }
                lose_fpu(1);    /* Save FPU state for the emulator. */
index 89847bee2b53538eba13f74a89b43ae8e9aec43b..44a6f25e902eed401ee227ce79ab2ffa64d76ab3 100644 (file)
@@ -593,14 +593,14 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
                return -EOPNOTSUPP;
 
        /* Avoid inadvertently triggering emulation */
-       if ((value & PR_FP_MODE_FR) && cpu_has_fpu &&
-           !(current_cpu_data.fpu_id & MIPS_FPIR_F64))
+       if ((value & PR_FP_MODE_FR) && raw_cpu_has_fpu &&
+           !(raw_current_cpu_data.fpu_id & MIPS_FPIR_F64))
                return -EOPNOTSUPP;
-       if ((value & PR_FP_MODE_FRE) && cpu_has_fpu && !cpu_has_fre)
+       if ((value & PR_FP_MODE_FRE) && raw_cpu_has_fpu && !cpu_has_fre)
                return -EOPNOTSUPP;
 
        /* FR = 0 not supported in MIPS R6 */
-       if (!(value & PR_FP_MODE_FR) && cpu_has_fpu && cpu_has_mips_r6)
+       if (!(value & PR_FP_MODE_FR) && raw_cpu_has_fpu && cpu_has_mips_r6)
                return -EOPNOTSUPP;
 
        /* Proceed with the mode switch */
index 5a69eb48d0a8cef87c33c3184f4ddc3236f01d2d..ee93d5fe61d7020487794ea2dcaedaff203bb006 100644 (file)
@@ -344,7 +344,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_ni_syscall                  /* available, was setaltroot */
        PTR     sys_add_key
        PTR     sys_request_key
-       PTR     sys_keyctl                      /* 6245 */
+       PTR     compat_sys_keyctl               /* 6245 */
        PTR     sys_set_thread_area
        PTR     sys_inotify_init
        PTR     sys_inotify_add_watch
index e4b6d7c9782263e7c6dfca1b7eb4e6818ca78a6e..b77052ec6fb21fa51ce3c1e845947f75740b3fee 100644 (file)
@@ -500,7 +500,7 @@ EXPORT(sys32_call_table)
        PTR     sys_ni_syscall                  /* available, was setaltroot */
        PTR     sys_add_key                     /* 4280 */
        PTR     sys_request_key
-       PTR     sys_keyctl
+       PTR     compat_sys_keyctl
        PTR     sys_set_thread_area
        PTR     sys_inotify_init
        PTR     sys_inotify_add_watch           /* 4285 */
index 2b521e07b8601a2c80e888b3064009779effa78b..7fef02a9eb85c7827284a490fd862dcf653d2a83 100644 (file)
@@ -174,6 +174,9 @@ asmlinkage void start_secondary(void)
        cpumask_set_cpu(cpu, &cpu_coherent_mask);
        notify_cpu_starting(cpu);
 
+       cpumask_set_cpu(cpu, &cpu_callin_map);
+       synchronise_count_slave(cpu);
+
        set_cpu_online(cpu, true);
 
        set_cpu_sibling_map(cpu);
@@ -181,10 +184,6 @@ asmlinkage void start_secondary(void)
 
        calculate_cpu_foreign_map();
 
-       cpumask_set_cpu(cpu, &cpu_callin_map);
-
-       synchronise_count_slave(cpu);
-
        /*
         * irq will be enabled in ->smp_finish(), enabling it too early
         * is dangerous.
index 8452d933a6453c9a1f8655d56a3e0812605a6a12..4e7b89f2e244ef00f0290892b09aba98b6827f28 100644 (file)
@@ -157,7 +157,6 @@ bool is_trap_insn(uprobe_opcode_t *insn)
 int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs)
 {
        struct uprobe_task *utask = current->utask;
-       union mips_instruction insn;
 
        /*
         * Now find the EPC where to resume after the breakpoint has been
@@ -168,10 +167,10 @@ int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs)
                unsigned long epc;
 
                epc = regs->cp0_epc;
-               __compute_return_epc_for_insn(regs, insn);
+               __compute_return_epc_for_insn(regs,
+                       (union mips_instruction) aup->insn[0]);
                aup->resume_epc = regs->cp0_epc;
        }
-
        utask->autask.saved_trap_nr = current->thread.trap_nr;
        current->thread.trap_nr = UPROBE_TRAP_NR;
        regs->cp0_epc = current->utask->xol_vaddr;
@@ -257,7 +256,7 @@ unsigned long arch_uretprobe_hijack_return_addr(
        ra = regs->regs[31];
 
        /* Replace the return address with the trampoline address */
-       regs->regs[31] = ra;
+       regs->regs[31] = trampoline_vaddr;
 
        return ra;
 }
@@ -280,24 +279,6 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
        return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
 }
 
-/**
- * set_orig_insn - Restore the original instruction.
- * @mm: the probed process address space.
- * @auprobe: arch specific probepoint information.
- * @vaddr: the virtual address to insert the opcode.
- *
- * For mm @mm, restore the original opcode (opcode) at @vaddr.
- * Return 0 (success) or a negative errno.
- *
- * This overrides the weak version in kernel/events/uprobes.c.
- */
-int set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
-                unsigned long vaddr)
-{
-       return uprobe_write_opcode(mm, vaddr,
-                       *(uprobe_opcode_t *)&auprobe->orig_inst[0].word);
-}
-
 void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
                                  void *src, unsigned long len)
 {
index 975e99759bab9ec1ae6aa80a47fa2f97765efcc6..5649a9e429e0a52861fb8d676f1a1103200b157a 100644 (file)
@@ -39,16 +39,16 @@ static struct vm_special_mapping vdso_vvar_mapping = {
 static void __init init_vdso_image(struct mips_vdso_image *image)
 {
        unsigned long num_pages, i;
+       unsigned long data_pfn;
 
        BUG_ON(!PAGE_ALIGNED(image->data));
        BUG_ON(!PAGE_ALIGNED(image->size));
 
        num_pages = image->size / PAGE_SIZE;
 
-       for (i = 0; i < num_pages; i++) {
-               image->mapping.pages[i] =
-                       virt_to_page(image->data + (i * PAGE_SIZE));
-       }
+       data_pfn = __phys_to_pfn(__pa_symbol(image->data));
+       for (i = 0; i < num_pages; i++)
+               image->mapping.pages[i] = pfn_to_page(data_pfn + i);
 }
 
 static int __init init_vdso(void)
index dc10c77b7500767a05ff835078b8825ceab21f28..3251b206e55ab03964a6f2337be20877f315de77 100644 (file)
@@ -807,6 +807,47 @@ enum emulation_result kvm_mips_emul_tlbr(struct kvm_vcpu *vcpu)
        return EMULATE_FAIL;
 }
 
+/**
+ * kvm_mips_invalidate_guest_tlb() - Indicates a change in guest MMU map.
+ * @vcpu:      VCPU with changed mappings.
+ * @tlb:       TLB entry being removed.
+ *
+ * This is called to indicate a single change in guest MMU mappings, so that we
+ * can arrange TLB flushes on this and other CPUs.
+ */
+static void kvm_mips_invalidate_guest_tlb(struct kvm_vcpu *vcpu,
+                                         struct kvm_mips_tlb *tlb)
+{
+       int cpu, i;
+       bool user;
+
+       /* No need to flush for entries which are already invalid */
+       if (!((tlb->tlb_lo[0] | tlb->tlb_lo[1]) & ENTRYLO_V))
+               return;
+       /* User address space doesn't need flushing for KSeg2/3 changes */
+       user = tlb->tlb_hi < KVM_GUEST_KSEG0;
+
+       preempt_disable();
+
+       /*
+        * Probe the shadow host TLB for the entry being overwritten, if one
+        * matches, invalidate it
+        */
+       kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
+
+       /* Invalidate the whole ASID on other CPUs */
+       cpu = smp_processor_id();
+       for_each_possible_cpu(i) {
+               if (i == cpu)
+                       continue;
+               if (user)
+                       vcpu->arch.guest_user_asid[i] = 0;
+               vcpu->arch.guest_kernel_asid[i] = 0;
+       }
+
+       preempt_enable();
+}
+
 /* Write Guest TLB Entry @ Index */
 enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
 {
@@ -826,11 +867,8 @@ enum emulation_result kvm_mips_emul_tlbwi(struct kvm_vcpu *vcpu)
        }
 
        tlb = &vcpu->arch.guest_tlb[index];
-       /*
-        * Probe the shadow host TLB for the entry being overwritten, if one
-        * matches, invalidate it
-        */
-       kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
+
+       kvm_mips_invalidate_guest_tlb(vcpu, tlb);
 
        tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
        tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
@@ -859,11 +897,7 @@ enum emulation_result kvm_mips_emul_tlbwr(struct kvm_vcpu *vcpu)
 
        tlb = &vcpu->arch.guest_tlb[index];
 
-       /*
-        * Probe the shadow host TLB for the entry being overwritten, if one
-        * matches, invalidate it
-        */
-       kvm_mips_host_tlb_inv(vcpu, tlb->tlb_hi);
+       kvm_mips_invalidate_guest_tlb(vcpu, tlb);
 
        tlb->tlb_mask = kvm_read_c0_guest_pagemask(cop0);
        tlb->tlb_hi = kvm_read_c0_guest_entryhi(cop0);
@@ -982,6 +1016,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
        int32_t rt, rd, copz, sel, co_bit, op;
        uint32_t pc = vcpu->arch.pc;
        unsigned long curr_pc;
+       int cpu, i;
 
        /*
         * Update PC and hold onto current PC in case there is
@@ -1089,8 +1124,16 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc,
                                                vcpu->arch.gprs[rt]
                                                & ASID_MASK);
 
+                                       preempt_disable();
                                        /* Blow away the shadow host TLBs */
                                        kvm_mips_flush_host_tlb(1);
+                                       cpu = smp_processor_id();
+                                       for_each_possible_cpu(i)
+                                               if (i != cpu) {
+                                                       vcpu->arch.guest_user_asid[i] = 0;
+                                                       vcpu->arch.guest_kernel_asid[i] = 0;
+                                               }
+                                       preempt_enable();
                                }
                                kvm_write_c0_guest_entryhi(cop0,
                                                           vcpu->arch.gprs[rt]);
@@ -1629,8 +1672,14 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
 
        preempt_disable();
        if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) {
-               if (kvm_mips_host_tlb_lookup(vcpu, va) < 0)
-                       kvm_mips_handle_kseg0_tlb_fault(va, vcpu);
+               if (kvm_mips_host_tlb_lookup(vcpu, va) < 0 &&
+                   kvm_mips_handle_kseg0_tlb_fault(va, vcpu)) {
+                       kvm_err("%s: handling mapped kseg0 tlb fault for %lx, vcpu: %p, ASID: %#lx\n",
+                               __func__, va, vcpu, read_c0_entryhi());
+                       er = EMULATE_FAIL;
+                       preempt_enable();
+                       goto done;
+               }
        } else if ((KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0) ||
                   KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) {
                int index;
@@ -1665,14 +1714,19 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
                                                                run, vcpu);
                                preempt_enable();
                                goto dont_update_pc;
-                       } else {
-                               /*
-                                * We fault an entry from the guest tlb to the
-                                * shadow host TLB
-                                */
-                               kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
-                                                                    NULL,
-                                                                    NULL);
+                       }
+                       /*
+                        * We fault an entry from the guest tlb to the
+                        * shadow host TLB
+                        */
+                       if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
+                                                                NULL, NULL)) {
+                               kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
+                                       __func__, va, index, vcpu,
+                                       read_c0_entryhi());
+                               er = EMULATE_FAIL;
+                               preempt_enable();
+                               goto done;
                        }
                }
        } else {
@@ -2633,8 +2687,13 @@ enum emulation_result kvm_mips_handle_tlbmiss(unsigned long cause,
                         * OK we have a Guest TLB entry, now inject it into the
                         * shadow host TLB
                         */
-                       kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb, NULL,
-                                                            NULL);
+                       if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb,
+                                                                NULL, NULL)) {
+                               kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
+                                       __func__, va, index, vcpu,
+                                       read_c0_entryhi());
+                               er = EMULATE_FAIL;
+                       }
                }
        }
 
index aed0ac2a4972cd1daf0f2992db6c100e9912fb70..eff71c75dc2703b4dacf3691d85d785967f3f913 100644 (file)
@@ -152,7 +152,7 @@ static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn)
        srcu_idx = srcu_read_lock(&kvm->srcu);
        pfn = kvm_mips_gfn_to_pfn(kvm, gfn);
 
-       if (kvm_mips_is_error_pfn(pfn)) {
+       if (is_error_noslot_pfn(pfn)) {
                kvm_err("Couldn't get pfn for gfn %#" PRIx64 "!\n", gfn);
                err = -EFAULT;
                goto out;
@@ -276,7 +276,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
        }
 
        gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
-       if (gfn >= kvm->arch.guest_pmap_npages) {
+       if ((gfn | 1) >= kvm->arch.guest_pmap_npages) {
                kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
                        gfn, badvaddr);
                kvm_mips_dump_host_tlbs();
@@ -361,25 +361,39 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
        unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
        struct kvm *kvm = vcpu->kvm;
        pfn_t pfn0, pfn1;
-
-       if ((tlb->tlb_hi & VPN2_MASK) == 0) {
-               pfn0 = 0;
-               pfn1 = 0;
-       } else {
-               if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo0)
-                                          >> PAGE_SHIFT) < 0)
-                       return -1;
-
-               if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo1)
-                                          >> PAGE_SHIFT) < 0)
-                       return -1;
-
-               pfn0 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo0)
-                                           >> PAGE_SHIFT];
-               pfn1 = kvm->arch.guest_pmap[mips3_tlbpfn_to_paddr(tlb->tlb_lo1)
-                                           >> PAGE_SHIFT];
+       gfn_t gfn0, gfn1;
+       long tlb_lo[2];
+
+       tlb_lo[0] = tlb->tlb_lo0;
+       tlb_lo[1] = tlb->tlb_lo1;
+
+       /*
+        * The commpage address must not be mapped to anything else if the guest
+        * TLB contains entries nearby, or commpage accesses will break.
+        */
+       if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) &
+                       VPN2_MASK & (PAGE_MASK << 1)))
+               tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
+
+       gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
+       gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
+       if (gfn0 >= kvm->arch.guest_pmap_npages ||
+           gfn1 >= kvm->arch.guest_pmap_npages) {
+               kvm_err("%s: Invalid gfn: [%#llx, %#llx], EHi: %#lx\n",
+                       __func__, gfn0, gfn1, tlb->tlb_hi);
+               kvm_mips_dump_guest_tlbs(vcpu);
+               return -1;
        }
 
+       if (kvm_mips_map_page(kvm, gfn0) < 0)
+               return -1;
+
+       if (kvm_mips_map_page(kvm, gfn1) < 0)
+               return -1;
+
+       pfn0 = kvm->arch.guest_pmap[gfn0];
+       pfn1 = kvm->arch.guest_pmap[gfn1];
+
        if (hpa0)
                *hpa0 = pfn0 << PAGE_SHIFT;
 
@@ -391,9 +405,9 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
                                               kvm_mips_get_kernel_asid(vcpu) :
                                               kvm_mips_get_user_asid(vcpu));
        entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) | (0x3 << 3) |
-                  (tlb->tlb_lo0 & MIPS3_PG_D) | (tlb->tlb_lo0 & MIPS3_PG_V);
+                  (tlb_lo[0] & MIPS3_PG_D) | (tlb_lo[0] & MIPS3_PG_V);
        entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) | (0x3 << 3) |
-                  (tlb->tlb_lo1 & MIPS3_PG_D) | (tlb->tlb_lo1 & MIPS3_PG_V);
+                  (tlb_lo[1] & MIPS3_PG_D) | (tlb_lo[1] & MIPS3_PG_V);
 
        kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
                  tlb->tlb_lo0, tlb->tlb_lo1);
@@ -794,10 +808,16 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu)
                                local_irq_restore(flags);
                                return KVM_INVALID_INST;
                        }
-                       kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
-                                                            &vcpu->arch.
-                                                            guest_tlb[index],
-                                                            NULL, NULL);
+                       if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
+                                               &vcpu->arch.guest_tlb[index],
+                                               NULL, NULL)) {
+                               kvm_err("%s: handling mapped seg tlb fault failed for %p, index: %u, vcpu: %p, ASID: %#lx\n",
+                                       __func__, opc, index, vcpu,
+                                       read_c0_entryhi());
+                               kvm_mips_dump_guest_tlbs(vcpu);
+                               local_irq_restore(flags);
+                               return KVM_INVALID_INST;
+                       }
                        inst = *(opc);
                }
                local_irq_restore(flags);
index a2631a52ca998c0029b27cec6fa85bac9d0782d0..444802e78554e85cc176496bcf22f9ef01a41676 100644 (file)
@@ -13,8 +13,8 @@
 #define SMBUS_PCI_REG64                0x64
 #define SMBUS_PCI_REGB4                0xb4
 
-#define HPET_MIN_CYCLES                64
-#define HPET_MIN_PROG_DELTA    (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1))
+#define HPET_MIN_CYCLES                16
+#define HPET_MIN_PROG_DELTA    (HPET_MIN_CYCLES * 12)
 
 static DEFINE_SPINLOCK(hpet_lock);
 DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device);
@@ -157,14 +157,14 @@ static int hpet_tick_resume(struct clock_event_device *evt)
 static int hpet_next_event(unsigned long delta,
                struct clock_event_device *evt)
 {
-       unsigned int cnt;
-       int res;
+       u32 cnt;
+       s32 res;
 
        cnt = hpet_read(HPET_COUNTER);
-       cnt += delta;
+       cnt += (u32) delta;
        hpet_write(HPET_T0_CMP, cnt);
 
-       res = (int)(cnt - hpet_read(HPET_COUNTER));
+       res = (s32)(cnt - hpet_read(HPET_COUNTER));
 
        return res < HPET_MIN_CYCLES ? -ETIME : 0;
 }
@@ -230,7 +230,7 @@ void __init setup_hpet_timer(void)
 
        cd = &per_cpu(hpet_clockevent_device, cpu);
        cd->name = "hpet";
-       cd->rating = 320;
+       cd->rating = 100;
        cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
        cd->set_state_shutdown = hpet_set_state_shutdown;
        cd->set_state_periodic = hpet_set_state_periodic;
index b4a8378935625b2e1d0f228f6961ebd8208544f1..5abe51cad8994122d29fca0b7bea59e336cea6cb 100644 (file)
@@ -65,7 +65,7 @@ static struct insn insn_table[] = {
 #ifndef CONFIG_CPU_MIPSR6
        { insn_cache,  M(cache_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
 #else
-       { insn_cache,  M6(cache_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
+       { insn_cache,  M6(spec3_op, 0, 0, 0, cache6_op),  RS | RT | SIMM9 },
 #endif
        { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
        { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
index 4740c82fb97a14e95118d05590b66b3192e9f1f5..36b09b2ea9729144c19ebd69a734b28a8ad2d45d 100644 (file)
@@ -39,6 +39,9 @@
 #include <linux/console.h>
 #endif
 
+#define ROCIT_CONFIG_GEN0              0x1f403000
+#define  ROCIT_CONFIG_GEN0_PCI_IOCU    BIT(7)
+
 extern void malta_be_init(void);
 extern int malta_be_handler(struct pt_regs *regs, int is_fixup);
 
@@ -107,6 +110,8 @@ static void __init fd_activate(void)
 static int __init plat_enable_iocoherency(void)
 {
        int supported = 0;
+       u32 cfg;
+
        if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) {
                if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
                        BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
@@ -129,7 +134,8 @@ static int __init plat_enable_iocoherency(void)
        } else if (mips_cm_numiocu() != 0) {
                /* Nothing special needs to be done to enable coherency */
                pr_info("CMP IOCU detected\n");
-               if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) {
+               cfg = __raw_readl((u32 *)CKSEG1ADDR(ROCIT_CONFIG_GEN0));
+               if (!(cfg & ROCIT_CONFIG_GEN0_PCI_IOCU)) {
                        pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n");
                        return 0;
                }
index 090393aa0f20d576a3bc87f64ed672998da828b4..6c7d78546eeeb9248e6ba8a007dcbc1d15a983ca 100644 (file)
@@ -75,7 +75,7 @@ obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o)
 $(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi)
 $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi)
 
-$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi)
+$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi)
 
 $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
        $(call if_changed,vdsold)
index 537278746a1534cead71e487aea7f13533e60b97..4af43d9ba4950dc7ec7d04051d276f66d35ceeac 100644 (file)
@@ -181,6 +181,7 @@ struct __large_struct { unsigned long buf[100]; };
                "2:\n"                                          \
                "       .section        .fixup,\"ax\"\n"        \
                "3:\n\t"                                        \
+               "       mov             0,%1\n"                 \
                "       mov             %3,%0\n"                \
                "       jmp             2b\n"                   \
                "       .previous\n"                            \
index 7826e6c364e74f0075e43081e5db367062baef30..ce8899e5e171370ebc88c08a91727ef9232febf9 100644 (file)
@@ -9,7 +9,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the Licence, or (at your option) any later version.
  */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
@@ -24,6 +24,8 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
 {
        if (access_ok(VERIFY_READ, from, n))
                __copy_user_zeroing(to, from, n);
+       else
+               memset(to, 0, n);
        return n;
 }
 
index caa51ff85a3c7d0ac7c57cf034758185aad64724..0ab82324c8174559ddd478aa0a2dd171b652b8c0 100644 (file)
@@ -102,9 +102,12 @@ extern long __copy_to_user(void __user *to, const void *from, unsigned long n);
 static inline long copy_from_user(void *to, const void __user *from,
                                unsigned long n)
 {
-       if (!access_ok(VERIFY_READ, from, n))
-               return n;
-       return __copy_from_user(to, from, n);
+       unsigned long res = n;
+       if (access_ok(VERIFY_READ, from, n))
+               res = __copy_from_user(to, from, n);
+       if (unlikely(res))
+               memset(to + (n - res), 0, res);
+       return res;
 }
 
 static inline long copy_to_user(void __user *to, const void *from,
@@ -139,7 +142,7 @@ extern long strnlen_user(const char __user *s, long n);
 
 #define __get_user_unknown(val, size, ptr, err) do {                   \
        err = 0;                                                        \
-       if (copy_from_user(&(val), ptr, size)) {                        \
+       if (__copy_from_user(&(val), ptr, size)) {                      \
                err = -EFAULT;                                          \
        }                                                               \
        } while (0)
@@ -166,7 +169,7 @@ do {                                                                        \
        ({                                                              \
        long __gu_err = -EFAULT;                                        \
        const __typeof__(*(ptr)) __user *__gu_ptr = (ptr);              \
-       unsigned long __gu_val;                                         \
+       unsigned long __gu_val = 0;                                     \
        __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
        (x) = (__force __typeof__(x))__gu_val;                          \
        __gu_err;                                                       \
index a6bd07ca3d6c08dc49af6ab4738fe85e1ddcd485..5cc6b4f1b79516a7a5882886b59884d03529df6d 100644 (file)
@@ -273,28 +273,20 @@ __copy_tofrom_user(void *to, const void *from, unsigned long size);
 static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long n)
 {
-       unsigned long over;
-
-       if (access_ok(VERIFY_READ, from, n))
-               return __copy_tofrom_user(to, from, n);
-       if ((unsigned long)from < TASK_SIZE) {
-               over = (unsigned long)from + n - TASK_SIZE;
-               return __copy_tofrom_user(to, from, n - over) + over;
-       }
-       return n;
+       unsigned long res = n;
+
+       if (likely(access_ok(VERIFY_READ, from, n)))
+               res = __copy_tofrom_user(to, from, n);
+       if (unlikely(res))
+               memset(to + (n - res), 0, res);
+       return res;
 }
 
 static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long n)
 {
-       unsigned long over;
-
-       if (access_ok(VERIFY_WRITE, to, n))
-               return __copy_tofrom_user(to, from, n);
-       if ((unsigned long)to < TASK_SIZE) {
-               over = (unsigned long)to + n - TASK_SIZE;
-               return __copy_tofrom_user(to, from, n - over) + over;
-       }
+       if (likely(access_ok(VERIFY_WRITE, to, n)))
+               n = __copy_tofrom_user(to, from, n);
        return n;
 }
 
@@ -303,13 +295,8 @@ extern unsigned long __clear_user(void *addr, unsigned long size);
 static inline __must_check unsigned long
 clear_user(void *addr, unsigned long size)
 {
-
-       if (access_ok(VERIFY_WRITE, addr, size))
-               return __clear_user(addr, size);
-       if ((unsigned long)addr < TASK_SIZE) {
-               unsigned long over = (unsigned long)addr + size - TASK_SIZE;
-               return __clear_user(addr, size - over) + over;
-       }
+       if (likely(access_ok(VERIFY_WRITE, addr, size)))
+               size = __clear_user(addr, size);
        return size;
 }
 
index 291cee28ccb60da84576ba1d9e103a0dc6e78ba5..c2c43f71468498828f924ebc54b9aa3f189ba95e 100644 (file)
@@ -83,10 +83,10 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
 
 /* This is the size of the initially mapped kernel memory */
-#ifdef CONFIG_64BIT
-#define KERNEL_INITIAL_ORDER   25      /* 1<<25 = 32MB */
+#if defined(CONFIG_64BIT)
+#define KERNEL_INITIAL_ORDER   26      /* 1<<26 = 64MB */
 #else
-#define KERNEL_INITIAL_ORDER   24      /* 1<<24 = 16MB */
+#define KERNEL_INITIAL_ORDER   25      /* 1<<25 = 32MB */
 #endif
 #define KERNEL_INITIAL_SIZE    (1 << KERNEL_INITIAL_ORDER)
 
index 6f893d29f1b21625aadc4464d06ffba30b7697f3..30eed2d6d8a8d7d2225b28b2e33f75c2dd0fbf52 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm-generic/uaccess-unaligned.h>
 
 #include <linux/bug.h>
+#include <linux/string.h>
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
@@ -246,13 +247,14 @@ static inline unsigned long __must_check copy_from_user(void *to,
                                           unsigned long n)
 {
         int sz = __compiletime_object_size(to);
-        int ret = -EFAULT;
+        unsigned long ret = n;
 
         if (likely(sz == -1 || !__builtin_constant_p(n) || sz >= n))
                 ret = __copy_from_user(to, from, n);
         else
                 copy_from_user_overflow();
-
+       if (unlikely(ret))
+               memset(to + (n - ret), 0, ret);
         return ret;
 }
 
index c0ae62520d1575526c83b014d194adc0f6a4428a..274d5bc6ecce4aba9e1d19b1cd0e1d6f42ba0eb3 100644 (file)
 #define        ENOTCONN        235     /* Transport endpoint is not connected */
 #define        ESHUTDOWN       236     /* Cannot send after transport endpoint shutdown */
 #define        ETOOMANYREFS    237     /* Too many references: cannot splice */
-#define EREFUSED       ECONNREFUSED    /* for HP's NFS apparently */
 #define        ETIMEDOUT       238     /* Connection timed out */
 #define        ECONNREFUSED    239     /* Connection refused */
-#define EREMOTERELEASE 240     /* Remote peer released connection */
+#define        EREFUSED        ECONNREFUSED    /* for HP's NFS apparently */
+#define        EREMOTERELEASE  240     /* Remote peer released connection */
 #define        EHOSTDOWN       241     /* Host is down */
 #define        EHOSTUNREACH    242     /* No route to host */
 
index f7ea626e29c9b3bce80d28062cbf802ab2313785..81d6f639194478fa96b33a7f30ba4d612c9cfa8f 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/export.h>
 
 #include <asm/processor.h>
+#include <asm/sections.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
 #include <asm/machdep.h>       /* for pa7300lc_init() proto */
@@ -140,6 +141,13 @@ void __init setup_arch(char **cmdline_p)
 #endif
        printk(KERN_CONT ".\n");
 
+       /*
+        * Check if initial kernel page mappings are sufficient.
+        * panic early if not, else we may access kernel functions
+        * and variables which can't be reached.
+        */
+       if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
+               panic("KERNEL_INITIAL_ORDER too small!");
 
        pdc_console_init();
 
index 308f29081d461b0a9b0a0d8eec0d54e0a1936ff3..60771df10fdea4e7ae3a45646a1615fe02823082 100644 (file)
@@ -88,8 +88,9 @@ SECTIONS
        /* Start of data section */
        _sdata = .;
 
-       RO_DATA_SECTION(8)
-
+       /* Architecturally we need to keep __gp below 0x1000000 and thus
+        * in front of RO_DATA_SECTION() which stores lots of tracepoint
+        * and ftrace symbols. */
 #ifdef CONFIG_64BIT
        . = ALIGN(16);
        /* Linkage tables */
@@ -104,6 +105,8 @@ SECTIONS
        }
 #endif
 
+       RO_DATA_SECTION(8)
+
        /* unwind info */
        .PARISC.unwind : {
                __start___unwind = .;
index db49e0d796b1bf50642365aa92d63c5a83a07320..ec7b8f1e4822c66a4ced8bad6cd52f869ad413b2 100644 (file)
@@ -160,6 +160,7 @@ config PPC
        select EDAC_ATOMIC_SCRUB
        select ARCH_HAS_DMA_SET_COHERENT_MASK
        select HAVE_ARCH_SECCOMP_FILTER
+       select HAVE_ARCH_HARDENED_USERCOPY
 
 config GENERIC_CSUM
        def_bool CPU_LITTLE_ENDIAN
index 9f8402b351157d6bb5d5ab9ff7d9326cc5229298..27e588f6c72eec75b1a4f2644272ac16ebd4d7dd 100644 (file)
@@ -164,6 +164,7 @@ struct coprocessor_request_block {
 #define ICSWX_INITIATED                (0x8)
 #define ICSWX_BUSY             (0x4)
 #define ICSWX_REJECTED         (0x2)
+#define ICSWX_XERS0            (0x1)   /* undefined or set from XERSO. */
 
 static inline int icswx(__be32 ccw, struct coprocessor_request_block *crb)
 {
index 070fa85520517943087f8bdc237aa9fefa29bdb7..627d129d7fcbb299b341fe6df5a3e269bcff8358 100644 (file)
 #define   MMCR0_FCHV   0x00000001UL /* freeze conditions in hypervisor mode */
 #define SPRN_MMCR1     798
 #define SPRN_MMCR2     785
+#define SPRN_UMMCR2    769
 #define SPRN_MMCRA     0x312
 #define   MMCRA_SDSYNC 0x80000000UL /* SDAR synced with SIAR */
 #define   MMCRA_SDAR_DCACHE_MISS 0x40000000UL
index 2a8ebae0936beb0f6b3ec46eafaf979f0d8ddedd..db71448b9bb92455cb6b93343b2604f5eb78ebdb 100644 (file)
@@ -323,29 +323,20 @@ extern unsigned long __copy_tofrom_user(void __user *to,
 static inline unsigned long copy_from_user(void *to,
                const void __user *from, unsigned long n)
 {
-       unsigned long over;
-
-       if (access_ok(VERIFY_READ, from, n))
+       if (likely(access_ok(VERIFY_READ, from, n))) {
+               check_object_size(to, n, false);
                return __copy_tofrom_user((__force void __user *)to, from, n);
-       if ((unsigned long)from < TASK_SIZE) {
-               over = (unsigned long)from + n - TASK_SIZE;
-               return __copy_tofrom_user((__force void __user *)to, from,
-                               n - over) + over;
        }
+       memset(to, 0, n);
        return n;
 }
 
 static inline unsigned long copy_to_user(void __user *to,
                const void *from, unsigned long n)
 {
-       unsigned long over;
-
-       if (access_ok(VERIFY_WRITE, to, n))
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               check_object_size(from, n, true);
                return __copy_tofrom_user(to, (__force void __user *)from, n);
-       if ((unsigned long)to < TASK_SIZE) {
-               over = (unsigned long)to + n - TASK_SIZE;
-               return __copy_tofrom_user(to, (__force void __user *)from,
-                               n - over) + over;
        }
        return n;
 }
@@ -387,6 +378,9 @@ static inline unsigned long __copy_from_user_inatomic(void *to,
                if (ret == 0)
                        return 0;
        }
+
+       check_object_size(to, n, false);
+
        return __copy_tofrom_user((__force void __user *)to, from, n);
 }
 
@@ -413,6 +407,9 @@ static inline unsigned long __copy_to_user_inatomic(void __user *to,
                if (ret == 0)
                        return 0;
        }
+
+       check_object_size(from, n, true);
+
        return __copy_tofrom_user(to, (__force const void __user *)from, n);
 }
 
@@ -437,10 +434,6 @@ static inline unsigned long clear_user(void __user *addr, unsigned long size)
        might_fault();
        if (likely(access_ok(VERIFY_WRITE, addr, size)))
                return __clear_user(addr, size);
-       if ((unsigned long)addr < TASK_SIZE) {
-               unsigned long over = (unsigned long)addr + size - TASK_SIZE;
-               return __clear_user(addr, size - over) + over;
-       }
        return size;
 }
 
index b34e8a54f7dbe54dc6c9b4d1b2ad76157f4b2870..98949b0df00a531e2003eef868e05f294600f6df 100644 (file)
@@ -677,7 +677,7 @@ int eeh_pci_enable(struct eeh_pe *pe, int function)
        /* Check if the request is finished successfully */
        if (active_flag) {
                rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
-               if (rc <= 0)
+               if (rc < 0)
                        return rc;
 
                if (rc & active_flag)
index 247a0dc012f10795a82b059274b4e7e1b8969ae3..c07bfb52275e27e307356cf58e48e0ed0db27c72 100644 (file)
@@ -909,6 +909,14 @@ static void eeh_handle_special_event(void)
                                /* Notify all devices to be down */
                                eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
                                bus = eeh_pe_bus_get(phb_pe);
+                               if (!bus) {
+                                       pr_err("%s: Cannot find PCI bus for "
+                                              "PHB#%d-PE#%x\n",
+                                              __func__,
+                                              pe->phb->global_number,
+                                              pe->addr);
+                                       break;
+                               }
                                eeh_pe_dev_traverse(pe,
                                        eeh_report_failure, NULL);
                                pcibios_remove_pci_devices(bus);
index a94f155db78e83d67fca2e967ba43585f18aeda8..edba294620db292a662cd04520e328802c5020c6 100644 (file)
@@ -334,13 +334,13 @@ syscall_exit_work:
 tabort_syscall:
        /* Firstly we need to enable TM in the kernel */
        mfmsr   r10
-       li      r13, 1
-       rldimi  r10, r13, MSR_TM_LG, 63-MSR_TM_LG
+       li      r9, 1
+       rldimi  r10, r9, MSR_TM_LG, 63-MSR_TM_LG
        mtmsrd  r10, 0
 
        /* tabort, this dooms the transaction, nothing else */
-       li      r13, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
-       TABORT(R13)
+       li      r9, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
+       TABORT(R9)
 
        /*
         * Return directly to userspace. We have corrupted user register state,
@@ -348,8 +348,8 @@ tabort_syscall:
         * resume after the tbegin of the aborted transaction with the
         * checkpointed register state.
         */
-       li      r13, MSR_RI
-       andc    r10, r10, r13
+       li      r9, MSR_RI
+       andc    r10, r10, r9
        mtmsrd  r10, 1
        mtspr   SPRN_SRR0, r11
        mtspr   SPRN_SRR1, r12
index 32e26526f7e4e0fc5d22adda109bb075a044ae70..1eb698f653b4c0e060963f1d8308c359cd2f4a06 100644 (file)
@@ -969,7 +969,7 @@ int __init nvram_remove_partition(const char *name, int sig,
 
                /* Make partition a free partition */
                part->header.signature = NVRAM_SIG_FREE;
-               strncpy(part->header.name, "wwwwwwwwwwww", 12);
+               memset(part->header.name, 'w', 12);
                part->header.checksum = nvram_checksum(&part->header);
                rc = nvram_write_header(part);
                if (rc <= 0) {
@@ -987,8 +987,8 @@ int __init nvram_remove_partition(const char *name, int sig,
                }
                if (prev) {
                        prev->header.length += part->header.length;
-                       prev->header.checksum = nvram_checksum(&part->header);
-                       rc = nvram_write_header(part);
+                       prev->header.checksum = nvram_checksum(&prev->header);
+                       rc = nvram_write_header(prev);
                        if (rc <= 0) {
                                printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc);
                                return rc;
index b7e86e00048fafe86f3a6122fb3e8959c7ec187f..7b89e7b305e6b15fb51cfe5cf601dec100e83b7a 100644 (file)
@@ -694,7 +694,7 @@ unsigned char ibm_architecture_vec[] = {
        OV4_MIN_ENT_CAP,                /* minimum VP entitled capacity */
 
        /* option vector 5: PAPR/OF options */
-       VECTOR_LENGTH(18),              /* length */
+       VECTOR_LENGTH(21),              /* length */
        0,                              /* don't ignore, don't halt */
        OV5_FEAT(OV5_LPAR) | OV5_FEAT(OV5_SPLPAR) | OV5_FEAT(OV5_LARGE_PAGES) |
        OV5_FEAT(OV5_DRCONF_MEMORY) | OV5_FEAT(OV5_DONATE_DEDICATE_CPU) |
@@ -725,8 +725,11 @@ unsigned char ibm_architecture_vec[] = {
        0,
        0,
        OV5_FEAT(OV5_PFO_HW_RNG) | OV5_FEAT(OV5_PFO_HW_ENCR) |
-       OV5_FEAT(OV5_PFO_HW_842),
-       OV5_FEAT(OV5_SUB_PROCESSORS),
+       OV5_FEAT(OV5_PFO_HW_842),                               /* Byte 17 */
+       0,                                                      /* Byte 18 */
+       0,                                                      /* Byte 19 */
+       0,                                                      /* Byte 20 */
+       OV5_FEAT(OV5_SUB_PROCESSORS),                           /* Byte 21 */
 
        /* option vector 6: IBM PAPR hints */
        VECTOR_LENGTH(3),               /* length */
index bf8f34a5867088d1a2346d17b89e2daaabe365ab..b7019b559ddbffd817563e6f0d3ae5f3d134b2ca 100644 (file)
@@ -110,17 +110,11 @@ _GLOBAL(tm_reclaim)
        std     r3, STK_PARAM(R3)(r1)
        SAVE_NVGPRS(r1)
 
-       /* We need to setup MSR for VSX register save instructions.  Here we
-        * also clear the MSR RI since when we do the treclaim, we won't have a
-        * valid kernel pointer for a while.  We clear RI here as it avoids
-        * adding another mtmsr closer to the treclaim.  This makes the region
-        * maked as non-recoverable wider than it needs to be but it saves on
-        * inserting another mtmsrd later.
-        */
+       /* We need to setup MSR for VSX register save instructions. */
        mfmsr   r14
        mr      r15, r14
        ori     r15, r15, MSR_FP
-       li      r16, MSR_RI
+       li      r16, 0
        ori     r16, r16, MSR_EE /* IRQs hard off */
        andc    r15, r15, r16
        oris    r15, r15, MSR_VEC@h
@@ -176,7 +170,17 @@ dont_backup_fp:
 1:     tdeqi   r6, 0
        EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0
 
-       /* The moment we treclaim, ALL of our GPRs will switch
+       /* Clear MSR RI since we are about to change r1, EE is already off. */
+       li      r4, 0
+       mtmsrd  r4, 1
+
+       /*
+        * BE CAREFUL HERE:
+        * At this point we can't take an SLB miss since we have MSR_RI
+        * off. Load only to/from the stack/paca which are in SLB bolted regions
+        * until we turn MSR RI back on.
+        *
+        * The moment we treclaim, ALL of our GPRs will switch
         * to user register state.  (FPRs, CCR etc. also!)
         * Use an sprg and a tm_scratch in the PACA to shuffle.
         */
@@ -197,6 +201,11 @@ dont_backup_fp:
 
        /* Store the PPR in r11 and reset to decent value */
        std     r11, GPR11(r1)                  /* Temporary stash */
+
+       /* Reset MSR RI so we can take SLB faults again */
+       li      r11, MSR_RI
+       mtmsrd  r11, 1
+
        mfspr   r11, SPRN_PPR
        HMT_MEDIUM
 
@@ -397,11 +406,6 @@ restore_gprs:
        ld      r5, THREAD_TM_DSCR(r3)
        ld      r6, THREAD_TM_PPR(r3)
 
-       /* Clear the MSR RI since we are about to change R1.  EE is already off
-        */
-       li      r4, 0
-       mtmsrd  r4, 1
-
        REST_GPR(0, r7)                         /* GPR0 */
        REST_2GPRS(2, r7)                       /* GPR2-3 */
        REST_GPR(4, r7)                         /* GPR4 */
@@ -439,10 +443,33 @@ restore_gprs:
        ld      r6, _CCR(r7)
        mtcr    r6
 
-       REST_GPR(1, r7)                         /* GPR1 */
-       REST_GPR(5, r7)                         /* GPR5-7 */
        REST_GPR(6, r7)
-       ld      r7, GPR7(r7)
+
+       /*
+        * Store r1 and r5 on the stack so that we can access them
+        * after we clear MSR RI.
+        */
+
+       REST_GPR(5, r7)
+       std     r5, -8(r1)
+       ld      r5, GPR1(r7)
+       std     r5, -16(r1)
+
+       REST_GPR(7, r7)
+
+       /* Clear MSR RI since we are about to change r1. EE is already off */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /*
+        * BE CAREFUL HERE:
+        * At this point we can't take an SLB miss since we have MSR_RI
+        * off. Load only to/from the stack/paca which are in SLB bolted regions
+        * until we turn MSR RI back on.
+        */
+
+       ld      r5, -8(r1)
+       ld      r1, -16(r1)
 
        /* Commit register state as checkpointed state: */
        TRECHKPT
index 2f01c4a0d8a037ca65cacd9af51022846661fcb0..7612eeb31da1483dc63dcce312a0a9ebfd113b25 100644 (file)
@@ -59,7 +59,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map)
        bl      V_LOCAL_FUNC(__get_datapage)
        mtlr    r12
        addi    r3,r3,CFG_SYSCALL_MAP64
-       cmpl  cr0,r4,0
+       cmpldi  cr0,r4,0
        crclr   cr0*4+so
        beqlr
        li      r0,__NR_syscalls
index a76b4af37ef297cdac6688785ed65d55d673bc66..3820213248836474c3db105f0a4fe2d0fad3d0d7 100644 (file)
@@ -145,7 +145,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
        bne     cr0,99f
 
        li      r3,0
-       cmpl  cr0,r4,0
+       cmpldi  cr0,r4,0
        crclr   cr0*4+so
        beqlr
        lis     r5,CLOCK_REALTIME_RES@h
index 2afdb9c0937dbd3b7471b88d75e17ca714bba1ae..729f8faa95c5794d270f4edffe375bdcf934a4da 100644 (file)
@@ -498,6 +498,7 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
        case SPRN_MMCR0:
        case SPRN_MMCR1:
        case SPRN_MMCR2:
+       case SPRN_UMMCR2:
 #endif
                break;
 unprivileged:
@@ -640,6 +641,7 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
        case SPRN_MMCR0:
        case SPRN_MMCR1:
        case SPRN_MMCR2:
+       case SPRN_UMMCR2:
        case SPRN_TIR:
 #endif
                *spr_val = 0;
index 463af88c95a28f225a4166bad0ff1278eb8487a6..974f73df00bbf1533458ad3e713cacd5349c78fb 100644 (file)
@@ -655,112 +655,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 BEGIN_FTR_SECTION
-       b       skip_tm
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-
-       /* Turn on TM/FP/VSX/VMX so we can restore them. */
-       mfmsr   r5
-       li      r6, MSR_TM >> 32
-       sldi    r6, r6, 32
-       or      r5, r5, r6
-       ori     r5, r5, MSR_FP
-       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
-       mtmsrd  r5
-
-       /*
-        * The user may change these outside of a transaction, so they must
-        * always be context switched.
-        */
-       ld      r5, VCPU_TFHAR(r4)
-       ld      r6, VCPU_TFIAR(r4)
-       ld      r7, VCPU_TEXASR(r4)
-       mtspr   SPRN_TFHAR, r5
-       mtspr   SPRN_TFIAR, r6
-       mtspr   SPRN_TEXASR, r7
-
-       ld      r5, VCPU_MSR(r4)
-       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-       beq     skip_tm /* TM not active in guest */
-
-       /* Make sure the failure summary is set, otherwise we'll program check
-        * when we trechkpt.  It's possible that this might have been not set
-        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
-        * host.
-        */
-       oris    r7, r7, (TEXASR_FS)@h
-       mtspr   SPRN_TEXASR, r7
-
-       /*
-        * We need to load up the checkpointed state for the guest.
-        * We need to do this early as it will blow away any GPRs, VSRs and
-        * some SPRs.
-        */
-
-       mr      r31, r4
-       addi    r3, r31, VCPU_FPRS_TM
-       bl      load_fp_state
-       addi    r3, r31, VCPU_VRS_TM
-       bl      load_vr_state
-       mr      r4, r31
-       lwz     r7, VCPU_VRSAVE_TM(r4)
-       mtspr   SPRN_VRSAVE, r7
-
-       ld      r5, VCPU_LR_TM(r4)
-       lwz     r6, VCPU_CR_TM(r4)
-       ld      r7, VCPU_CTR_TM(r4)
-       ld      r8, VCPU_AMR_TM(r4)
-       ld      r9, VCPU_TAR_TM(r4)
-       mtlr    r5
-       mtcr    r6
-       mtctr   r7
-       mtspr   SPRN_AMR, r8
-       mtspr   SPRN_TAR, r9
-
-       /*
-        * Load up PPR and DSCR values but don't put them in the actual SPRs
-        * till the last moment to avoid running with userspace PPR and DSCR for
-        * too long.
-        */
-       ld      r29, VCPU_DSCR_TM(r4)
-       ld      r30, VCPU_PPR_TM(r4)
-
-       std     r2, PACATMSCRATCH(r13) /* Save TOC */
-
-       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
-       li      r5, 0
-       mtmsrd  r5, 1
-
-       /* Load GPRs r0-r28 */
-       reg = 0
-       .rept   29
-       ld      reg, VCPU_GPRS_TM(reg)(r31)
-       reg = reg + 1
-       .endr
-
-       mtspr   SPRN_DSCR, r29
-       mtspr   SPRN_PPR, r30
-
-       /* Load final GPRs */
-       ld      29, VCPU_GPRS_TM(29)(r31)
-       ld      30, VCPU_GPRS_TM(30)(r31)
-       ld      31, VCPU_GPRS_TM(31)(r31)
-
-       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
-       TRECHKPT
-
-       /* Now let's get back the state we need. */
-       HMT_MEDIUM
-       GET_PACA(r13)
-       ld      r29, HSTATE_DSCR(r13)
-       mtspr   SPRN_DSCR, r29
-       ld      r4, HSTATE_KVM_VCPU(r13)
-       ld      r1, HSTATE_HOST_R1(r13)
-       ld      r2, PACATMSCRATCH(r13)
-
-       /* Set the MSR RI since we have our registers back. */
-       li      r5, MSR_RI
-       mtmsrd  r5, 1
-skip_tm:
+       bl      kvmppc_restore_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
 
        /* Load guest PMU registers */
@@ -841,12 +737,6 @@ BEGIN_FTR_SECTION
        /* Skip next section on POWER7 */
        b       8f
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
        /* Load up POWER8-specific registers */
        ld      r5, VCPU_IAMR(r4)
        lwz     r6, VCPU_PSPB(r4)
@@ -1436,106 +1326,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 BEGIN_FTR_SECTION
-       b       2f
-END_FTR_SECTION_IFCLR(CPU_FTR_TM)
-       /* Turn on TM. */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
-       ld      r5, VCPU_MSR(r9)
-       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-       beq     1f      /* TM not active in guest. */
-
-       li      r3, TM_CAUSE_KVM_RESCHED
-
-       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
-       li      r5, 0
-       mtmsrd  r5, 1
-
-       /* All GPRs are volatile at this point. */
-       TRECLAIM(R3)
-
-       /* Temporarily store r13 and r9 so we have some regs to play with */
-       SET_SCRATCH0(r13)
-       GET_PACA(r13)
-       std     r9, PACATMSCRATCH(r13)
-       ld      r9, HSTATE_KVM_VCPU(r13)
-
-       /* Get a few more GPRs free. */
-       std     r29, VCPU_GPRS_TM(29)(r9)
-       std     r30, VCPU_GPRS_TM(30)(r9)
-       std     r31, VCPU_GPRS_TM(31)(r9)
-
-       /* Save away PPR and DSCR soon so don't run with user values. */
-       mfspr   r31, SPRN_PPR
-       HMT_MEDIUM
-       mfspr   r30, SPRN_DSCR
-       ld      r29, HSTATE_DSCR(r13)
-       mtspr   SPRN_DSCR, r29
-
-       /* Save all but r9, r13 & r29-r31 */
-       reg = 0
-       .rept   29
-       .if (reg != 9) && (reg != 13)
-       std     reg, VCPU_GPRS_TM(reg)(r9)
-       .endif
-       reg = reg + 1
-       .endr
-       /* ... now save r13 */
-       GET_SCRATCH0(r4)
-       std     r4, VCPU_GPRS_TM(13)(r9)
-       /* ... and save r9 */
-       ld      r4, PACATMSCRATCH(r13)
-       std     r4, VCPU_GPRS_TM(9)(r9)
-
-       /* Reload stack pointer and TOC. */
-       ld      r1, HSTATE_HOST_R1(r13)
-       ld      r2, PACATOC(r13)
-
-       /* Set MSR RI now we have r1 and r13 back. */
-       li      r5, MSR_RI
-       mtmsrd  r5, 1
-
-       /* Save away checkpinted SPRs. */
-       std     r31, VCPU_PPR_TM(r9)
-       std     r30, VCPU_DSCR_TM(r9)
-       mflr    r5
-       mfcr    r6
-       mfctr   r7
-       mfspr   r8, SPRN_AMR
-       mfspr   r10, SPRN_TAR
-       std     r5, VCPU_LR_TM(r9)
-       stw     r6, VCPU_CR_TM(r9)
-       std     r7, VCPU_CTR_TM(r9)
-       std     r8, VCPU_AMR_TM(r9)
-       std     r10, VCPU_TAR_TM(r9)
-
-       /* Restore r12 as trap number. */
-       lwz     r12, VCPU_TRAP(r9)
-
-       /* Save FP/VSX. */
-       addi    r3, r9, VCPU_FPRS_TM
-       bl      store_fp_state
-       addi    r3, r9, VCPU_VRS_TM
-       bl      store_vr_state
-       mfspr   r6, SPRN_VRSAVE
-       stw     r6, VCPU_VRSAVE_TM(r9)
-1:
-       /*
-        * We need to save these SPRs after the treclaim so that the software
-        * error code is recorded correctly in the TEXASR.  Also the user may
-        * change these outside of a transaction, so they must always be
-        * context switched.
-        */
-       mfspr   r5, SPRN_TFHAR
-       mfspr   r6, SPRN_TFIAR
-       mfspr   r7, SPRN_TEXASR
-       std     r5, VCPU_TFHAR(r9)
-       std     r6, VCPU_TFIAR(r9)
-       std     r7, VCPU_TEXASR(r9)
-2:
+       bl      kvmppc_save_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
 #endif
 
        /* Increment yield count if they have a VPA */
@@ -2245,6 +2037,13 @@ _GLOBAL(kvmppc_h_cede)           /* r3 = vcpu pointer, r11 = msr, r13 = paca */
        /* save FP state */
        bl      kvmppc_save_fp
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+       ld      r9, HSTATE_KVM_VCPU(r13)
+       bl      kvmppc_save_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+
        /*
         * Set DEC to the smaller of DEC and HDEC, so that we wake
         * no later than the end of our timeslice (HDEC interrupts
@@ -2321,6 +2120,12 @@ kvm_end_cede:
        bl      kvmhv_accumulate_time
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+       bl      kvmppc_restore_tm
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+
        /* load up FP state */
        bl      kvmppc_load_fp
 
@@ -2629,6 +2434,239 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        mr      r4,r31
        blr
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Save transactional state and TM-related registers.
+ * Called with r9 pointing to the vcpu struct.
+ * This can modify all checkpointed registers, but
+ * restores r1, r2 and r9 (vcpu pointer) before exit.
+ */
+kvmppc_save_tm:
+       mflr    r0
+       std     r0, PPC_LR_STKOFF(r1)
+
+       /* Turn on TM. */
+       mfmsr   r8
+       li      r0, 1
+       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+       mtmsrd  r8
+
+       ld      r5, VCPU_MSR(r9)
+       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       beq     1f      /* TM not active in guest. */
+
+       std     r1, HSTATE_HOST_R1(r13)
+       li      r3, TM_CAUSE_KVM_RESCHED
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /* All GPRs are volatile at this point. */
+       TRECLAIM(R3)
+
+       /* Temporarily store r13 and r9 so we have some regs to play with */
+       SET_SCRATCH0(r13)
+       GET_PACA(r13)
+       std     r9, PACATMSCRATCH(r13)
+       ld      r9, HSTATE_KVM_VCPU(r13)
+
+       /* Get a few more GPRs free. */
+       std     r29, VCPU_GPRS_TM(29)(r9)
+       std     r30, VCPU_GPRS_TM(30)(r9)
+       std     r31, VCPU_GPRS_TM(31)(r9)
+
+       /* Save away PPR and DSCR soon so don't run with user values. */
+       mfspr   r31, SPRN_PPR
+       HMT_MEDIUM
+       mfspr   r30, SPRN_DSCR
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+
+       /* Save all but r9, r13 & r29-r31 */
+       reg = 0
+       .rept   29
+       .if (reg != 9) && (reg != 13)
+       std     reg, VCPU_GPRS_TM(reg)(r9)
+       .endif
+       reg = reg + 1
+       .endr
+       /* ... now save r13 */
+       GET_SCRATCH0(r4)
+       std     r4, VCPU_GPRS_TM(13)(r9)
+       /* ... and save r9 */
+       ld      r4, PACATMSCRATCH(r13)
+       std     r4, VCPU_GPRS_TM(9)(r9)
+
+       /* Reload stack pointer and TOC. */
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r2, PACATOC(r13)
+
+       /* Set MSR RI now we have r1 and r13 back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+
+       /* Save away checkpinted SPRs. */
+       std     r31, VCPU_PPR_TM(r9)
+       std     r30, VCPU_DSCR_TM(r9)
+       mflr    r5
+       mfcr    r6
+       mfctr   r7
+       mfspr   r8, SPRN_AMR
+       mfspr   r10, SPRN_TAR
+       std     r5, VCPU_LR_TM(r9)
+       stw     r6, VCPU_CR_TM(r9)
+       std     r7, VCPU_CTR_TM(r9)
+       std     r8, VCPU_AMR_TM(r9)
+       std     r10, VCPU_TAR_TM(r9)
+
+       /* Restore r12 as trap number. */
+       lwz     r12, VCPU_TRAP(r9)
+
+       /* Save FP/VSX. */
+       addi    r3, r9, VCPU_FPRS_TM
+       bl      store_fp_state
+       addi    r3, r9, VCPU_VRS_TM
+       bl      store_vr_state
+       mfspr   r6, SPRN_VRSAVE
+       stw     r6, VCPU_VRSAVE_TM(r9)
+1:
+       /*
+        * We need to save these SPRs after the treclaim so that the software
+        * error code is recorded correctly in the TEXASR.  Also the user may
+        * change these outside of a transaction, so they must always be
+        * context switched.
+        */
+       mfspr   r5, SPRN_TFHAR
+       mfspr   r6, SPRN_TFIAR
+       mfspr   r7, SPRN_TEXASR
+       std     r5, VCPU_TFHAR(r9)
+       std     r6, VCPU_TFIAR(r9)
+       std     r7, VCPU_TEXASR(r9)
+
+       ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+
+/*
+ * Restore transactional state and TM-related registers.
+ * Called with r4 pointing to the vcpu struct.
+ * This potentially modifies all checkpointed registers.
+ * It restores r1, r2, r4 from the PACA.
+ */
+kvmppc_restore_tm:
+       mflr    r0
+       std     r0, PPC_LR_STKOFF(r1)
+
+       /* Turn on TM/FP/VSX/VMX so we can restore them. */
+       mfmsr   r5
+       li      r6, MSR_TM >> 32
+       sldi    r6, r6, 32
+       or      r5, r5, r6
+       ori     r5, r5, MSR_FP
+       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
+       mtmsrd  r5
+
+       /*
+        * The user may change these outside of a transaction, so they must
+        * always be context switched.
+        */
+       ld      r5, VCPU_TFHAR(r4)
+       ld      r6, VCPU_TFIAR(r4)
+       ld      r7, VCPU_TEXASR(r4)
+       mtspr   SPRN_TFHAR, r5
+       mtspr   SPRN_TFIAR, r6
+       mtspr   SPRN_TEXASR, r7
+
+       ld      r5, VCPU_MSR(r4)
+       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       beqlr           /* TM not active in guest */
+       std     r1, HSTATE_HOST_R1(r13)
+
+       /* Make sure the failure summary is set, otherwise we'll program check
+        * when we trechkpt.  It's possible that this might have been not set
+        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+        * host.
+        */
+       oris    r7, r7, (TEXASR_FS)@h
+       mtspr   SPRN_TEXASR, r7
+
+       /*
+        * We need to load up the checkpointed state for the guest.
+        * We need to do this early as it will blow away any GPRs, VSRs and
+        * some SPRs.
+        */
+
+       mr      r31, r4
+       addi    r3, r31, VCPU_FPRS_TM
+       bl      load_fp_state
+       addi    r3, r31, VCPU_VRS_TM
+       bl      load_vr_state
+       mr      r4, r31
+       lwz     r7, VCPU_VRSAVE_TM(r4)
+       mtspr   SPRN_VRSAVE, r7
+
+       ld      r5, VCPU_LR_TM(r4)
+       lwz     r6, VCPU_CR_TM(r4)
+       ld      r7, VCPU_CTR_TM(r4)
+       ld      r8, VCPU_AMR_TM(r4)
+       ld      r9, VCPU_TAR_TM(r4)
+       mtlr    r5
+       mtcr    r6
+       mtctr   r7
+       mtspr   SPRN_AMR, r8
+       mtspr   SPRN_TAR, r9
+
+       /*
+        * Load up PPR and DSCR values but don't put them in the actual SPRs
+        * till the last moment to avoid running with userspace PPR and DSCR for
+        * too long.
+        */
+       ld      r29, VCPU_DSCR_TM(r4)
+       ld      r30, VCPU_PPR_TM(r4)
+
+       std     r2, PACATMSCRATCH(r13) /* Save TOC */
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /* Load GPRs r0-r28 */
+       reg = 0
+       .rept   29
+       ld      reg, VCPU_GPRS_TM(reg)(r31)
+       reg = reg + 1
+       .endr
+
+       mtspr   SPRN_DSCR, r29
+       mtspr   SPRN_PPR, r30
+
+       /* Load final GPRs */
+       ld      29, VCPU_GPRS_TM(29)(r31)
+       ld      30, VCPU_GPRS_TM(30)(r31)
+       ld      31, VCPU_GPRS_TM(31)(r31)
+
+       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
+       TRECHKPT
+
+       /* Now let's get back the state we need. */
+       HMT_MEDIUM
+       GET_PACA(r13)
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+       ld      r4, HSTATE_KVM_VCPU(r13)
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r2, PACATMSCRATCH(r13)
+
+       /* Set the MSR RI since we have our registers back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+
+       ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+#endif
+
 /*
  * We come here if we get any exception or interrupt while we are
  * executing host real mode code while in guest MMU context.
index fd5875179e5c0e6738a1e7867a75f05cbe1fa0c8..6d63cd67b09b689a9cc2322613bfcadf74bafd3d 100644 (file)
@@ -2033,7 +2033,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
                if (type == KVMPPC_DEBUG_NONE)
                        continue;
 
-               if (type & !(KVMPPC_DEBUG_WATCH_READ |
+               if (type & ~(KVMPPC_DEBUG_WATCH_READ |
                             KVMPPC_DEBUG_WATCH_WRITE |
                             KVMPPC_DEBUG_BREAKPOINT))
                        return -EINVAL;
index f09899e35991711d0a57e74519af662b59e59f15..7b22624f332ce5e45dc5337d2d97b0c31c36a764 100644 (file)
@@ -359,6 +359,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
        addi    r3,r3,8
 171:
 177:
+179:
        addi    r3,r3,8
 370:
 372:
@@ -373,7 +374,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 173:
 174:
 175:
-179:
 181:
 184:
 186:
index 6527882ce05ede3a0a45f74d3a11c4c375da6514..ddfd2740a1b5d3cd643207fd5250a3515e810987 100644 (file)
@@ -106,6 +106,8 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
        switch (REGION_ID(ea)) {
        case USER_REGION_ID:
                pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
+               if (mm == NULL)
+                       return 1;
                psize = get_slice_psize(mm, ea);
                ssize = user_segment_size(ea);
                vsid = get_vsid(mm->context.id, ea, ssize);
index 736d18b3cefd3bd16e2d9ab7c34b56bb7f5e8a61..4c48b487698cf4208618647d8038cc1a9d72e3aa 100644 (file)
@@ -113,7 +113,12 @@ BEGIN_FTR_SECTION
 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
        b       slb_finish_load_1T
 
-0:
+0:     /*
+        * For userspace addresses, make sure this is region 0.
+        */
+       cmpdi   r9, 0
+       bne     8f
+
        /* when using slices, we extract the psize off the slice bitmaps
         * and then we need to get the sllp encoding off the mmu_psize_defs
         * array.
index 2ba602591a20412c95cd470c5b6fb129872c3f94..92736851c795afac23926700014a72ac0e6c44d1 100644 (file)
@@ -956,6 +956,11 @@ static int pnv_eeh_reset(struct eeh_pe *pe, int option)
                }
 
                bus = eeh_pe_bus_get(pe);
+               if (!bus) {
+                       pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n",
+                              __func__, pe->phb->global_number, pe->addr);
+                       return -EIO;
+               }
                if (pci_is_root_bus(bus) ||
                        pci_is_root_bus(bus->parent))
                        ret = pnv_eeh_root_reset(hose, option);
@@ -1163,7 +1168,7 @@ static void pnv_eeh_get_and_dump_hub_diag(struct pci_controller *hose)
                return;
        }
 
-       switch (data->type) {
+       switch (be16_to_cpu(data->type)) {
        case OPAL_P7IOC_DIAG_TYPE_RGC:
                pr_info("P7IOC diag-data for RGC\n\n");
                pnv_eeh_dump_hub_diag_common(data);
@@ -1395,7 +1400,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
 
                                /* Try best to clear it */
                                opal_pci_eeh_freeze_clear(phb->opal_id,
-                                       frozen_pe_no,
+                                       be64_to_cpu(frozen_pe_no),
                                        OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
                                ret = EEH_NEXT_ERR_NONE;
                        } else if ((*pe)->state & EEH_PE_ISOLATED ||
index 2ee96431f7360e1d8d63ece45520416860c62428..4c827826c05eb13b09f4e0cd9f9c73d6967ec9a9 100644 (file)
@@ -370,6 +370,7 @@ static irqreturn_t process_dump(int irq, void *data)
        uint32_t dump_id, dump_size, dump_type;
        struct dump_obj *dump;
        char name[22];
+       struct kobject *kobj;
 
        rc = dump_read_info(&dump_id, &dump_size, &dump_type);
        if (rc != OPAL_SUCCESS)
@@ -381,8 +382,12 @@ static irqreturn_t process_dump(int irq, void *data)
         * that gracefully and not create two conflicting
         * entries.
         */
-       if (kset_find_obj(dump_kset, name))
+       kobj = kset_find_obj(dump_kset, name);
+       if (kobj) {
+               /* Drop reference added by kset_find_obj() */
+               kobject_put(kobj);
                return 0;
+       }
 
        dump = create_dump_obj(dump_id, dump_size, dump_type);
        if (!dump)
index 37f959bf392e72a8a4bc7dee92181846b1383458..f2344cbd2f464cb93a3afbcbf21dc8263069b555 100644 (file)
@@ -247,6 +247,7 @@ static irqreturn_t elog_event(int irq, void *data)
        uint64_t elog_type;
        int rc;
        char name[2+16+1];
+       struct kobject *kobj;
 
        rc = opal_get_elog_size(&id, &size, &type);
        if (rc != OPAL_SUCCESS) {
@@ -269,8 +270,12 @@ static irqreturn_t elog_event(int irq, void *data)
         * that gracefully and not create two conflicting
         * entries.
         */
-       if (kset_find_obj(elog_kset, name))
+       kobj = kset_find_obj(elog_kset, name);
+       if (kobj) {
+               /* Drop reference added by kset_find_obj() */
+               kobject_put(kobj);
                return IRQ_HANDLED;
+       }
 
        create_elog_obj(log_id, elog_size, elog_type);
 
index ad8c3f4a5e0bec7a839b624ab99c5238f472f18f..dd5e0f3b1b5d00c8772003787d68ba030df53cea 100644 (file)
@@ -197,8 +197,8 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
                        be64_to_cpu(data->dma1ErrorLog1));
 
        for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
-               if ((data->pestA[i] >> 63) == 0 &&
-                   (data->pestB[i] >> 63) == 0)
+               if ((be64_to_cpu(data->pestA[i]) >> 63) == 0 &&
+                   (be64_to_cpu(data->pestB[i]) >> 63) == 0)
                        continue;
 
                pr_info("PE[%3d] A/B: %016llx %016llx\n",
index b7a67e3d2201e4d5988e9cb3df651651c12024c8..3ae43282460e34edea9f26d054b4622f9b4e69bd 100644 (file)
@@ -406,7 +406,7 @@ static void __pSeries_lpar_hugepage_invalidate(unsigned long *slot,
                                             unsigned long *vpn, int count,
                                             int psize, int ssize)
 {
-       unsigned long param[8];
+       unsigned long param[PLPAR_HCALL9_BUFSIZE];
        int i = 0, pix = 0, rc;
        unsigned long flags = 0;
        int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
@@ -523,7 +523,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
        unsigned long flags = 0;
        struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch);
        int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
-       unsigned long param[9];
+       unsigned long param[PLPAR_HCALL9_BUFSIZE];
        unsigned long hash, index, shift, hidx, slot;
        real_pte_t pte;
        int psize, ssize;
index 3a55f493c7da72b9ee7ee7ad7c8c76d9e01bed8d..60530fd93d6d11368731fedfe145afb6826c7e59 100644 (file)
@@ -117,6 +117,7 @@ config S390
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_EARLY_PFN_TO_NID
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_SOFT_DIRTY
index b8045b97f4fbd888c35783b13a2b5b9dc89f353f..d750cc0dfe301ed1dd5fa5edd8df1a6fb97cc451 100644 (file)
@@ -669,11 +669,13 @@ static const struct file_operations prng_tdes_fops = {
 static struct miscdevice prng_sha512_dev = {
        .name   = "prandom",
        .minor  = MISC_DYNAMIC_MINOR,
+       .mode   = 0644,
        .fops   = &prng_sha512_fops,
 };
 static struct miscdevice prng_tdes_dev = {
        .name   = "prandom",
        .minor  = MISC_DYNAMIC_MINOR,
+       .mode   = 0644,
        .fops   = &prng_tdes_fops,
 };
 
index 1aac41e83ea197121c5dd178c587323f9b875aa1..92df3eb8d14ef45309a30f264e760e55f0fe3a11 100644 (file)
@@ -23,6 +23,8 @@ enum zpci_ioat_dtype {
 #define ZPCI_IOTA_FS_2G                        2
 #define ZPCI_KEY                       (PAGE_DEFAULT_KEY << 5)
 
+#define ZPCI_TABLE_SIZE_RT     (1UL << 42)
+
 #define ZPCI_IOTA_STO_FLAG     (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)
 #define ZPCI_IOTA_RTTO_FLAG    (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
 #define ZPCI_IOTA_RSTO_FLAG    (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS)
index a2e6ef32e05445b190b444cb249db44f638e10d2..0a2031618f7fc619326c3d3e69f20dd71802c4dd 100644 (file)
@@ -81,7 +81,8 @@ static inline void __tlb_flush_full(struct mm_struct *mm)
 }
 
 /*
- * Flush TLB entries for a specific ASCE on all CPUs.
+ * Flush TLB entries for a specific ASCE on all CPUs. Should never be used
+ * when more than one asce (e.g. gmap) ran on this mm.
  */
 static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce)
 {
index 9dd4cc47ddc79298886fe40a5e229628b2ceff3d..5c7381c5ad7f8a93082497c2776bcb66287efe60 100644 (file)
@@ -215,28 +215,28 @@ int __put_user_bad(void) __attribute__((noreturn));
        __chk_user_ptr(ptr);                                    \
        switch (sizeof(*(ptr))) {                               \
        case 1: {                                               \
-               unsigned char __x;                              \
+               unsigned char __x = 0;                          \
                __gu_err = __get_user_fn(&__x, ptr,             \
                                         sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
        case 2: {                                               \
-               unsigned short __x;                             \
+               unsigned short __x = 0;                         \
                __gu_err = __get_user_fn(&__x, ptr,             \
                                         sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
        case 4: {                                               \
-               unsigned int __x;                               \
+               unsigned int __x = 0;                           \
                __gu_err = __get_user_fn(&__x, ptr,             \
                                         sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
                break;                                          \
        };                                                      \
        case 8: {                                               \
-               unsigned long long __x;                         \
+               unsigned long long __x = 0;                     \
                __gu_err = __get_user_fn(&__x, ptr,             \
                                         sizeof(*(ptr)));       \
                (x) = *(__force __typeof__(*(ptr)) *) &__x;     \
index b1f0a90f933bbc95cc04c9e028d87865555909a9..42570d8fb265f5580ef9fb56b9a351a3c6fa596f 100644 (file)
@@ -2070,13 +2070,6 @@ void s390_reset_system(void (*fn_pre)(void),
        S390_lowcore.program_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 
-       /*
-        * Clear subchannel ID and number to signal new kernel that no CCW or
-        * SCSI IPL has been done (for kexec and kdump)
-        */
-       S390_lowcore.subchannel_id = 0;
-       S390_lowcore.subchannel_nr = 0;
-
        /* Store status at absolute zero */
        store_status();
 
index ae4de559e3a04288c6be111de684b3355f35109b..6986c20166f028bd859fa38af033d076a93eb3f3 100644 (file)
@@ -104,6 +104,7 @@ static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
 
 unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
+       check_object_size(to, n, false);
        if (static_branch_likely(&have_mvcos))
                return copy_from_user_mvcos(to, from, n);
        return copy_from_user_mvcp(to, from, n);
@@ -177,6 +178,7 @@ static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
 
 unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
+       check_object_size(from, n, true);
        if (static_branch_likely(&have_mvcos))
                return copy_to_user_mvcos(to, from, n);
        return copy_to_user_mvcs(to, from, n);
index 471a370a527bfd9eb5e9bd03e98a9e6c7eff4b96..8345ae1f117d0cfdf4cfcadc5a01c0ec4bfd7174 100644 (file)
@@ -166,7 +166,7 @@ EXPORT_SYMBOL_GPL(gmap_alloc);
 static void gmap_flush_tlb(struct gmap *gmap)
 {
        if (MACHINE_HAS_IDTE)
-               __tlb_flush_asce(gmap->mm, gmap->asce);
+               __tlb_flush_idte(gmap->asce);
        else
                __tlb_flush_global();
 }
@@ -205,7 +205,7 @@ void gmap_free(struct gmap *gmap)
 
        /* Flush tlb. */
        if (MACHINE_HAS_IDTE)
-               __tlb_flush_asce(gmap->mm, gmap->asce);
+               __tlb_flush_idte(gmap->asce);
        else
                __tlb_flush_global();
 
index 19442395f413b061c36ed848c0962c09624b7282..f2f6720a3331d3005882e73c57ae1e71c32b83b1 100644 (file)
@@ -701,8 +701,7 @@ static int zpci_restore(struct device *dev)
                goto out;
 
        zpci_map_resources(pdev);
-       zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
-                          zdev->start_dma + zdev->iommu_size - 1,
+       zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
                           (u64) zdev->dma_table);
 
 out:
index d348f2c09a1eede659378cf4ae2686df008e4bd8..3a40f718baefd23b7626555d69babc4fe5c0a6f6 100644 (file)
@@ -458,7 +458,19 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
                goto out_clean;
        }
 
-       zdev->iommu_size = (unsigned long) high_memory - PAGE_OFFSET;
+       /*
+        * Restrict the iommu bitmap size to the minimum of the following:
+        * - main memory size
+        * - 3-level pagetable address limit minus start_dma offset
+        * - DMA address range allowed by the hardware (clp query pci fn)
+        *
+        * Also set zdev->end_dma to the actual end address of the usable
+        * range, instead of the theoretical maximum as reported by hardware.
+        */
+       zdev->iommu_size = min3((u64) high_memory,
+                               ZPCI_TABLE_SIZE_RT - zdev->start_dma,
+                               zdev->end_dma - zdev->start_dma + 1);
+       zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
        zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
        zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
        if (!zdev->iommu_bitmap) {
@@ -466,10 +478,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
                goto out_reg;
        }
 
-       rc = zpci_register_ioat(zdev,
-                               0,
-                               zdev->start_dma + PAGE_OFFSET,
-                               zdev->start_dma + zdev->iommu_size - 1,
+       rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
                                (u64) zdev->dma_table);
        if (rc)
                goto out_reg;
index 20a3591225ccea9aa3d93acc11a97a34bf254501..01aec8ccde834119b0cf893c6d8ff4b81a41cb20 100644 (file)
@@ -163,7 +163,7 @@ do {                                                                        \
                __get_user_asm(val, "lw", ptr);                         \
                 break;                                                 \
        case 8:                                                         \
-               if ((copy_from_user((void *)&val, ptr, 8)) == 0)        \
+               if (__copy_from_user((void *)&val, ptr, 8) == 0)        \
                        __gu_err = 0;                                   \
                else                                                    \
                        __gu_err = -EFAULT;                             \
@@ -188,6 +188,8 @@ do {                                                                        \
                                                                        \
        if (likely(access_ok(VERIFY_READ, __gu_ptr, size)))             \
                __get_user_common((x), size, __gu_ptr);                 \
+       else                                                            \
+               (x) = 0;                                                \
                                                                        \
        __gu_err;                                                       \
 })
@@ -201,6 +203,7 @@ do {                                                                        \
                "2:\n"                                                  \
                ".section .fixup,\"ax\"\n"                              \
                "3:li   %0, %4\n"                                       \
+               "li     %1, 0\n"                                        \
                "j      2b\n"                                           \
                ".previous\n"                                           \
                ".section __ex_table,\"a\"\n"                           \
@@ -298,35 +301,34 @@ extern int __copy_tofrom_user(void *to, const void *from, unsigned long len);
 static inline unsigned long
 copy_from_user(void *to, const void *from, unsigned long len)
 {
-       unsigned long over;
+       unsigned long res = len;
 
-       if (access_ok(VERIFY_READ, from, len))
-               return __copy_tofrom_user(to, from, len);
+       if (likely(access_ok(VERIFY_READ, from, len)))
+               res = __copy_tofrom_user(to, from, len);
 
-       if ((unsigned long)from < TASK_SIZE) {
-               over = (unsigned long)from + len - TASK_SIZE;
-               return __copy_tofrom_user(to, from, len - over) + over;
-       }
-       return len;
+       if (unlikely(res))
+               memset(to + (len - res), 0, res);
+
+       return res;
 }
 
 static inline unsigned long
 copy_to_user(void *to, const void *from, unsigned long len)
 {
-       unsigned long over;
-
-       if (access_ok(VERIFY_WRITE, to, len))
-               return __copy_tofrom_user(to, from, len);
+       if (likely(access_ok(VERIFY_WRITE, to, len)))
+               len = __copy_tofrom_user(to, from, len);
 
-       if ((unsigned long)to < TASK_SIZE) {
-               over = (unsigned long)to + len - TASK_SIZE;
-               return __copy_tofrom_user(to, from, len - over) + over;
-       }
        return len;
 }
 
-#define __copy_from_user(to, from, len)        \
-               __copy_tofrom_user((to), (from), (len))
+static inline unsigned long
+__copy_from_user(void *to, const void *from, unsigned long len)
+{
+       unsigned long left = __copy_tofrom_user(to, from, len);
+       if (unlikely(left))
+               memset(to + (len - left), 0, left);
+       return left;
+}
 
 #define __copy_to_user(to, from, len)          \
                __copy_tofrom_user((to), (from), (len))
@@ -340,17 +342,17 @@ __copy_to_user_inatomic(void *to, const void *from, unsigned long len)
 static inline unsigned long
 __copy_from_user_inatomic(void *to, const void *from, unsigned long len)
 {
-       return __copy_from_user(to, from, len);
+       return __copy_tofrom_user(to, from, len);
 }
 
-#define __copy_in_user(to, from, len)  __copy_from_user(to, from, len)
+#define __copy_in_user(to, from, len)  __copy_tofrom_user(to, from, len)
 
 static inline unsigned long
 copy_in_user(void *to, const void *from, unsigned long len)
 {
        if (access_ok(VERIFY_READ, from, len) &&
                      access_ok(VERFITY_WRITE, to, len))
-               return copy_from_user(to, from, len);
+               return __copy_tofrom_user(to, from, len);
 }
 
 /*
index a49635c512665ddc6b9e70e5d944c57e26d349d6..92ade79ac4272ea22657b3aac6adfb90b1d4105f 100644 (file)
@@ -151,7 +151,10 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
        __kernel_size_t __copy_size = (__kernel_size_t) n;
 
        if (__copy_size && __access_ok(__copy_from, __copy_size))
-               return __copy_user(to, from, __copy_size);
+               __copy_size = __copy_user(to, from, __copy_size);
+
+       if (unlikely(__copy_size))
+               memset(to + (n - __copy_size), 0, __copy_size);
 
        return __copy_size;
 }
index c01376c76b868727b55bd117551cc1b96b93d8f1..ca5073dd459674d1ad835406fc46baa1957d01ac 100644 (file)
@@ -24,6 +24,7 @@
 #define __get_user_size(x,ptr,size,retval)                     \
 do {                                                           \
        retval = 0;                                             \
+       x = 0;                                                  \
        switch (size) {                                         \
        case 1:                                                 \
                retval = __get_user_asm_b((void *)&x,           \
index 56442d2d7bbca4181e8897bfa5d9719dbded43d1..3736be630113b4e1ae8fd26ff45cff32d03d47a9 100644 (file)
@@ -43,6 +43,7 @@ config SPARC
        select ODD_RT_SIGACTION
        select OLD_SIGSUSPEND
        select ARCH_HAS_SG_CHAIN
+       select HAVE_ARCH_HARDENED_USERCOPY
 
 config SPARC32
        def_bool !64BIT
index 64ee103dc29da142305d93d26fd44cf4a62ae699..e7d6bb4cd619b362aa8fd84c71ecc3d7a18b9eb3 100644 (file)
@@ -313,23 +313,28 @@ unsigned long __copy_user(void __user *to, const void __user *from, unsigned lon
 
 static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       if (n && __access_ok((unsigned long) to, n))
+       if (n && __access_ok((unsigned long) to, n)) {
+               check_object_size(from, n, true);
                return __copy_user(to, (__force void __user *) from, n);
-       else
+       else
                return n;
 }
 
 static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
+       check_object_size(from, n, true);
        return __copy_user(to, (__force void __user *) from, n);
 }
 
 static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       if (n && __access_ok((unsigned long) from, n))
+       if (n && __access_ok((unsigned long) from, n)) {
+               check_object_size(to, n, false);
                return __copy_user((__force void __user *) to, from, n);
-       else
+       else {
+               memset(to, 0, n);
                return n;
+       }
 }
 
 static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
index ea6e9a20f3ffb5a80156b1766ac2112c3c0d2bdc..9c2b93bcb631b4262e7974286483a0c2b0ae3b06 100644 (file)
@@ -250,8 +250,11 @@ unsigned long copy_from_user_fixup(void *to, const void __user *from,
 static inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long size)
 {
-       unsigned long ret = ___copy_from_user(to, from, size);
+       unsigned long ret;
 
+       check_object_size(to, size, false);
+
+       ret = ___copy_from_user(to, from, size);
        if (unlikely(ret))
                ret = copy_from_user_fixup(to, from, size);
 
@@ -267,8 +270,11 @@ unsigned long copy_to_user_fixup(void __user *to, const void *from,
 static inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long size)
 {
-       unsigned long ret = ___copy_to_user(to, from, size);
+       unsigned long ret;
+
+       check_object_size(from, size, true);
 
+       ret = ___copy_to_user(to, from, size);
        if (unlikely(ret))
                ret = copy_to_user_fixup(to, from, size);
        return ret;
index c505d77e4d06a8293eda3f7ce2c88a80fb32840f..e9d54a06736f63aaa6bc9e789d773d8d786204e0 100644 (file)
@@ -129,6 +129,7 @@ extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
 struct linux_binprm;
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
                                       int executable_stack);
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
 #define ARCH_DLINFO \
 do { \
        NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \
index c93e92709f14326d278afe9cabc4de6f5d7b9381..f497123ed980c436c4480b9f3f5b03d13ce35ea3 100644 (file)
@@ -18,4 +18,6 @@
 /* The vDSO location. */
 #define AT_SYSINFO_EHDR         33
 
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
 #endif /* _ASM_TILE_AUXVEC_H */
index 1dd5bd8a8c599360ae1626b66010c1a18b12145b..133055311dce1c1ea0d4e2ae26195cc7da4c5647 100644 (file)
@@ -81,7 +81,7 @@
   .altinstr_replacement : { *(.altinstr_replacement) }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
-  .exit.text : { *(.exit.text) }
+  .exit.text : { EXIT_TEXT }
   .exit.data : { *(.exit.data) }
 
   .preinit_array : {
index d95759ac048303cea010701e0d81e6e49ef6b713..68143221db3023ee14e3a7bc1dde4e8d6812a634 100644 (file)
@@ -79,6 +79,7 @@ config X86
        select HAVE_ALIGNED_STRUCT_PAGE         if SLUB
        select HAVE_AOUT                        if X86_32
        select HAVE_ARCH_AUDITSYSCALL
+       select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_ARCH_HUGE_VMAP              if X86_64 || X86_PAE
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KASAN                  if X86_64 && SPARSEMEM_VMEMMAP
@@ -88,7 +89,7 @@ config X86
        select HAVE_ARCH_SOFT_DIRTY             if X86_64
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
-       select HAVE_BPF_JIT                     if X86_64
+       select HAVE_ARCH_WITHIN_STACK_FRAMES
        select HAVE_CC_STACKPROTECTOR
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
index 0a291cdfaf77100117baf53b2e3af75a43a8af4c..efa6073ffa7e44b1693818f603a8fcd32841e636 100644 (file)
@@ -22,7 +22,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
        vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
-KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
+KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC)
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 cflags-$(CONFIG_X86_32) := -march=i386
 cflags-$(CONFIG_X86_64) := -mcmodel=small
@@ -35,6 +35,18 @@ KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
+ifeq ($(CONFIG_RELOCATABLE),y)
+# If kernel is relocatable, build compressed kernel as PIE.
+ifeq ($(CONFIG_X86_32),y)
+LDFLAGS += $(call ld-option, -pie) $(call ld-option, --no-dynamic-linker)
+else
+# To build 64-bit compressed kernel as PIE, we disable relocation
+# overflow check to avoid relocation overflow error with a new linker
+# command-line option, -z noreloc-overflow.
+LDFLAGS += $(shell $(LD) --help 2>&1 | grep -q "\-z noreloc-overflow" \
+       && echo "-z noreloc-overflow -pie --no-dynamic-linker")
+endif
+endif
 LDFLAGS_vmlinux := -T
 
 hostprogs-y    := mkpiggy
index 8ef964ddc18ec656b1e3b0f038adf134484dbdd2..0256064da8da38c69098cbccc75a19cc0493ca82 100644 (file)
 #include <asm/asm-offsets.h>
 #include <asm/bootparam.h>
 
+/*
+ * The 32-bit x86 assembler in binutils 2.26 will generate R_386_GOT32X
+ * relocation to get the symbol address in PIC.  When the compressed x86
+ * kernel isn't built as PIC, the linker optimizes R_386_GOT32X
+ * relocations to their fixed symbol addresses.  However, when the
+ * compressed x86 kernel is loaded at a different address, it leads
+ * to the following load failure:
+ *
+ *   Failed to allocate space for phdrs
+ *
+ * during the decompression stage.
+ *
+ * If the compressed x86 kernel is relocatable at run-time, it should be
+ * compiled with -fPIE, instead of -fPIC, if possible and should be built as
+ * Position Independent Executable (PIE) so that linker won't optimize
+ * R_386_GOT32X relocation to its fixed symbol address.  Older
+ * linkers generate R_386_32 relocations against locally defined symbols,
+ * _bss, _ebss, _got and _egot, in PIE.  It isn't wrong, just less
+ * optimal than R_386_RELATIVE.  But the x86 kernel fails to properly handle
+ * R_386_32 relocations when relocating the kernel.  To generate
+ * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as
+ * hidden:
+ */
+       .hidden _bss
+       .hidden _ebss
+       .hidden _got
+       .hidden _egot
+
        __HEAD
 ENTRY(startup_32)
 #ifdef CONFIG_EFI_STUB
index b0c0d16ef58d1099342c97aff83767dd35c73691..86558a1991393c509bc3005c021c2ab490b26b2a 100644 (file)
 #include <asm/asm-offsets.h>
 #include <asm/bootparam.h>
 
+/*
+ * Locally defined symbols should be marked hidden:
+ */
+       .hidden _bss
+       .hidden _ebss
+       .hidden _got
+       .hidden _egot
+
        __HEAD
        .code32
 ENTRY(startup_32)
index 4e2ecfa23c15978faf88416ad11ca859e1201718..4b429df40d7a2fb9ee9fce2eb5315b592d1200e9 100644 (file)
@@ -1 +1,3 @@
 CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
index f17705e1332cc3b81dc9a3a7551ece5d1848d5db..e62f4401e79284b9d4589d1c2e02ca3e2ce25a21 100644 (file)
 # 285 sys_setaltroot
 286    i386    add_key                 sys_add_key
 287    i386    request_key             sys_request_key
-288    i386    keyctl                  sys_keyctl
+288    i386    keyctl                  sys_keyctl                      compat_sys_keyctl
 289    i386    ioprio_set              sys_ioprio_set
 290    i386    ioprio_get              sys_ioprio_get
 291    i386    inotify_init            sys_inotify_init
index b94f6f64e23d0cf7e630c190fe48518b47e819ed..dbff1456d2152a6993ba5f381f6a7ef838b52f28 100644 (file)
@@ -24,6 +24,7 @@
 #define _ASM_X86_MTRR_H
 
 #include <uapi/asm/mtrr.h>
+#include <asm/pat.h>
 
 
 /*
@@ -83,9 +84,12 @@ static inline int mtrr_trim_uncached_memory(unsigned long end_pfn)
 static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
 {
 }
+static inline void mtrr_bp_init(void)
+{
+       pat_disable("MTRRs disabled, skipping PAT initialization too.");
+}
 
 #define mtrr_ap_init() do {} while (0)
-#define mtrr_bp_init() do {} while (0)
 #define set_mtrr_aps_delayed_init() do {} while (0)
 #define mtrr_aps_init() do {} while (0)
 #define mtrr_bp_restore() do {} while (0)
index ca6c228d5e62837be88984b652bb436949295d03..0b1ff4c1c14e782c0375027ce99cab09e96a04fb 100644 (file)
@@ -5,8 +5,8 @@
 #include <asm/pgtable_types.h>
 
 bool pat_enabled(void);
+void pat_disable(const char *reason);
 extern void pat_init(void);
-void pat_init_cache_modes(u64);
 
 extern int reserve_memtype(u64 start, u64 end,
                enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm);
index 7a6bed5c08bc3cc266dcc7c24e71863f684d2630..baad72e4c1000d0387ca076c57a9645bcbbf189d 100644 (file)
@@ -76,6 +76,8 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
        u8 ret_flags;
 
        version = src->version;
+       /* Make the latest version visible */
+       smp_rmb();
 
        offset = pvclock_get_nsec_offset(src);
        ret = src->system_time + offset;
index c7b551028740f18a5360070a6ccb5dc9ad714c5e..0c977fc124a77b7a766cce85de4c9e130d699689 100644 (file)
@@ -177,6 +177,50 @@ static inline unsigned long current_stack_pointer(void)
        return sp;
 }
 
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *              1 if within a frame
+ *             -1 if placed across a frame boundary (or outside stack)
+ *              0 unable to determine (no frame pointers, etc)
+ */
+static inline int arch_within_stack_frames(const void * const stack,
+                                          const void * const stackend,
+                                          const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+       const void *frame = NULL;
+       const void *oldframe;
+
+       oldframe = __builtin_frame_address(1);
+       if (oldframe)
+               frame = __builtin_frame_address(2);
+       /*
+        * low ----------------------------------------------> high
+        * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+        *                     ^----------------^
+        *               allow copies only within here
+        */
+       while (stack <= frame && frame < stackend) {
+               /*
+                * If obj + len extends past the last frame, this
+                * check won't pass and the next frame will be 0,
+                * causing us to bail out and correctly report
+                * the copy as invalid.
+                */
+               if (obj + len <= frame)
+                       return obj >= oldframe + 2 * sizeof(void *) ? 1 : -1;
+               oldframe = frame;
+               frame = *(const void * const *)frame;
+       }
+       return -1;
+#else
+       return 0;
+#endif
+}
+
 #else /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_X86_64
index 6df2029405a3ae55df8b9718dd320b55dde5c1ad..6433e28dc9c89c8d4c8f826c86212a957d23f5ab 100644 (file)
@@ -32,7 +32,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
 /* Initialize cr4 shadow for this CPU. */
 static inline void cr4_init_shadow(void)
 {
-       this_cpu_write(cpu_tlbstate.cr4, __read_cr4());
+       this_cpu_write(cpu_tlbstate.cr4, __read_cr4_safe());
 }
 
 /* Set in this cpu's CR4. */
@@ -86,7 +86,14 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask)
 
 static inline void __native_flush_tlb(void)
 {
+       /*
+        * If current->mm == NULL then we borrow a mm which may change during a
+        * task switch and therefore we must not be preempted while we write CR3
+        * back:
+        */
+       preempt_disable();
        native_write_cr3(native_read_cr3());
+       preempt_enable();
 }
 
 static inline void __native_flush_tlb_global_irq_disabled(void)
index 09b1b0ab94b7653f7ed7019eb7e35b518582f825..dbe64f27280e34138dc5163b587579db35d3c768 100644 (file)
@@ -134,6 +134,9 @@ extern int __get_user_4(void);
 extern int __get_user_8(void);
 extern int __get_user_bad(void);
 
+#define __uaccess_begin() stac()
+#define __uaccess_end()   clac()
+
 /*
  * This is a type: either unsigned long, if the argument fits into
  * that type, or otherwise unsigned long long.
@@ -193,10 +196,10 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
 
 #ifdef CONFIG_X86_32
 #define __put_user_asm_u64(x, addr, err, errret)                       \
-       asm volatile(ASM_STAC "\n"                                      \
+       asm volatile("\n"                                               \
                     "1:        movl %%eax,0(%2)\n"                     \
                     "2:        movl %%edx,4(%2)\n"                     \
-                    "3: " ASM_CLAC "\n"                                \
+                    "3:"                                               \
                     ".section .fixup,\"ax\"\n"                         \
                     "4:        movl %3,%0\n"                           \
                     "  jmp 3b\n"                                       \
@@ -207,10 +210,10 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
                     : "A" (x), "r" (addr), "i" (errret), "0" (err))
 
 #define __put_user_asm_ex_u64(x, addr)                                 \
-       asm volatile(ASM_STAC "\n"                                      \
+       asm volatile("\n"                                               \
                     "1:        movl %%eax,0(%1)\n"                     \
                     "2:        movl %%edx,4(%1)\n"                     \
-                    "3: " ASM_CLAC "\n"                                \
+                    "3:"                                               \
                     _ASM_EXTABLE_EX(1b, 2b)                            \
                     _ASM_EXTABLE_EX(2b, 3b)                            \
                     : : "A" (x), "r" (addr))
@@ -304,6 +307,10 @@ do {                                                                       \
        }                                                               \
 } while (0)
 
+/*
+ * This doesn't do __uaccess_begin/end - the exception handling
+ * around it must do that.
+ */
 #define __put_user_size_ex(x, ptr, size)                               \
 do {                                                                   \
        __chk_user_ptr(ptr);                                            \
@@ -358,9 +365,9 @@ do {                                                                        \
 } while (0)
 
 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
-       asm volatile(ASM_STAC "\n"                                      \
+       asm volatile("\n"                                               \
                     "1:        mov"itype" %2,%"rtype"1\n"              \
-                    "2: " ASM_CLAC "\n"                                \
+                    "2:\n"                                             \
                     ".section .fixup,\"ax\"\n"                         \
                     "3:        mov %3,%0\n"                            \
                     "  xor"itype" %"rtype"1,%"rtype"1\n"               \
@@ -370,6 +377,10 @@ do {                                                                       \
                     : "=r" (err), ltype(x)                             \
                     : "m" (__m(addr)), "i" (errret), "0" (err))
 
+/*
+ * This doesn't do __uaccess_begin/end - the exception handling
+ * around it must do that.
+ */
 #define __get_user_size_ex(x, ptr, size)                               \
 do {                                                                   \
        __chk_user_ptr(ptr);                                            \
@@ -400,7 +411,9 @@ do {                                                                        \
 #define __put_user_nocheck(x, ptr, size)                       \
 ({                                                             \
        int __pu_err;                                           \
+       __uaccess_begin();                                      \
        __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \
+       __uaccess_end();                                        \
        __builtin_expect(__pu_err, 0);                          \
 })
 
@@ -408,7 +421,9 @@ do {                                                                        \
 ({                                                                     \
        int __gu_err;                                                   \
        unsigned long __gu_val;                                         \
+       __uaccess_begin();                                              \
        __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);    \
+       __uaccess_end();                                                \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
        __builtin_expect(__gu_err, 0);                                  \
 })
@@ -423,9 +438,9 @@ struct __large_struct { unsigned long buf[100]; };
  * aliasing issues.
  */
 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
-       asm volatile(ASM_STAC "\n"                                      \
+       asm volatile("\n"                                               \
                     "1:        mov"itype" %"rtype"1,%2\n"              \
-                    "2: " ASM_CLAC "\n"                                \
+                    "2:\n"                                             \
                     ".section .fixup,\"ax\"\n"                         \
                     "3:        mov %3,%0\n"                            \
                     "  jmp 2b\n"                                       \
@@ -445,11 +460,11 @@ struct __large_struct { unsigned long buf[100]; };
  */
 #define uaccess_try    do {                                            \
        current_thread_info()->uaccess_err = 0;                         \
-       stac();                                                         \
+       __uaccess_begin();                                              \
        barrier();
 
 #define uaccess_catch(err)                                             \
-       clac();                                                         \
+       __uaccess_end();                                                \
        (err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0);    \
 } while (0)
 
@@ -547,12 +562,13 @@ extern void __cmpxchg_wrong_size(void)
        __typeof__(ptr) __uval = (uval);                                \
        __typeof__(*(ptr)) __old = (old);                               \
        __typeof__(*(ptr)) __new = (new);                               \
+       __uaccess_begin();                                              \
        switch (size) {                                                 \
        case 1:                                                         \
        {                                                               \
-               asm volatile("\t" ASM_STAC "\n"                         \
+               asm volatile("\n"                                       \
                        "1:\t" LOCK_PREFIX "cmpxchgb %4, %2\n"          \
-                       "2:\t" ASM_CLAC "\n"                            \
+                       "2:\n"                                          \
                        "\t.section .fixup, \"ax\"\n"                   \
                        "3:\tmov     %3, %0\n"                          \
                        "\tjmp     2b\n"                                \
@@ -566,9 +582,9 @@ extern void __cmpxchg_wrong_size(void)
        }                                                               \
        case 2:                                                         \
        {                                                               \
-               asm volatile("\t" ASM_STAC "\n"                         \
+               asm volatile("\n"                                       \
                        "1:\t" LOCK_PREFIX "cmpxchgw %4, %2\n"          \
-                       "2:\t" ASM_CLAC "\n"                            \
+                       "2:\n"                                          \
                        "\t.section .fixup, \"ax\"\n"                   \
                        "3:\tmov     %3, %0\n"                          \
                        "\tjmp     2b\n"                                \
@@ -582,9 +598,9 @@ extern void __cmpxchg_wrong_size(void)
        }                                                               \
        case 4:                                                         \
        {                                                               \
-               asm volatile("\t" ASM_STAC "\n"                         \
+               asm volatile("\n"                                       \
                        "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"          \
-                       "2:\t" ASM_CLAC "\n"                            \
+                       "2:\n"                                          \
                        "\t.section .fixup, \"ax\"\n"                   \
                        "3:\tmov     %3, %0\n"                          \
                        "\tjmp     2b\n"                                \
@@ -601,9 +617,9 @@ extern void __cmpxchg_wrong_size(void)
                if (!IS_ENABLED(CONFIG_X86_64))                         \
                        __cmpxchg_wrong_size();                         \
                                                                        \
-               asm volatile("\t" ASM_STAC "\n"                         \
+               asm volatile("\n"                                       \
                        "1:\t" LOCK_PREFIX "cmpxchgq %4, %2\n"          \
-                       "2:\t" ASM_CLAC "\n"                            \
+                       "2:\n"                                          \
                        "\t.section .fixup, \"ax\"\n"                   \
                        "3:\tmov     %3, %0\n"                          \
                        "\tjmp     2b\n"                                \
@@ -618,6 +634,7 @@ extern void __cmpxchg_wrong_size(void)
        default:                                                        \
                __cmpxchg_wrong_size();                                 \
        }                                                               \
+       __uaccess_end();                                                \
        *__uval = __old;                                                \
        __ret;                                                          \
 })
@@ -689,7 +706,7 @@ __copy_from_user_overflow(int size, unsigned long count)
 
 #endif
 
-static inline unsigned long __must_check
+static __always_inline unsigned long __must_check
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        int sz = __compiletime_object_size(to);
@@ -714,9 +731,10 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
         * case, and do only runtime checking for non-constant sizes.
         */
 
-       if (likely(sz < 0 || sz >= n))
+       if (likely(sz < 0 || sz >= n)) {
+               check_object_size(to, n, false);
                n = _copy_from_user(to, from, n);
-       else if(__builtin_constant_p(n))
+       } else if (__builtin_constant_p(n))
                copy_from_user_overflow();
        else
                __copy_from_user_overflow(sz, n);
@@ -724,7 +742,7 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
        return n;
 }
 
-static inline unsigned long __must_check
+static __always_inline unsigned long __must_check
 copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        int sz = __compiletime_object_size(from);
@@ -732,9 +750,10 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
        might_fault();
 
        /* See the comment in copy_from_user() above. */
-       if (likely(sz < 0 || sz >= n))
+       if (likely(sz < 0 || sz >= n)) {
+               check_object_size(from, n, true);
                n = _copy_to_user(to, from, n);
-       else if(__builtin_constant_p(n))
+       } else if (__builtin_constant_p(n))
                copy_to_user_overflow();
        else
                __copy_to_user_overflow(sz, n);
@@ -745,5 +764,30 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
 #undef __copy_from_user_overflow
 #undef __copy_to_user_overflow
 
+/*
+ * The "unsafe" user accesses aren't really "unsafe", but the naming
+ * is a big fat warning: you have to not only do the access_ok()
+ * checking before using them, but you have to surround them with the
+ * user_access_begin/end() pair.
+ */
+#define user_access_begin()    __uaccess_begin()
+#define user_access_end()      __uaccess_end()
+
+#define unsafe_put_user(x, ptr, err_label)                                     \
+do {                                                                           \
+       int __pu_err;                                                           \
+       __put_user_size((x), (ptr), sizeof(*(ptr)), __pu_err, -EFAULT);         \
+       if (unlikely(__pu_err)) goto err_label;                                 \
+} while (0)
+
+#define unsafe_get_user(x, ptr, err_label)                                     \
+do {                                                                           \
+       int __gu_err;                                                           \
+       unsigned long __gu_val;                                                 \
+       __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), __gu_err, -EFAULT);    \
+       (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
+       if (unlikely(__gu_err)) goto err_label;                                 \
+} while (0)
+
 #endif /* _ASM_X86_UACCESS_H */
 
index f5dcb5204dcd5b27e8b8e9a1b87612a28cda10c6..7d3bdd1ed6977b5e1f69dc8ba3e3d6cfa8f861a3 100644 (file)
@@ -33,38 +33,11 @@ unsigned long __must_check __copy_from_user_ll_nocache_nozero
  * the specified block with access_ok() before calling this function.
  * The caller should also make sure he pins the user space address
  * so that we don't result in page fault and sleep.
- *
- * Here we special-case 1, 2 and 4-byte copy_*_user invocations.  On a fault
- * we return the initial request size (1, 2 or 4), as copy_*_user should do.
- * If a store crosses a page boundary and gets a fault, the x86 will not write
- * anything, so this is accurate.
  */
-
 static __always_inline unsigned long __must_check
 __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 {
-       if (__builtin_constant_p(n)) {
-               unsigned long ret;
-
-               switch (n) {
-               case 1:
-                       __put_user_size(*(u8 *)from, (u8 __user *)to,
-                                       1, ret, 1);
-                       return ret;
-               case 2:
-                       __put_user_size(*(u16 *)from, (u16 __user *)to,
-                                       2, ret, 2);
-                       return ret;
-               case 4:
-                       __put_user_size(*(u32 *)from, (u32 __user *)to,
-                                       4, ret, 4);
-                       return ret;
-               case 8:
-                       __put_user_size(*(u64 *)from, (u64 __user *)to,
-                                       8, ret, 8);
-                       return ret;
-               }
-       }
+       check_object_size(from, n, true);
        return __copy_to_user_ll(to, from, n);
 }
 
@@ -93,26 +66,6 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
 static __always_inline unsigned long
 __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
-       /* Avoid zeroing the tail if the copy fails..
-        * If 'n' is constant and 1, 2, or 4, we do still zero on a failure,
-        * but as the zeroing behaviour is only significant when n is not
-        * constant, that shouldn't be a problem.
-        */
-       if (__builtin_constant_p(n)) {
-               unsigned long ret;
-
-               switch (n) {
-               case 1:
-                       __get_user_size(*(u8 *)to, from, 1, ret, 1);
-                       return ret;
-               case 2:
-                       __get_user_size(*(u16 *)to, from, 2, ret, 2);
-                       return ret;
-               case 4:
-                       __get_user_size(*(u32 *)to, from, 4, ret, 4);
-                       return ret;
-               }
-       }
        return __copy_from_user_ll_nozero(to, from, n);
 }
 
@@ -143,18 +96,25 @@ static __always_inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        might_fault();
+       check_object_size(to, n, false);
        if (__builtin_constant_p(n)) {
                unsigned long ret;
 
                switch (n) {
                case 1:
+                       __uaccess_begin();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
+                       __uaccess_end();
                        return ret;
                case 2:
+                       __uaccess_begin();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
+                       __uaccess_end();
                        return ret;
                case 4:
+                       __uaccess_begin();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
+                       __uaccess_end();
                        return ret;
                }
        }
@@ -170,13 +130,19 @@ static __always_inline unsigned long __copy_from_user_nocache(void *to,
 
                switch (n) {
                case 1:
+                       __uaccess_begin();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
+                       __uaccess_end();
                        return ret;
                case 2:
+                       __uaccess_begin();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
+                       __uaccess_end();
                        return ret;
                case 4:
+                       __uaccess_begin();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
+                       __uaccess_end();
                        return ret;
                }
        }
index f2f9b39b274ab0c2f81ab6b388f78ba5c881ec5e..2957c8237c28d6e46283bca9dd58a6ec528f1913 100644 (file)
@@ -53,38 +53,53 @@ int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
 {
        int ret = 0;
 
+       check_object_size(dst, size, false);
        if (!__builtin_constant_p(size))
                return copy_user_generic(dst, (__force void *)src, size);
        switch (size) {
-       case 1:__get_user_asm(*(u8 *)dst, (u8 __user *)src,
+       case 1:
+               __uaccess_begin();
+               __get_user_asm(*(u8 *)dst, (u8 __user *)src,
                              ret, "b", "b", "=q", 1);
+               __uaccess_end();
                return ret;
-       case 2:__get_user_asm(*(u16 *)dst, (u16 __user *)src,
+       case 2:
+               __uaccess_begin();
+               __get_user_asm(*(u16 *)dst, (u16 __user *)src,
                              ret, "w", "w", "=r", 2);
+               __uaccess_end();
                return ret;
-       case 4:__get_user_asm(*(u32 *)dst, (u32 __user *)src,
+       case 4:
+               __uaccess_begin();
+               __get_user_asm(*(u32 *)dst, (u32 __user *)src,
                              ret, "l", "k", "=r", 4);
+               __uaccess_end();
                return ret;
-       case 8:__get_user_asm(*(u64 *)dst, (u64 __user *)src,
+       case 8:
+               __uaccess_begin();
+               __get_user_asm(*(u64 *)dst, (u64 __user *)src,
                              ret, "q", "", "=r", 8);
+               __uaccess_end();
                return ret;
        case 10:
+               __uaccess_begin();
                __get_user_asm(*(u64 *)dst, (u64 __user *)src,
                               ret, "q", "", "=r", 10);
-               if (unlikely(ret))
-                       return ret;
-               __get_user_asm(*(u16 *)(8 + (char *)dst),
-                              (u16 __user *)(8 + (char __user *)src),
-                              ret, "w", "w", "=r", 2);
+               if (likely(!ret))
+                       __get_user_asm(*(u16 *)(8 + (char *)dst),
+                                      (u16 __user *)(8 + (char __user *)src),
+                                      ret, "w", "w", "=r", 2);
+               __uaccess_end();
                return ret;
        case 16:
+               __uaccess_begin();
                __get_user_asm(*(u64 *)dst, (u64 __user *)src,
                               ret, "q", "", "=r", 16);
-               if (unlikely(ret))
-                       return ret;
-               __get_user_asm(*(u64 *)(8 + (char *)dst),
-                              (u64 __user *)(8 + (char __user *)src),
-                              ret, "q", "", "=r", 8);
+               if (likely(!ret))
+                       __get_user_asm(*(u64 *)(8 + (char *)dst),
+                                      (u64 __user *)(8 + (char __user *)src),
+                                      ret, "q", "", "=r", 8);
+               __uaccess_end();
                return ret;
        default:
                return copy_user_generic(dst, (__force void *)src, size);
@@ -103,38 +118,55 @@ int __copy_to_user_nocheck(void __user *dst, const void *src, unsigned size)
 {
        int ret = 0;
 
+       check_object_size(src, size, true);
        if (!__builtin_constant_p(size))
                return copy_user_generic((__force void *)dst, src, size);
        switch (size) {
-       case 1:__put_user_asm(*(u8 *)src, (u8 __user *)dst,
+       case 1:
+               __uaccess_begin();
+               __put_user_asm(*(u8 *)src, (u8 __user *)dst,
                              ret, "b", "b", "iq", 1);
+               __uaccess_end();
                return ret;
-       case 2:__put_user_asm(*(u16 *)src, (u16 __user *)dst,
+       case 2:
+               __uaccess_begin();
+               __put_user_asm(*(u16 *)src, (u16 __user *)dst,
                              ret, "w", "w", "ir", 2);
+               __uaccess_end();
                return ret;
-       case 4:__put_user_asm(*(u32 *)src, (u32 __user *)dst,
+       case 4:
+               __uaccess_begin();
+               __put_user_asm(*(u32 *)src, (u32 __user *)dst,
                              ret, "l", "k", "ir", 4);
+               __uaccess_end();
                return ret;
-       case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst,
+       case 8:
+               __uaccess_begin();
+               __put_user_asm(*(u64 *)src, (u64 __user *)dst,
                              ret, "q", "", "er", 8);
+               __uaccess_end();
                return ret;
        case 10:
+               __uaccess_begin();
                __put_user_asm(*(u64 *)src, (u64 __user *)dst,
                               ret, "q", "", "er", 10);
-               if (unlikely(ret))
-                       return ret;
-               asm("":::"memory");
-               __put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
-                              ret, "w", "w", "ir", 2);
+               if (likely(!ret)) {
+                       asm("":::"memory");
+                       __put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
+                                      ret, "w", "w", "ir", 2);
+               }
+               __uaccess_end();
                return ret;
        case 16:
+               __uaccess_begin();
                __put_user_asm(*(u64 *)src, (u64 __user *)dst,
                               ret, "q", "", "er", 16);
-               if (unlikely(ret))
-                       return ret;
-               asm("":::"memory");
-               __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
-                              ret, "q", "", "er", 8);
+               if (likely(!ret)) {
+                       asm("":::"memory");
+                       __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
+                                      ret, "q", "", "er", 8);
+               }
+               __uaccess_end();
                return ret;
        default:
                return copy_user_generic((__force void *)dst, src, size);
@@ -160,39 +192,47 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
        switch (size) {
        case 1: {
                u8 tmp;
+               __uaccess_begin();
                __get_user_asm(tmp, (u8 __user *)src,
                               ret, "b", "b", "=q", 1);
                if (likely(!ret))
                        __put_user_asm(tmp, (u8 __user *)dst,
                                       ret, "b", "b", "iq", 1);
+               __uaccess_end();
                return ret;
        }
        case 2: {
                u16 tmp;
+               __uaccess_begin();
                __get_user_asm(tmp, (u16 __user *)src,
                               ret, "w", "w", "=r", 2);
                if (likely(!ret))
                        __put_user_asm(tmp, (u16 __user *)dst,
                                       ret, "w", "w", "ir", 2);
+               __uaccess_end();
                return ret;
        }
 
        case 4: {
                u32 tmp;
+               __uaccess_begin();
                __get_user_asm(tmp, (u32 __user *)src,
                               ret, "l", "k", "=r", 4);
                if (likely(!ret))
                        __put_user_asm(tmp, (u32 __user *)dst,
                                       ret, "l", "k", "ir", 4);
+               __uaccess_end();
                return ret;
        }
        case 8: {
                u64 tmp;
+               __uaccess_begin();
                __get_user_asm(tmp, (u64 __user *)src,
                               ret, "q", "", "=r", 8);
                if (likely(!ret))
                        __put_user_asm(tmp, (u64 __user *)dst,
                                       ret, "q", "", "er", 8);
+               __uaccess_end();
                return ret;
        }
        default:
index 2f69e3b184f62c2f7e87c6956bc58fbadb711965..a3e1f8497f8c6911aaac556c5935daace3a706ac 100644 (file)
@@ -1587,6 +1587,9 @@ void __init enable_IR_x2apic(void)
        unsigned long flags;
        int ret, ir_stat;
 
+       if (skip_ioapic_setup)
+               return;
+
        ir_stat = irq_remapping_prepare();
        if (ir_stat < 0 && !x2apic_supported())
                return;
index df6b4eeac0bde402207f321491880edfb588ed77..0988e204f1e39424a08e8d50ff91440206bfc8a5 100644 (file)
@@ -659,11 +659,28 @@ void irq_complete_move(struct irq_cfg *cfg)
  */
 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;
+       struct irq_data *irqdata;
+       struct apic_chip_data *data;
+       struct irq_cfg *cfg;
        unsigned int cpu;
 
+       /*
+        * The function is called for all descriptors regardless of which
+        * irqdomain they belong to. For example if an IRQ is provided by
+        * an irq_chip as part of a GPIO driver, the chip data for that
+        * descriptor is specific to the irq_chip in question.
+        *
+        * Check first that the chip_data is what we expect
+        * (apic_chip_data) before touching it any further.
+        */
+       irqdata = irq_domain_get_irq_data(x86_vector_domain,
+                                         irq_desc_get_irq(desc));
+       if (!irqdata)
+               return;
+
+       data = apic_chip_data(irqdata);
+       cfg = data ? &data->cfg : NULL;
+
        if (!cfg)
                return;
 
index a8816b3251620c941f543e595e949aa60c43467d..6cb5834062a3936f54a3d7d3035135979f0c6d31 100644 (file)
@@ -656,6 +656,17 @@ static void init_amd_gh(struct cpuinfo_x86 *c)
                set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
 }
 
+#define MSR_AMD64_DE_CFG       0xC0011029
+
+static void init_amd_ln(struct cpuinfo_x86 *c)
+{
+       /*
+        * Apply erratum 665 fix unconditionally so machines without a BIOS
+        * fix work.
+        */
+       msr_set_bit(MSR_AMD64_DE_CFG, 31);
+}
+
 static void init_amd_bd(struct cpuinfo_x86 *c)
 {
        u64 value;
@@ -713,6 +724,7 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 6:    init_amd_k7(c); break;
        case 0xf:  init_amd_k8(c); break;
        case 0x10: init_amd_gh(c); break;
+       case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
        }
 
index c2b7522cbf357617bf8302f3c4f964834b940926..2b49b113d65d02267be149ef5039139871779209 100644 (file)
@@ -737,21 +737,20 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
                identify_cpu_without_cpuid(c);
 
        /* cyrix could have cpuid enabled via c_identify()*/
-       if (!have_cpuid_p())
-               return;
+       if (have_cpuid_p()) {
+               cpu_detect(c);
+               get_cpu_vendor(c);
+               get_cpu_cap(c);
 
-       cpu_detect(c);
-       get_cpu_vendor(c);
-       get_cpu_cap(c);
-
-       if (this_cpu->c_early_init)
-               this_cpu->c_early_init(c);
+               if (this_cpu->c_early_init)
+                       this_cpu->c_early_init(c);
 
-       c->cpu_index = 0;
-       filter_cpuid_features(c, false);
+               c->cpu_index = 0;
+               filter_cpuid_features(c, false);
 
-       if (this_cpu->c_bsp_init)
-               this_cpu->c_bsp_init(c);
+               if (this_cpu->c_bsp_init)
+                       this_cpu->c_bsp_init(c);
+       }
 
        setup_force_cpu_cap(X86_FEATURE_ALWAYS);
        fpu__init_system(c);
index 20e242ea1bc46b5f5828c7b95071d920853b7609..cfc4a966e2b9e2a80e1d3349c6dfdbe9c28ea08b 100644 (file)
@@ -152,6 +152,11 @@ static struct clocksource hyperv_cs = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static unsigned char hv_get_nmi_reason(void)
+{
+       return 0;
+}
+
 static void __init ms_hyperv_init_platform(void)
 {
        /*
@@ -191,6 +196,13 @@ static void __init ms_hyperv_init_platform(void)
        machine_ops.crash_shutdown = hv_machine_crash_shutdown;
 #endif
        mark_tsc_unstable("running on Hyper-V");
+
+       /*
+        * Generation 2 instances don't support reading the NMI status from
+        * 0x61 port.
+        */
+       if (efi_enabled(EFI_BOOT))
+               x86_platform.get_nmi_reason = hv_get_nmi_reason;
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
index 3b533cf37c745c9ecfc81fc5fde94bc46f84e1b5..b5624fafa44a5083f511d661c030b240dd29dae6 100644 (file)
@@ -444,11 +444,24 @@ static void __init print_mtrr_state(void)
                pr_debug("TOM2: %016llx aka %lldM\n", mtrr_tom2, mtrr_tom2>>20);
 }
 
+/* PAT setup for BP. We need to go through sync steps here */
+void __init mtrr_bp_pat_init(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       prepare_set();
+
+       pat_init();
+
+       post_set();
+       local_irq_restore(flags);
+}
+
 /* Grab all of the MTRR state for this CPU into *state */
 bool __init get_mtrr_state(void)
 {
        struct mtrr_var_range *vrs;
-       unsigned long flags;
        unsigned lo, dummy;
        unsigned int i;
 
@@ -481,15 +494,6 @@ bool __init get_mtrr_state(void)
 
        mtrr_state_set = 1;
 
-       /* PAT setup for BP. We need to go through sync steps here */
-       local_irq_save(flags);
-       prepare_set();
-
-       pat_init();
-
-       post_set();
-       local_irq_restore(flags);
-
        return !!(mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED);
 }
 
index f891b4750f04c00b296b84598aa396bcbe9724c7..fa77ac8291f03d7e268dabc8a565aab9cab046f7 100644 (file)
@@ -752,6 +752,9 @@ void __init mtrr_bp_init(void)
                        /* BIOS may override */
                        __mtrr_enabled = get_mtrr_state();
 
+                       if (mtrr_enabled())
+                               mtrr_bp_pat_init();
+
                        if (mtrr_cleanup(phys_addr)) {
                                changed_by_mtrr_cleanup = 1;
                                mtrr_if->set_all();
@@ -759,8 +762,16 @@ void __init mtrr_bp_init(void)
                }
        }
 
-       if (!mtrr_enabled())
+       if (!mtrr_enabled()) {
                pr_info("MTRR: Disabled\n");
+
+               /*
+                * PAT initialization relies on MTRR's rendezvous handler.
+                * Skip PAT init until the handler can initialize both
+                * features independently.
+                */
+               pat_disable("MTRRs disabled, skipping PAT initialization too.");
+       }
 }
 
 void mtrr_ap_init(void)
index 951884dcc43354573c2bd234aed3fd3adb067a84..6c7ced07d16d1181c6ef21f4f2252ef63019a77b 100644 (file)
@@ -52,6 +52,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
 void fill_mtrr_var_range(unsigned int index,
                u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
 bool get_mtrr_state(void);
+void mtrr_bp_pat_init(void);
 
 extern void set_mtrr_ops(const struct mtrr_ops *ops);
 
index a316ca96f1b639d8a0f58f616c1c62d4da61bfdf..fc704ed587e83970c733b8b6e11a227fe305cb6a 100644 (file)
@@ -211,6 +211,20 @@ static void __put_rmid(u32 rmid)
        list_add_tail(&entry->list, &cqm_rmid_limbo_lru);
 }
 
+static void cqm_cleanup(void)
+{
+       int i;
+
+       if (!cqm_rmid_ptrs)
+               return;
+
+       for (i = 0; i < cqm_max_rmid; i++)
+               kfree(cqm_rmid_ptrs[i]);
+
+       kfree(cqm_rmid_ptrs);
+       cqm_rmid_ptrs = NULL;
+}
+
 static int intel_cqm_setup_rmid_cache(void)
 {
        struct cqm_rmid_entry *entry;
@@ -218,7 +232,7 @@ static int intel_cqm_setup_rmid_cache(void)
        int r = 0;
 
        nr_rmids = cqm_max_rmid + 1;
-       cqm_rmid_ptrs = kmalloc(sizeof(struct cqm_rmid_entry *) *
+       cqm_rmid_ptrs = kzalloc(sizeof(struct cqm_rmid_entry *) *
                                nr_rmids, GFP_KERNEL);
        if (!cqm_rmid_ptrs)
                return -ENOMEM;
@@ -249,11 +263,9 @@ static int intel_cqm_setup_rmid_cache(void)
        mutex_unlock(&cache_mutex);
 
        return 0;
-fail:
-       while (r--)
-               kfree(cqm_rmid_ptrs[r]);
 
-       kfree(cqm_rmid_ptrs);
+fail:
+       cqm_cleanup();
        return -ENOMEM;
 }
 
@@ -281,9 +293,13 @@ static bool __match_event(struct perf_event *a, struct perf_event *b)
 
        /*
         * Events that target same task are placed into the same cache group.
+        * Mark it as a multi event group, so that we update ->count
+        * for every event rather than just the group leader later.
         */
-       if (a->hw.target == b->hw.target)
+       if (a->hw.target == b->hw.target) {
+               b->hw.is_group_event = true;
                return true;
+       }
 
        /*
         * Are we an inherited event?
@@ -849,6 +865,7 @@ static void intel_cqm_setup_event(struct perf_event *event,
        bool conflict = false;
        u32 rmid;
 
+       event->hw.is_group_event = false;
        list_for_each_entry(iter, &cache_groups, hw.cqm_groups_entry) {
                rmid = iter->hw.cqm_rmid;
 
@@ -940,7 +957,9 @@ static u64 intel_cqm_event_count(struct perf_event *event)
                return __perf_event_count(event);
 
        /*
-        * Only the group leader gets to report values. This stops us
+        * Only the group leader gets to report values except in case of
+        * multiple events in the same group, we still need to read the
+        * other events.This stops us
         * reporting duplicate values to userspace, and gives us a clear
         * rule for which task gets to report the values.
         *
@@ -948,7 +967,7 @@ static u64 intel_cqm_event_count(struct perf_event *event)
         * specific packages - we forfeit that ability when we create
         * task events.
         */
-       if (!cqm_group_leader(event))
+       if (!cqm_group_leader(event) && !event->hw.is_group_event)
                return 0;
 
        /*
@@ -1315,7 +1334,7 @@ static const struct x86_cpu_id intel_cqm_match[] = {
 
 static int __init intel_cqm_init(void)
 {
-       char *str, scale[20];
+       char *str = NULL, scale[20];
        int i, cpu, ret;
 
        if (!x86_match_cpu(intel_cqm_match))
@@ -1375,16 +1394,25 @@ static int __init intel_cqm_init(void)
                cqm_pick_event_reader(i);
        }
 
-       __perf_cpu_notifier(intel_cqm_cpu_notifier);
-
        ret = perf_pmu_register(&intel_cqm_pmu, "intel_cqm", -1);
-       if (ret)
+       if (ret) {
                pr_err("Intel CQM perf registration failed: %d\n", ret);
-       else
-               pr_info("Intel CQM monitoring enabled\n");
+               goto out;
+       }
+
+       pr_info("Intel CQM monitoring enabled\n");
 
+       /*
+        * Register the hot cpu notifier once we are sure cqm
+        * is enabled to avoid notifier leak.
+        */
+       __perf_cpu_notifier(intel_cqm_cpu_notifier);
 out:
        cpu_notifier_register_done();
+       if (ret) {
+               kfree(str);
+               cqm_cleanup();
+       }
 
        return ret;
 }
index 7abb2b88572e04425722a214e1ee3925fe429e34..1e7de3cefc9c4c70e1809bca8d5c2ed5d1070cab 100644 (file)
@@ -1110,6 +1110,13 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit)
        void *at;
        u64 pebs_status;
 
+       /*
+        * fmt0 does not have a status bitfield (does not use
+        * perf_record_nhm format)
+        */
+       if (x86_pmu.intel_cap.pebs_format < 1)
+               return base;
+
        if (base == NULL)
                return NULL;
 
@@ -1195,7 +1202,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
        if (!event->attr.precise_ip)
                return;
 
-       n = (top - at) / x86_pmu.pebs_record_size;
+       n = top - at;
        if (n <= 0)
                return;
 
index 569c1e4f96feb897956a64e35bd8fccb07dca6c6..52a2526c3fbe457d899d0d66dad28e69feabf41f 100644 (file)
@@ -753,7 +753,7 @@ u64 __init early_reserve_e820(u64 size, u64 align)
 /*
  * Find the highest page frame number we have available
  */
-static unsigned long __init e820_end_pfn(unsigned long limit_pfn)
+static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
 {
        int i;
        unsigned long last_pfn = 0;
@@ -764,11 +764,7 @@ static unsigned long __init e820_end_pfn(unsigned long limit_pfn)
                unsigned long start_pfn;
                unsigned long end_pfn;
 
-               /*
-                * Persistent memory is accounted as ram for purposes of
-                * establishing max_pfn and mem_map.
-                */
-               if (ei->type != E820_RAM && ei->type != E820_PRAM)
+               if (ei->type != type)
                        continue;
 
                start_pfn = ei->addr >> PAGE_SHIFT;
@@ -793,12 +789,12 @@ static unsigned long __init e820_end_pfn(unsigned long limit_pfn)
 }
 unsigned long __init e820_end_of_ram_pfn(void)
 {
-       return e820_end_pfn(MAX_ARCH_PFN);
+       return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
 }
 
 unsigned long __init e820_end_of_low_ram_pfn(void)
 {
-       return e820_end_pfn(1UL << (32-PAGE_SHIFT));
+       return e820_end_pfn(1UL << (32 - PAGE_SHIFT), E820_RAM);
 }
 
 static void early_panic(char *msg)
index db9a675e751b0bf1401af295a40b1e7a314bab6a..a257d6077d1b3110d7813af09d6d842848039a2e 100644 (file)
 
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
 #include <linux/pci_ids.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
 #include <drm/i915_drm.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
@@ -21,6 +25,9 @@
 #include <asm/iommu.h>
 #include <asm/gart.h>
 #include <asm/irq_remapping.h>
+#include <asm/early_ioremap.h>
+
+#define dev_err(msg)  pr_err("pci 0000:%02x:%02x.%d: %s", bus, slot, func, msg)
 
 static void __init fix_hypertransport_config(int num, int slot, int func)
 {
@@ -75,6 +82,13 @@ static void __init nvidia_bugs(int num, int slot, int func)
 {
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_X86_IO_APIC
+       /*
+        * Only applies to Nvidia root ports (bus 0) and not to
+        * Nvidia graphics cards with PCI ports on secondary buses.
+        */
+       if (num)
+               return;
+
        /*
         * All timer overrides on Nvidia are
         * wrong unless HPET is enabled.
@@ -317,12 +331,11 @@ static u32 __init i85x_stolen_base(int num, int slot, int func, size_t stolen_si
 
 static u32 __init i865_stolen_base(int num, int slot, int func, size_t stolen_size)
 {
-       /*
-        * FIXME is the graphics stolen memory region
-        * always at TOUD? Ie. is it always the last
-        * one to be allocated by the BIOS?
-        */
-       return read_pci_config_16(0, 0, 0, I865_TOUD) << 16;
+       u16 toud = 0;
+
+       toud = read_pci_config_16(0, 0, 0, I865_TOUD);
+
+       return (phys_addr_t)(toud << 16) + i845_tseg_size();
 }
 
 static size_t __init i830_stolen_size(int num, int slot, int func)
@@ -589,6 +602,61 @@ static void __init force_disable_hpet(int num, int slot, int func)
 #endif
 }
 
+#define BCM4331_MMIO_SIZE      16384
+#define BCM4331_PM_CAP         0x40
+#define bcma_aread32(reg)      ioread32(mmio + 1 * BCMA_CORE_SIZE + reg)
+#define bcma_awrite32(reg, val)        iowrite32(val, mmio + 1 * BCMA_CORE_SIZE + reg)
+
+static void __init apple_airport_reset(int bus, int slot, int func)
+{
+       void __iomem *mmio;
+       u16 pmcsr;
+       u64 addr;
+       int i;
+
+       if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc."))
+               return;
+
+       /* Card may have been put into PCI_D3hot by grub quirk */
+       pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
+
+       if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
+               pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+               write_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL, pmcsr);
+               mdelay(10);
+
+               pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL);
+               if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) {
+                       dev_err("Cannot power up Apple AirPort card\n");
+                       return;
+               }
+       }
+
+       addr  =      read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+       addr |= (u64)read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1) << 32;
+       addr &= PCI_BASE_ADDRESS_MEM_MASK;
+
+       mmio = early_ioremap(addr, BCM4331_MMIO_SIZE);
+       if (!mmio) {
+               dev_err("Cannot iomap Apple AirPort card\n");
+               return;
+       }
+
+       pr_info("Resetting Apple AirPort card (left enabled by EFI)\n");
+
+       for (i = 0; bcma_aread32(BCMA_RESET_ST) && i < 30; i++)
+               udelay(10);
+
+       bcma_awrite32(BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
+       bcma_aread32(BCMA_RESET_CTL);
+       udelay(1);
+
+       bcma_awrite32(BCMA_RESET_CTL, 0);
+       bcma_aread32(BCMA_RESET_CTL);
+       udelay(10);
+
+       early_iounmap(mmio, BCM4331_MMIO_SIZE);
+}
 
 #define QFLAG_APPLY_ONCE       0x1
 #define QFLAG_APPLIED          0x2
@@ -602,12 +670,6 @@ struct chipset {
        void (*f)(int num, int slot, int func);
 };
 
-/*
- * Only works for devices on the root bus. If you add any devices
- * not on bus 0 readd another loop level in early_quirks(). But
- * be careful because at least the Nvidia quirk here relies on
- * only matching on bus 0.
- */
 static struct chipset early_qrk[] __initdata = {
        { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
          PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs },
@@ -637,9 +699,13 @@ static struct chipset early_qrk[] __initdata = {
         */
        { PCI_VENDOR_ID_INTEL, 0x0f00,
                PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet},
+       { PCI_VENDOR_ID_BROADCOM, 0x4331,
+         PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset},
        {}
 };
 
+static void __init early_pci_scan_bus(int bus);
+
 /**
  * check_dev_quirk - apply early quirks to a given PCI device
  * @num: bus number
@@ -648,7 +714,7 @@ static struct chipset early_qrk[] __initdata = {
  *
  * Check the vendor & device ID against the early quirks table.
  *
- * If the device is single function, let early_quirks() know so we don't
+ * If the device is single function, let early_pci_scan_bus() know so we don't
  * poke at this device again.
  */
 static int __init check_dev_quirk(int num, int slot, int func)
@@ -657,6 +723,7 @@ static int __init check_dev_quirk(int num, int slot, int func)
        u16 vendor;
        u16 device;
        u8 type;
+       u8 sec;
        int i;
 
        class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE);
@@ -684,25 +751,36 @@ static int __init check_dev_quirk(int num, int slot, int func)
 
        type = read_pci_config_byte(num, slot, func,
                                    PCI_HEADER_TYPE);
+
+       if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
+               sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS);
+               if (sec > num)
+                       early_pci_scan_bus(sec);
+       }
+
        if (!(type & 0x80))
                return -1;
 
        return 0;
 }
 
-void __init early_quirks(void)
+static void __init early_pci_scan_bus(int bus)
 {
        int slot, func;
 
-       if (!early_pci_allowed())
-               return;
-
        /* Poor man's PCI discovery */
-       /* Only scan the root bus */
        for (slot = 0; slot < 32; slot++)
                for (func = 0; func < 8; func++) {
                        /* Only probe function 0 on single fn devices */
-                       if (check_dev_quirk(0, slot, func))
+                       if (check_dev_quirk(bus, slot, func))
                                break;
                }
 }
+
+void __init early_quirks(void)
+{
+       if (!early_pci_allowed())
+               return;
+
+       early_pci_scan_bus(0);
+}
index c2130aef3f9d25d6c6a47f3499b8096c5cfb8e80..f534a0e3af5358f904364a4e0680f1c231370cb4 100644 (file)
@@ -55,12 +55,12 @@ asm (".pushsection .entry.text, \"ax\"\n"
      ".popsection");
 
 /* identity function, which can be inlined */
-u32 _paravirt_ident_32(u32 x)
+u32 notrace _paravirt_ident_32(u32 x)
 {
        return x;
 }
 
-u64 _paravirt_ident_64(u64 x)
+u64 notrace _paravirt_ident_64(u64 x)
 {
        return x;
 }
index 558f50edebca8f55a8c33e67bfcd21f9c78037a9..479a409ddac8eaaaf72e48646166af5615baff70 100644 (file)
@@ -188,8 +188,8 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs)
                return sp;
 
        prev_esp = (u32 *)(context);
-       if (prev_esp)
-               return (unsigned long)prev_esp;
+       if (*prev_esp)
+               return (unsigned long)*prev_esp;
 
        return (unsigned long)regs;
 }
index 2f355d229a587771680b28080d92fd06f345d7e7..bf0ce75735b02f0c5cbfb6b9ae5e616b512a271f 100644 (file)
@@ -66,6 +66,8 @@ u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src)
 
        do {
                version = __pvclock_read_cycles(src, &ret, &flags);
+               /* Make sure that the version double-check is last. */
+               smp_rmb();
        } while ((src->version & 1) || version != src->version);
 
        return flags & valid_flags;
@@ -80,6 +82,8 @@ cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
 
        do {
                version = __pvclock_read_cycles(src, &ret, &flags);
+               /* Make sure that the version double-check is last. */
+               smp_rmb();
        } while ((src->version & 1) || version != src->version);
 
        if (unlikely((flags & PVCLOCK_GUEST_STOPPED) != 0)) {
index bf4db6eaec8fda2aae48f2fe7c1cddb8d157b37f..c6aace2bbe083e28ee8bf3e6870d313e82d37d21 100644 (file)
@@ -357,20 +357,22 @@ static void riprel_analyze(struct arch_uprobe *auprobe, struct insn *insn)
                *cursor &= 0xfe;
        }
        /*
-        * Similar treatment for VEX3 prefix.
-        * TODO: add XOP/EVEX treatment when insn decoder supports them
+        * Similar treatment for VEX3/EVEX prefix.
+        * TODO: add XOP treatment when insn decoder supports them
         */
-       if (insn->vex_prefix.nbytes == 3) {
+       if (insn->vex_prefix.nbytes >= 3) {
                /*
                 * vex2:     c5    rvvvvLpp   (has no b bit)
                 * vex3/xop: c4/8f rxbmmmmm wvvvvLpp
                 * evex:     62    rxbR00mm wvvvv1pp zllBVaaa
-                *   (evex will need setting of both b and x since
-                *   in non-sib encoding evex.x is 4th bit of MODRM.rm)
-                * Setting VEX3.b (setting because it has inverted meaning):
+                * Setting VEX3.b (setting because it has inverted meaning).
+                * Setting EVEX.x since (in non-SIB encoding) EVEX.x
+                * is the 4th bit of MODRM.rm, and needs the same treatment.
+                * For VEX3-encoded insns, VEX3.x value has no effect in
+                * non-SIB encoding, the change is superfluous but harmless.
                 */
                cursor = auprobe->insn + insn_offset_vex_prefix(insn) + 1;
-               *cursor |= 0x20;
+               *cursor |= 0x60;
        }
 
        /*
@@ -415,12 +417,10 @@ static void riprel_analyze(struct arch_uprobe *auprobe, struct insn *insn)
 
        reg = MODRM_REG(insn);  /* Fetch modrm.reg */
        reg2 = 0xff;            /* Fetch vex.vvvv */
-       if (insn->vex_prefix.nbytes == 2)
-               reg2 = insn->vex_prefix.bytes[1];
-       else if (insn->vex_prefix.nbytes == 3)
+       if (insn->vex_prefix.nbytes)
                reg2 = insn->vex_prefix.bytes[2];
        /*
-        * TODO: add XOP, EXEV vvvv reading.
+        * TODO: add XOP vvvv reading.
         *
         * vex.vvvv field is in bits 6-3, bits are inverted.
         * But in 32-bit mode, high-order bit may be ignored.
index 88d0a92d3f94676d2e68cdb19b2bdd35b49a7d15..3aab53f8cad244ef402d0c03c56c63e112d459a6 100644 (file)
@@ -580,7 +580,7 @@ static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
        ioapic->irr = 0;
        ioapic->irr_delivered = 0;
        ioapic->id = 0;
-       memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS);
+       memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi));
        rtc_irq_eoi_tracking_reset(ioapic);
 }
 
index c146f3c262c3bdd43f83e736688147559a8e9a4f..0149ac59c273c15921bbe2a8cff7d9427e6a0976 100644 (file)
@@ -539,6 +539,7 @@ static void mtrr_lookup_var_start(struct mtrr_iter *iter)
 
        iter->fixed = false;
        iter->start_max = iter->start;
+       iter->range = NULL;
        iter->range = list_prepare_entry(iter->range, &mtrr_state->head, node);
 
        __mtrr_lookup_var_next(iter);
index 41e7943004fe65c8e67f59f591c4a9d802ec3cd6..268df707b5ce8f5d7739e3d23c7ab48f8085941a 100644 (file)
@@ -408,6 +408,7 @@ struct nested_vmx {
        struct list_head vmcs02_pool;
        int vmcs02_num;
        u64 vmcs01_tsc_offset;
+       bool change_vmcs01_virtual_x2apic_mode;
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
        /*
@@ -8124,6 +8125,7 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
        if ((vectoring_info & VECTORING_INFO_VALID_MASK) &&
                        (exit_reason != EXIT_REASON_EXCEPTION_NMI &&
                        exit_reason != EXIT_REASON_EPT_VIOLATION &&
+                       exit_reason != EXIT_REASON_PML_FULL &&
                        exit_reason != EXIT_REASON_TASK_SWITCH)) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_DELIVERY_EV;
@@ -8183,6 +8185,12 @@ static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
 {
        u32 sec_exec_control;
 
+       /* Postpone execution until vmcs01 is the current VMCS. */
+       if (is_guest_mode(vcpu)) {
+               to_vmx(vcpu)->nested.change_vmcs01_virtual_x2apic_mode = true;
+               return;
+       }
+
        /*
         * There is not point to enable virtualize x2apic without enable
         * apicv
@@ -8736,6 +8744,22 @@ static void vmx_load_vmcs01(struct kvm_vcpu *vcpu)
        put_cpu();
 }
 
+/*
+ * Ensure that the current vmcs of the logical processor is the
+ * vmcs01 of the vcpu before calling free_nested().
+ */
+static void vmx_free_vcpu_nested(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int r;
+
+       r = vcpu_load(vcpu);
+       BUG_ON(r);
+       vmx_load_vmcs01(vcpu);
+       free_nested(vmx);
+       vcpu_put(vcpu);
+}
+
 static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -8744,8 +8768,7 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
                vmx_destroy_pml_buffer(vmx);
        free_vpid(vmx->vpid);
        leave_guest_mode(vcpu);
-       vmx_load_vmcs01(vcpu);
-       free_nested(vmx);
+       vmx_free_vcpu_nested(vcpu);
        free_loaded_vmcs(vmx->loaded_vmcs);
        kfree(vmx->guest_msrs);
        kvm_vcpu_uninit(vcpu);
@@ -10467,6 +10490,12 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
        /* Update TSC_OFFSET if TSC was changed while L2 ran */
        vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
 
+       if (vmx->nested.change_vmcs01_virtual_x2apic_mode) {
+               vmx->nested.change_vmcs01_virtual_x2apic_mode = false;
+               vmx_set_virtual_x2apic_mode(vcpu,
+                               vcpu->arch.apic_base & X2APIC_ENABLE);
+       }
+
        /* This is needed for same reason as it was needed in prepare_vmcs02 */
        vmx->host_rsp = 0;
 
index be222666b1c2554c18f179766cc72c98c1d9b2d8..d7cb9577fa31fbe0f06e305933c0caf6c9645eb0 100644 (file)
@@ -2735,7 +2735,6 @@ 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)
index 72bb52f93c3d619d0dc6c0355b7ab293a24c3199..d2dc0438d654a8bbcfc71583cea8f49f693afcff 100644 (file)
@@ -93,18 +93,6 @@ static unsigned long mmap_base(unsigned long rnd)
        return PAGE_ALIGN(TASK_SIZE - gap - rnd);
 }
 
-/*
- * Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64
- * does, but not when emulating X86_32
- */
-static unsigned long mmap_legacy_base(unsigned long rnd)
-{
-       if (mmap_is_ia32())
-               return TASK_UNMAPPED_BASE;
-       else
-               return TASK_UNMAPPED_BASE + rnd;
-}
-
 /*
  * This function, called very early during the creation of a new
  * process VM image, sets up which VM layout function to use:
@@ -116,7 +104,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
        if (current->flags & PF_RANDOMIZE)
                random_factor = arch_mmap_rnd();
 
-       mm->mmap_legacy_base = mmap_legacy_base(random_factor);
+       mm->mmap_legacy_base = TASK_UNMAPPED_BASE + random_factor;
 
        if (mmap_is_legacy()) {
                mm->mmap_base = mm->mmap_legacy_base;
index 188e3e07eeeba7c0eb6555c138a16e97c3e5d787..6ad687d104cafb360c26cb1110c8fdf45fa43680 100644 (file)
 static bool boot_cpu_done;
 
 static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
+static void init_cache_modes(void);
 
-static inline void pat_disable(const char *reason)
+void pat_disable(const char *reason)
 {
+       if (!__pat_enabled)
+               return;
+
+       if (boot_cpu_done) {
+               WARN_ONCE(1, "x86/PAT: PAT cannot be disabled after initialization\n");
+               return;
+       }
+
        __pat_enabled = 0;
        pr_info("x86/PAT: %s\n", reason);
+
+       init_cache_modes();
 }
 
 static int __init nopat(char *str)
@@ -180,7 +191,7 @@ static enum page_cache_mode pat_get_cache_mode(unsigned pat_val, char *msg)
  * configuration.
  * Using lower indices is preferred, so we start with highest index.
  */
-void pat_init_cache_modes(u64 pat)
+static void __init_cache_modes(u64 pat)
 {
        enum page_cache_mode cache;
        char pat_msg[33];
@@ -201,14 +212,11 @@ static void pat_bsp_init(u64 pat)
 {
        u64 tmp_pat;
 
-       if (!cpu_has_pat) {
+       if (!boot_cpu_has(X86_FEATURE_PAT)) {
                pat_disable("PAT not supported by CPU.");
                return;
        }
 
-       if (!pat_enabled())
-               goto done;
-
        rdmsrl(MSR_IA32_CR_PAT, tmp_pat);
        if (!tmp_pat) {
                pat_disable("PAT MSR is 0, disabled.");
@@ -217,16 +225,12 @@ static void pat_bsp_init(u64 pat)
 
        wrmsrl(MSR_IA32_CR_PAT, pat);
 
-done:
-       pat_init_cache_modes(pat);
+       __init_cache_modes(pat);
 }
 
 static void pat_ap_init(u64 pat)
 {
-       if (!pat_enabled())
-               return;
-
-       if (!cpu_has_pat) {
+       if (!boot_cpu_has(X86_FEATURE_PAT)) {
                /*
                 * If this happens we are on a secondary CPU, but switched to
                 * PAT on the boot CPU. We have no way to undo PAT.
@@ -237,18 +241,32 @@ static void pat_ap_init(u64 pat)
        wrmsrl(MSR_IA32_CR_PAT, pat);
 }
 
-void pat_init(void)
+static void init_cache_modes(void)
 {
-       u64 pat;
-       struct cpuinfo_x86 *c = &boot_cpu_data;
+       u64 pat = 0;
+       static int init_cm_done;
 
-       if (!pat_enabled()) {
+       if (init_cm_done)
+               return;
+
+       if (boot_cpu_has(X86_FEATURE_PAT)) {
+               /*
+                * CPU supports PAT. Set PAT table to be consistent with
+                * PAT MSR. This case supports "nopat" boot option, and
+                * virtual machine environments which support PAT without
+                * MTRRs. In specific, Xen has unique setup to PAT MSR.
+                *
+                * If PAT MSR returns 0, it is considered invalid and emulates
+                * as No PAT.
+                */
+               rdmsrl(MSR_IA32_CR_PAT, pat);
+       }
+
+       if (!pat) {
                /*
                 * No PAT. Emulate the PAT table that corresponds to the two
-                * cache bits, PWT (Write Through) and PCD (Cache Disable). This
-                * setup is the same as the BIOS default setup when the system
-                * has PAT but the "nopat" boot option has been specified. This
-                * emulated PAT table is used when MSR_IA32_CR_PAT returns 0.
+                * cache bits, PWT (Write Through) and PCD (Cache Disable).
+                * This setup is also the same as the BIOS default setup.
                 *
                 * PTE encoding:
                 *
@@ -265,10 +283,36 @@ void pat_init(void)
                 */
                pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) |
                      PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC);
+       }
+
+       __init_cache_modes(pat);
+
+       init_cm_done = 1;
+}
+
+/**
+ * pat_init - Initialize PAT MSR and PAT table
+ *
+ * This function initializes PAT MSR and PAT table with an OS-defined value
+ * to enable additional cache attributes, WC and WT.
+ *
+ * This function must be called on all CPUs using the specific sequence of
+ * operations defined in Intel SDM. mtrr_rendezvous_handler() provides this
+ * procedure for PAT.
+ */
+void pat_init(void)
+{
+       u64 pat;
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+
+       if (!pat_enabled()) {
+               init_cache_modes();
+               return;
+       }
 
-       } else if ((c->x86_vendor == X86_VENDOR_INTEL) &&
-                  (((c->x86 == 0x6) && (c->x86_model <= 0xd)) ||
-                   ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) {
+       if ((c->x86_vendor == X86_VENDOR_INTEL) &&
+           (((c->x86 == 0x6) && (c->x86_model <= 0xd)) ||
+            ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) {
                /*
                 * PAT support with the lower four entries. Intel Pentium 2,
                 * 3, M, and 4 are affected by PAT errata, which makes the
@@ -733,25 +777,6 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
        if (file->f_flags & O_DSYNC)
                pcm = _PAGE_CACHE_MODE_UC_MINUS;
 
-#ifdef CONFIG_X86_32
-       /*
-        * On the PPro and successors, the MTRRs are used to set
-        * memory types for physical addresses outside main memory,
-        * so blindly setting UC or PWT on those pages is wrong.
-        * For Pentiums and earlier, the surround logic should disable
-        * caching for the high addresses through the KEN pin, but
-        * we maintain the tradition of paranoia in this code.
-        */
-       if (!pat_enabled() &&
-           !(boot_cpu_has(X86_FEATURE_MTRR) ||
-             boot_cpu_has(X86_FEATURE_K6_MTRR) ||
-             boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
-             boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) &&
-           (pfn << PAGE_SHIFT) >= __pa(high_memory)) {
-               pcm = _PAGE_CACHE_MODE_UC;
-       }
-#endif
-
        *vma_prot = __pgprot((pgprot_val(*vma_prot) & ~_PAGE_CACHE_MASK) |
                             cachemode2protval(pcm));
        return 1;
index 8b93e634af84c4698e6f7c6ab718a018e2cdc9db..ae97f24a4371c5d224871d3c9ce407f3dfa75c63 100644 (file)
@@ -37,6 +37,7 @@
 
 /* Quirks for the listed devices */
 #define PCI_DEVICE_ID_INTEL_MRFL_MMC   0x1190
+#define PCI_DEVICE_ID_INTEL_MRFL_HSU   0x1191
 
 /* Fixed BAR fields */
 #define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00        /* Fixed BAR (TBD) */
@@ -224,14 +225,21 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
                /* Special treatment for IRQ0 */
                if (dev->irq == 0) {
+                       /*
+                        * Skip HS UART common registers device since it has
+                        * IRQ0 assigned and not used by the kernel.
+                        */
+                       if (dev->device == PCI_DEVICE_ID_INTEL_MRFL_HSU)
+                               return -EBUSY;
                        /*
                         * TNG has IRQ0 assigned to eMMC controller. But there
                         * are also other devices with bogus PCI configuration
                         * that have IRQ0 assigned. This check ensures that
-                        * eMMC gets it.
+                        * eMMC gets it. The rest of devices still could be
+                        * enabled without interrupt line being allocated.
                         */
                        if (dev->device != PCI_DEVICE_ID_INTEL_MRFL_MMC)
-                               return -EBUSY;
+                               return 0;
                }
                break;
        default:
index beab8c706ac95070f02b683df74b056f0d53ca64..ffa41591bff92fa7200d47a51265458ffeb8b031 100644 (file)
@@ -74,7 +74,6 @@
 #include <asm/mach_traps.h>
 #include <asm/mwait.h>
 #include <asm/pci_x86.h>
-#include <asm/pat.h>
 #include <asm/cpu.h>
 
 #ifdef CONFIG_ACPI
@@ -1519,7 +1518,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
 {
        struct physdev_set_iopl set_iopl;
        unsigned long initrd_start = 0;
-       u64 pat;
        int rc;
 
        if (!xen_start_info)
@@ -1627,13 +1625,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
                                   xen_start_info->nr_pages);
        xen_reserve_special_pages();
 
-       /*
-        * Modify the cache mode translation tables to match Xen's PAT
-        * configuration.
-        */
-       rdmsrl(MSR_IA32_CR_PAT, pat);
-       pat_init_cache_modes(pat);
-
        /* keep using Xen gdt for now; no urgent need to change it */
 
 #ifdef CONFIG_X86_32
diff --git a/backported-features b/backported-features
new file mode 100644 (file)
index 0000000..b680ed4
--- /dev/null
@@ -0,0 +1,14 @@
+               LSK backported features
+
+1, The kaslr and kaslr-pax_usercopy branches base on LSK directly.
+       v4.4/topic/mm-kaslr
+       v4.4/topic/mm-kaslr-pax_usercopy
+
+2, Coresight and openCSD are used for Juno board 'perf' tool implement.
+       origin/v4.4/topic/coresight
+       origin/v4.4/topic/perf-opencsd-4.4-github
+
+3, OPTEE base on LSK mainline, but isn't included of mainline.
+
+Feature introducation:
+https://wiki.linaro.org/lsk/features
index d4d144363250f7dfe2e2ed41ed9fca7425c18c0a..46e2cc1d4016e450dff6273f6ef8ee8755985848 100644 (file)
@@ -584,6 +584,8 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
        bio->bi_rw = bio_src->bi_rw;
        bio->bi_iter = bio_src->bi_iter;
        bio->bi_io_vec = bio_src->bi_io_vec;
+
+       bio_clone_blkcg_association(bio, bio_src);
 }
 EXPORT_SYMBOL(__bio_clone_fast);
 
@@ -689,6 +691,8 @@ integrity_clone:
                }
        }
 
+       bio_clone_blkcg_association(bio, bio_src);
+
        return bio;
 }
 EXPORT_SYMBOL(bio_clone_bioset);
@@ -2014,6 +2018,17 @@ void bio_disassociate_task(struct bio *bio)
        }
 }
 
+/**
+ * bio_clone_blkcg_association - clone blkcg association from src to dst bio
+ * @dst: destination bio
+ * @src: source bio
+ */
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src)
+{
+       if (src->bi_css)
+               WARN_ON(bio_associate_blkcg(dst, src->bi_css));
+}
+
 #endif /* CONFIG_BLK_CGROUP */
 
 static void __init biovec_init_slabs(void)
index 5a37188b559fba8feb1da48b00d5290c3a6a09b6..9d359e05fad74d0a2f2a9a64ef3aeeb40bb3a7d6 100644 (file)
@@ -1331,10 +1331,8 @@ int blkcg_policy_register(struct blkcg_policy *pol)
                        struct blkcg_policy_data *cpd;
 
                        cpd = pol->cpd_alloc_fn(GFP_KERNEL);
-                       if (!cpd) {
-                               mutex_unlock(&blkcg_pol_mutex);
+                       if (!cpd)
                                goto err_free_cpds;
-                       }
 
                        blkcg->cpd[pol->plid] = cpd;
                        cpd->blkcg = blkcg;
index f8e64cac981ae4cb8d5e7860eeef257d53d8ce53..25f25271b42a50b00b8d02c969b038d0b4bf5573 100644 (file)
@@ -40,6 +40,8 @@
 #include "blk.h"
 #include "blk-mq.h"
 
+#include <linux/math64.h>
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
@@ -515,7 +517,9 @@ EXPORT_SYMBOL_GPL(blk_queue_bypass_end);
 
 void blk_set_queue_dying(struct request_queue *q)
 {
-       queue_flag_set_unlocked(QUEUE_FLAG_DYING, q);
+       spin_lock_irq(q->queue_lock);
+       queue_flag_set(QUEUE_FLAG_DYING, q);
+       spin_unlock_irq(q->queue_lock);
 
        if (q->mq_ops)
                blk_mq_wake_waiters(q);
@@ -3539,3 +3543,85 @@ int __init blk_dev_init(void)
 
        return 0;
 }
+
+/*
+ * Blk IO latency support. We want this to be as cheap as possible, so doing
+ * this lockless (and avoiding atomics), a few off by a few errors in this
+ * code is not harmful, and we don't want to do anything that is
+ * perf-impactful.
+ * TODO : If necessary, we can make the histograms per-cpu and aggregate
+ * them when printing them out.
+ */
+void
+blk_zero_latency_hist(struct io_latency_state *s)
+{
+       memset(s->latency_y_axis_read, 0,
+              sizeof(s->latency_y_axis_read));
+       memset(s->latency_y_axis_write, 0,
+              sizeof(s->latency_y_axis_write));
+       s->latency_reads_elems = 0;
+       s->latency_writes_elems = 0;
+}
+EXPORT_SYMBOL(blk_zero_latency_hist);
+
+ssize_t
+blk_latency_hist_show(struct io_latency_state *s, char *buf)
+{
+       int i;
+       int bytes_written = 0;
+       u_int64_t num_elem, elem;
+       int pct;
+
+       num_elem = s->latency_reads_elems;
+       if (num_elem > 0) {
+               bytes_written += scnprintf(buf + bytes_written,
+                          PAGE_SIZE - bytes_written,
+                          "IO svc_time Read Latency Histogram (n = %llu):\n",
+                          num_elem);
+               for (i = 0;
+                    i < ARRAY_SIZE(latency_x_axis_us);
+                    i++) {
+                       elem = s->latency_y_axis_read[i];
+                       pct = div64_u64(elem * 100, num_elem);
+                       bytes_written += scnprintf(buf + bytes_written,
+                                                  PAGE_SIZE - bytes_written,
+                                                  "\t< %5lluus%15llu%15d%%\n",
+                                                  latency_x_axis_us[i],
+                                                  elem, pct);
+               }
+               /* Last element in y-axis table is overflow */
+               elem = s->latency_y_axis_read[i];
+               pct = div64_u64(elem * 100, num_elem);
+               bytes_written += scnprintf(buf + bytes_written,
+                                          PAGE_SIZE - bytes_written,
+                                          "\t> %5dms%15llu%15d%%\n", 10,
+                                          elem, pct);
+       }
+       num_elem = s->latency_writes_elems;
+       if (num_elem > 0) {
+               bytes_written += scnprintf(buf + bytes_written,
+                          PAGE_SIZE - bytes_written,
+                          "IO svc_time Write Latency Histogram (n = %llu):\n",
+                          num_elem);
+               for (i = 0;
+                    i < ARRAY_SIZE(latency_x_axis_us);
+                    i++) {
+                       elem = s->latency_y_axis_write[i];
+                       pct = div64_u64(elem * 100, num_elem);
+                       bytes_written += scnprintf(buf + bytes_written,
+                                                  PAGE_SIZE - bytes_written,
+                                                  "\t< %5lluus%15llu%15d%%\n",
+                                                  latency_x_axis_us[i],
+                                                  elem, pct);
+               }
+               /* Last element in y-axis table is overflow */
+               elem = s->latency_y_axis_write[i];
+               pct = div64_u64(elem * 100, num_elem);
+               bytes_written += scnprintf(buf + bytes_written,
+                                          PAGE_SIZE - bytes_written,
+                                          "\t> %5dms%15llu%15d%%\n", 10,
+                                          elem, pct);
+       }
+       return bytes_written;
+}
+EXPORT_SYMBOL(blk_latency_hist_show);
index b966db8f35569fbf970a787e583333bb84b8ec91..7225511cf0b48b1644ef3c56bf77d1f58e4911ca 100644 (file)
@@ -92,8 +92,30 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
        bool do_split = true;
        struct bio *new = NULL;
        const unsigned max_sectors = get_max_io_size(q, bio);
+       unsigned bvecs = 0;
 
        bio_for_each_segment(bv, bio, iter) {
+               /*
+                * With arbitrary bio size, the incoming bio may be very
+                * big. We have to split the bio into small bios so that
+                * each holds at most BIO_MAX_PAGES bvecs because
+                * bio_clone() can fail to allocate big bvecs.
+                *
+                * It should have been better to apply the limit per
+                * request queue in which bio_clone() is involved,
+                * instead of globally. The biggest blocker is the
+                * bio_clone() in bio bounce.
+                *
+                * If bio is splitted by this reason, we should have
+                * allowed to continue bios merging, but don't do
+                * that now for making the change simple.
+                *
+                * TODO: deal with bio bounce's bio_clone() gracefully
+                * and convert the global limit into per-queue limit.
+                */
+               if (bvecs++ >= BIO_MAX_PAGES)
+                       goto split;
+
                /*
                 * If the queue doesn't support SG gaps and adding this
                 * offset would create a gap, disallow it.
index 6d6f8feb48c08ab875e67c496193a743709b0621..c3e461ec40e4c9ceeb7b0595bf088957354ce752 100644 (file)
@@ -601,8 +601,10 @@ static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx,
                 * If a request wasn't started before the queue was
                 * marked dying, kill it here or it'll go unnoticed.
                 */
-               if (unlikely(blk_queue_dying(rq->q)))
-                       blk_mq_complete_request(rq, -EIO);
+               if (unlikely(blk_queue_dying(rq->q))) {
+                       rq->errors = -EIO;
+                       blk_mq_end_request(rq, rq->errors);
+               }
                return;
        }
        if (rq->cmd_flags & REQ_NO_TIMEOUT)
@@ -778,7 +780,7 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
                switch (ret) {
                case BLK_MQ_RQ_QUEUE_OK:
                        queued++;
-                       continue;
+                       break;
                case BLK_MQ_RQ_QUEUE_BUSY:
                        list_add(&rq->queuelist, &rq_list);
                        __blk_mq_requeue_request(rq);
index 1f9093e901daed7849a54633be5d80ce96b010f4..3ad307ee602903e94b500008001359bc40bfebe8 100644 (file)
@@ -3003,7 +3003,6 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
        if (time_before(jiffies, rq->fifo_time))
                rq = NULL;
 
-       cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
        return rq;
 }
 
@@ -3377,6 +3376,9 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned int max_dispatch;
 
+       if (cfq_cfqq_must_dispatch(cfqq))
+               return true;
+
        /*
         * Drain async requests before we start sync IO
         */
@@ -3468,15 +3470,20 @@ static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
        BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
 
+       rq = cfq_check_fifo(cfqq);
+       if (rq)
+               cfq_mark_cfqq_must_dispatch(cfqq);
+
        if (!cfq_may_dispatch(cfqd, cfqq))
                return false;
 
        /*
         * follow expired path, else get first next available
         */
-       rq = cfq_check_fifo(cfqq);
        if (!rq)
                rq = cfqq->next_rq;
+       else
+               cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
 
        /*
         * insert request into driver dispatch list
@@ -3944,7 +3951,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
         * if the new request is sync, but the currently running queue is
         * not, let the sync request have priority.
         */
-       if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
+       if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq) && !cfq_cfqq_must_dispatch(cfqq))
                return true;
 
        if (new_cfqq->cfqg != cfqq->cfqg)
index 817c67c9e45e3966623b028f0d3d8722e4ebac1e..fad9db981675c8a0f753127eb5dfa0f40dc881a4 100644 (file)
@@ -612,7 +612,7 @@ void add_disk(struct gendisk *disk)
 
        /* Register BDI before referencing it from bdev */
        bdi = &disk->queue->backing_dev_info;
-       bdi_register_dev(bdi, disk_devt(disk));
+       bdi_register_owner(bdi, disk_to_dev(disk));
 
        blk_register_region(disk_devt(disk), disk->minors, NULL,
                            exact_match, exact_lock, disk);
@@ -831,6 +831,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
        if (iter) {
                class_dev_iter_exit(iter);
                kfree(iter);
+               seqf->private = NULL;
        }
 }
 
index cc7800e9eb441e2b7737a152f0dbb60182821408..01b8116298a13b5463e7969ce66c0b037bcfccd5 100644 (file)
@@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p)
        if (ret)
                goto out;
        ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
+       task_lock(p);
        if (p->io_context)
                ret = p->io_context->ioprio;
+       task_unlock(p);
 out:
        return ret;
 }
index 758acabf2d819727ecd7f4cf0c6aa21c1c40649f..8f3056cd03991ddf820c3d8442d35daf3db7ee84 100644 (file)
@@ -547,9 +547,7 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
        struct pkcs7_signed_info *sinfo = ctx->sinfo;
 
        if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
-           !test_bit(sinfo_has_message_digest, &sinfo->aa_set) ||
-           (ctx->msg->data_type == OID_msIndirectData &&
-            !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) {
+           !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
                pr_warn("Missing required AuthAttr\n");
                return -EBADMSG;
        }
index c0748bbd4c083b47f78c662cdd7cb490590a2587..84f8d4d8b6bc8c3f54d4ae2ef90bb6e8d693e570 100644 (file)
@@ -368,8 +368,6 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
 
                dma_set_unmap(tx, unmap);
                async_tx_submit(chan, tx, submit);
-
-               return tx;
        } else {
                struct page *p_src = P(blocks, disks);
                struct page *q_src = Q(blocks, disks);
@@ -424,9 +422,11 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
                submit->cb_param = cb_param_orig;
                submit->flags = flags_orig;
                async_tx_sync_epilog(submit);
-
-               return NULL;
+               tx = NULL;
        }
+       dmaengine_unmap_put(unmap);
+
+       return tx;
 }
 EXPORT_SYMBOL_GPL(async_syndrome_val);
 
index 8cc1622b2ee008ef7f5ff31a3ea7d8777f3f5f1b..dca7bc87dad9d326e39d44d1b62baad5006460da 100644 (file)
@@ -234,6 +234,8 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc,
                return blkcipher_walk_done(desc, walk, -EINVAL);
        }
 
+       bsize = min(walk->walk_blocksize, n);
+
        walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY |
                         BLKCIPHER_WALK_DIFF);
        if (!scatterwalk_aligned(&walk->in, walk->alignmask) ||
@@ -246,7 +248,6 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc,
                }
        }
 
-       bsize = min(walk->walk_blocksize, n);
        n = scatterwalk_clamp(&walk->in, n);
        n = scatterwalk_clamp(&walk->out, n);
 
index c81861b1350b60a1c2def7695dd16d7b0db39ade..e7aa904cb20bae034cf9520c5f67fe7da0358cda 100644 (file)
@@ -594,9 +594,14 @@ static int cryptd_hash_export(struct ahash_request *req, void *out)
 
 static int cryptd_hash_import(struct ahash_request *req, const void *in)
 {
-       struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+       struct cryptd_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+       struct shash_desc *desc = cryptd_shash_desc(req);
+
+       desc->tfm = ctx->child;
+       desc->flags = req->base.flags;
 
-       return crypto_shash_import(&rctx->desc, in);
+       return crypto_shash_import(desc, in);
 }
 
 static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
index b96a84560b67790845321250e1f1a799557bb4b8..343a74e96e2a2fea2285c59e8e340b9cc87e3c72 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * echainiv: Encrypted Chain IV Generator
  *
- * This generator generates an IV based on a sequence number by xoring it
- * with a salt and then encrypting it with the same key as used to encrypt
+ * This generator generates an IV based on a sequence number by multiplying
+ * it with a salt and then encrypting it with the same key as used to encrypt
  * the plain text.  This algorithm requires that the block size be equal
  * to the IV size.  It is mainly useful for CBC.
  *
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/percpu.h>
-#include <linux/spinlock.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 
-#define MAX_IV_SIZE 16
-
-static DEFINE_PER_CPU(u32 [MAX_IV_SIZE / sizeof(u32)], echainiv_iv);
-
-/* We don't care if we get preempted and read/write IVs from the next CPU. */
-static void echainiv_read_iv(u8 *dst, unsigned size)
-{
-       u32 *a = (u32 *)dst;
-       u32 __percpu *b = echainiv_iv;
-
-       for (; size >= 4; size -= 4) {
-               *a++ = this_cpu_read(*b);
-               b++;
-       }
-}
-
-static void echainiv_write_iv(const u8 *src, unsigned size)
-{
-       const u32 *a = (const u32 *)src;
-       u32 __percpu *b = echainiv_iv;
-
-       for (; size >= 4; size -= 4) {
-               this_cpu_write(*b, *a);
-               a++;
-               b++;
-       }
-}
-
-static void echainiv_encrypt_complete2(struct aead_request *req, int err)
-{
-       struct aead_request *subreq = aead_request_ctx(req);
-       struct crypto_aead *geniv;
-       unsigned int ivsize;
-
-       if (err == -EINPROGRESS)
-               return;
-
-       if (err)
-               goto out;
-
-       geniv = crypto_aead_reqtfm(req);
-       ivsize = crypto_aead_ivsize(geniv);
-
-       echainiv_write_iv(subreq->iv, ivsize);
-
-       if (req->iv != subreq->iv)
-               memcpy(req->iv, subreq->iv, ivsize);
-
-out:
-       if (req->iv != subreq->iv)
-               kzfree(subreq->iv);
-}
-
-static void echainiv_encrypt_complete(struct crypto_async_request *base,
-                                        int err)
-{
-       struct aead_request *req = base->data;
-
-       echainiv_encrypt_complete2(req, err);
-       aead_request_complete(req, err);
-}
-
 static int echainiv_encrypt(struct aead_request *req)
 {
        struct crypto_aead *geniv = crypto_aead_reqtfm(req);
        struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
        struct aead_request *subreq = aead_request_ctx(req);
-       crypto_completion_t compl;
-       void *data;
+       __be64 nseqno;
+       u64 seqno;
        u8 *info;
        unsigned int ivsize = crypto_aead_ivsize(geniv);
        int err;
@@ -107,8 +43,6 @@ static int echainiv_encrypt(struct aead_request *req)
 
        aead_request_set_tfm(subreq, ctx->child);
 
-       compl = echainiv_encrypt_complete;
-       data = req;
        info = req->iv;
 
        if (req->src != req->dst) {
@@ -123,29 +57,30 @@ static int echainiv_encrypt(struct aead_request *req)
                        return err;
        }
 
-       if (unlikely(!IS_ALIGNED((unsigned long)info,
-                                crypto_aead_alignmask(geniv) + 1))) {
-               info = kmalloc(ivsize, req->base.flags &
-                                      CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
-                                                                 GFP_ATOMIC);
-               if (!info)
-                       return -ENOMEM;
-
-               memcpy(info, req->iv, ivsize);
-       }
-
-       aead_request_set_callback(subreq, req->base.flags, compl, data);
+       aead_request_set_callback(subreq, req->base.flags,
+                                 req->base.complete, req->base.data);
        aead_request_set_crypt(subreq, req->dst, req->dst,
                               req->cryptlen, info);
        aead_request_set_ad(subreq, req->assoclen);
 
-       crypto_xor(info, ctx->salt, ivsize);
+       memcpy(&nseqno, info + ivsize - 8, 8);
+       seqno = be64_to_cpu(nseqno);
+       memset(info, 0, ivsize);
+
        scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
-       echainiv_read_iv(info, ivsize);
 
-       err = crypto_aead_encrypt(subreq);
-       echainiv_encrypt_complete2(req, err);
-       return err;
+       do {
+               u64 a;
+
+               memcpy(&a, ctx->salt + ivsize - 8, 8);
+
+               a |= 1;
+               a *= seqno;
+
+               memcpy(info + ivsize - 8, &a, 8);
+       } while ((ivsize -= 8));
+
+       return crypto_aead_encrypt(subreq);
 }
 
 static int echainiv_decrypt(struct aead_request *req)
@@ -192,8 +127,7 @@ static int echainiv_aead_create(struct crypto_template *tmpl,
        alg = crypto_spawn_aead_alg(spawn);
 
        err = -EINVAL;
-       if (inst->alg.ivsize & (sizeof(u32) - 1) ||
-           inst->alg.ivsize > MAX_IV_SIZE)
+       if (inst->alg.ivsize & (sizeof(u64) - 1) || !inst->alg.ivsize)
                goto free_inst;
 
        inst->alg.encrypt = echainiv_encrypt;
@@ -202,7 +136,6 @@ static int echainiv_aead_create(struct crypto_template *tmpl,
        inst->alg.init = aead_init_geniv;
        inst->alg.exit = aead_exit_geniv;
 
-       inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
        inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
        inst->alg.base.cra_ctxsize += inst->alg.ivsize;
 
index bec329b3de8d7f2e51ed3bf2d91afcdbe4678e8d..1238b3c5a321984c0414dc283bf9891764762e6a 100644 (file)
@@ -117,7 +117,7 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
        struct crypto_ablkcipher *ctr = ctx->ctr;
        struct {
                be128 hash;
-               u8 iv[8];
+               u8 iv[16];
 
                struct crypto_gcm_setkey_result result;
 
@@ -639,7 +639,9 @@ static int crypto_gcm_create_common(struct crypto_template *tmpl,
 
        ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
                                    CRYPTO_ALG_TYPE_HASH,
-                                   CRYPTO_ALG_TYPE_AHASH_MASK);
+                                   CRYPTO_ALG_TYPE_AHASH_MASK |
+                                   crypto_requires_sync(algt->type,
+                                                        algt->mask));
        if (IS_ERR(ghash_alg))
                return PTR_ERR(ghash_alg);
 
index bac70995e0640a49fbc56797c4f7b605791ff98b..12ad3e3a84e3d7d570e75fad4c521718a3bf9790 100644 (file)
 
 #include <crypto/algapi.h>
 #include <crypto/gf128mul.h>
+#include <crypto/ghash.h>
 #include <crypto/internal/hash.h>
 #include <linux/crypto.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
-#define GHASH_BLOCK_SIZE       16
-#define GHASH_DIGEST_SIZE      16
-
-struct ghash_ctx {
-       struct gf128mul_4k *gf128;
-};
-
-struct ghash_desc_ctx {
-       u8 buffer[GHASH_BLOCK_SIZE];
-       u32 bytes;
-};
-
 static int ghash_init(struct shash_desc *desc)
 {
        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
index ea5815c5e12817912e1749d6aaf1a84606d7e7f3..bc769c448d4a9829c0733ca3adbd1dc04bd5afec 100644 (file)
@@ -72,7 +72,8 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
 
 void scatterwalk_done(struct scatter_walk *walk, int out, int more)
 {
-       if (!(scatterwalk_pagelen(walk) & (PAGE_SIZE - 1)) || !more)
+       if (!more || walk->offset >= walk->sg->offset + walk->sg->length ||
+           !(walk->offset & (PAGE_SIZE - 1)))
                scatterwalk_pagedone(walk, out, more);
 }
 EXPORT_SYMBOL_GPL(scatterwalk_done);
index 5f97468df8ff04e6bf0856a7b64324c16992cfb8..b2e50d8007fe6fa20a9a1ea5809292175a4a3dbf 100644 (file)
@@ -504,11 +504,20 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
         * Evaluate the \_Sx namespace object containing the register values
         * for this state
         */
-       info->relative_pathname =
-           ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
+       info->relative_pathname = ACPI_CAST_PTR(char,
+                                               acpi_gbl_sleep_state_names
+                                               [sleep_state]);
+
        status = acpi_ns_evaluate(info);
        if (ACPI_FAILURE(status)) {
-               goto cleanup;
+               if (status == AE_NOT_FOUND) {
+
+                       /* The _Sx states are optional, ignore NOT_FOUND */
+
+                       goto final_cleanup;
+               }
+
+               goto warning_cleanup;
        }
 
        /* Must have a return object */
@@ -517,7 +526,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
                ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
                            info->relative_pathname));
                status = AE_AML_NO_RETURN_VALUE;
-               goto cleanup;
+               goto warning_cleanup;
        }
 
        /* Return object must be of type Package */
@@ -526,7 +535,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
                ACPI_ERROR((AE_INFO,
                            "Sleep State return object is not a Package"));
                status = AE_AML_OPERAND_TYPE;
-               goto cleanup1;
+               goto return_value_cleanup;
        }
 
        /*
@@ -570,16 +579,17 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
                break;
        }
 
-cleanup1:
+return_value_cleanup:
        acpi_ut_remove_reference(info->return_object);
 
-cleanup:
+warning_cleanup:
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status,
                                "While evaluating Sleep State [%s]",
                                info->relative_pathname));
        }
 
+final_cleanup:
        ACPI_FREE(info);
        return_ACPI_STATUS(status);
 }
index 6730f965b3793f25ba73125a00b18f346decf75f..0afd1981e350b070484252e6a8d66ceb3162d9b8 100644 (file)
@@ -216,8 +216,10 @@ int acpi_get_psd_map(struct cpudata **all_cpu_data)
                        continue;
 
                cpc_ptr = per_cpu(cpc_desc_ptr, i);
-               if (!cpc_ptr)
-                       continue;
+               if (!cpc_ptr) {
+                       retval = -EFAULT;
+                       goto err_ret;
+               }
 
                pdomain = &(cpc_ptr->domain_info);
                cpumask_set_cpu(i, pr->shared_cpu_map);
@@ -239,8 +241,10 @@ int acpi_get_psd_map(struct cpudata **all_cpu_data)
                                continue;
 
                        match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
-                       if (!match_cpc_ptr)
-                               continue;
+                       if (!match_cpc_ptr) {
+                               retval = -EFAULT;
+                               goto err_ret;
+                       }
 
                        match_pdomain = &(match_cpc_ptr->domain_info);
                        if (match_pdomain->domain != pdomain->domain)
@@ -270,8 +274,10 @@ int acpi_get_psd_map(struct cpudata **all_cpu_data)
                                continue;
 
                        match_cpc_ptr = per_cpu(cpc_desc_ptr, j);
-                       if (!match_cpc_ptr)
-                               continue;
+                       if (!match_cpc_ptr) {
+                               retval = -EFAULT;
+                               goto err_ret;
+                       }
 
                        match_pdomain = &(match_cpc_ptr->domain_info);
                        if (match_pdomain->domain != pdomain->domain)
@@ -502,9 +508,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        /* Store CPU Logical ID */
        cpc_ptr->cpu_id = pr->id;
 
-       /* Plug it into this CPUs CPC descriptor. */
-       per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
-
        /* Parse PSD data for this CPU */
        ret = acpi_get_psd(cpc_ptr, handle);
        if (ret)
@@ -517,6 +520,9 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                        goto out_free;
        }
 
+       /* Plug PSD data into this CPUs CPC descriptor. */
+       per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
+
        /* Everything looks okay */
        pr_debug("Parsed CPC struct for CPU: %d\n", pr->id);
 
index b420fb46669dd698c4d346559c325c0f4afeaf4d..43f20328f830ec7b6f178cd07af91818ad674260 100644 (file)
@@ -101,6 +101,7 @@ enum ec_command {
 #define ACPI_EC_UDELAY_POLL    550     /* Wait 1ms for EC transaction polling */
 #define ACPI_EC_CLEAR_MAX      100     /* Maximum number of events to query
                                         * when trying to clear the EC */
+#define ACPI_EC_MAX_QUERIES    16      /* Maximum number of parallel queries */
 
 enum {
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
@@ -121,6 +122,10 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
 module_param(ec_delay, uint, 0644);
 MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
 
+static unsigned int ec_max_queries __read_mostly = ACPI_EC_MAX_QUERIES;
+module_param(ec_max_queries, uint, 0644);
+MODULE_PARM_DESC(ec_max_queries, "Maximum parallel _Qxx evaluations");
+
 static bool ec_busy_polling __read_mostly;
 module_param(ec_busy_polling, bool, 0644);
 MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
@@ -174,6 +179,7 @@ static void acpi_ec_event_processor(struct work_struct *work);
 
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
+static struct workqueue_struct *ec_query_wq;
 
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
 static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
@@ -1097,7 +1103,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
         * work queue execution.
         */
        ec_dbg_evt("Query(0x%02x) scheduled", value);
-       if (!schedule_work(&q->work)) {
+       if (!queue_work(ec_query_wq, &q->work)) {
                ec_dbg_evt("Query(0x%02x) overlapped", value);
                result = -EBUSY;
        }
@@ -1657,15 +1663,41 @@ static struct acpi_driver acpi_ec_driver = {
                },
 };
 
+static inline int acpi_ec_query_init(void)
+{
+       if (!ec_query_wq) {
+               ec_query_wq = alloc_workqueue("kec_query", 0,
+                                             ec_max_queries);
+               if (!ec_query_wq)
+                       return -ENODEV;
+       }
+       return 0;
+}
+
+static inline void acpi_ec_query_exit(void)
+{
+       if (ec_query_wq) {
+               destroy_workqueue(ec_query_wq);
+               ec_query_wq = NULL;
+       }
+}
+
 int __init acpi_ec_init(void)
 {
-       int result = 0;
+       int result;
 
+       /* register workqueue for _Qxx evaluations */
+       result = acpi_ec_query_init();
+       if (result)
+               goto err_exit;
        /* Now register the driver for the EC */
        result = acpi_bus_register_driver(&acpi_ec_driver);
-       if (result < 0)
-               return -ENODEV;
+       if (result)
+               goto err_exit;
 
+err_exit:
+       if (result)
+               acpi_ec_query_exit();
        return result;
 }
 
@@ -1675,5 +1707,6 @@ static void __exit acpi_ec_exit(void)
 {
 
        acpi_bus_unregister_driver(&acpi_ec_driver);
+       acpi_ec_query_exit();
 }
 #endif /* 0 */
index 11d8209e6e5d12972c0c86fcf0fa1b506ab46232..c097f477c74c19a75c9300d6e99306c4479f35a5 100644 (file)
@@ -1072,11 +1072,12 @@ static u32 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
 {
        struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
        u64 offset = nfit_blk->stat_offset + mmio->size * bw;
+       const u32 STATUS_MASK = 0x80000037;
 
        if (mmio->num_lines)
                offset = to_interleave_offset(offset, mmio);
 
-       return readl(mmio->addr.base + offset);
+       return readl(mmio->addr.base + offset) & STATUS_MASK;
 }
 
 static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
@@ -1805,6 +1806,9 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
 
        dev_dbg(dev, "%s: event: %d\n", __func__, event);
 
+       if (event != NFIT_NOTIFY_UPDATE)
+               return;
+
        device_lock(dev);
        if (!dev->driver) {
                /* dev->driver may be null if we're being removed */
index 3d549a3836590bb9dd55f6dd14dd8619698597ab..13d6ec1ff055d602738a92a576dd737ac777af22 100644 (file)
@@ -45,6 +45,10 @@ enum {
        ND_BLK_DCR_LATCH = 2,
 };
 
+enum nfit_root_notifiers {
+       NFIT_NOTIFY_UPDATE = 0x80,
+};
+
 struct nfit_spa {
        struct acpi_nfit_system_address *spa;
        struct list_head list;
index 72b6e9ef0ae9bedbf72ea0a3438f1f4395308136..d176e0ece47041c851f287563f31d4a8fbae6288 100644 (file)
@@ -327,10 +327,18 @@ int __init acpi_numa_init(void)
 
        /* SRAT: Static Resource Affinity Table */
        if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
-               acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
-                                    acpi_parse_x2apic_affinity, 0);
-               acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
-                                    acpi_parse_processor_affinity, 0);
+               struct acpi_subtable_proc srat_proc[2];
+
+               memset(srat_proc, 0, sizeof(srat_proc));
+               srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
+               srat_proc[0].handler = acpi_parse_processor_affinity;
+               srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY;
+               srat_proc[1].handler = acpi_parse_x2apic_affinity;
+
+               acpi_table_parse_entries_array(ACPI_SIG_SRAT,
+                                       sizeof(struct acpi_table_srat),
+                                       srat_proc, ARRAY_SIZE(srat_proc), 0);
+
                cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
                                            acpi_parse_memory_affinity,
                                            NR_NODE_MEMBLKS);
index 78d5f02a073bb1c9e84beaeaf2f38b6f54125333..dcb3d6245ca599db12380f36df7962c4505bf7d4 100644 (file)
@@ -1958,7 +1958,7 @@ int __init acpi_scan_init(void)
 
 static struct acpi_probe_entry *ape;
 static int acpi_probe_count;
-static DEFINE_SPINLOCK(acpi_probe_lock);
+static DEFINE_MUTEX(acpi_probe_mutex);
 
 static int __init acpi_match_madt(struct acpi_subtable_header *header,
                                  const unsigned long end)
@@ -1977,7 +1977,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
        if (acpi_disabled)
                return 0;
 
-       spin_lock(&acpi_probe_lock);
+       mutex_lock(&acpi_probe_mutex);
        for (ape = ap_head; nr; ape++, nr--) {
                if (ACPI_COMPARE_NAME(ACPI_SIG_MADT, ape->id)) {
                        acpi_probe_count = 0;
@@ -1990,7 +1990,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
                                count++;
                }
        }
-       spin_unlock(&acpi_probe_lock);
+       mutex_unlock(&acpi_probe_mutex);
 
        return count;
 }
index 0243d375c6fd40134bd7404008ef6e43144867dc..4b3a9e27f1b611cd9d7b2c4b7268a214e0211b0c 100644 (file)
@@ -555,23 +555,22 @@ static void acpi_global_event_handler(u32 event_type, acpi_handle device,
 static int get_status(u32 index, acpi_event_status *status,
                      acpi_handle *handle)
 {
-       int result = 0;
+       int result;
 
        if (index >= num_gpes + ACPI_NUM_FIXED_EVENTS)
-               goto end;
+               return -EINVAL;
 
        if (index < num_gpes) {
                result = acpi_get_gpe_device(index, handle);
                if (result) {
                        ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
                                        "Invalid GPE 0x%x", index));
-                       goto end;
+                       return result;
                }
                result = acpi_get_gpe_status(*handle, index, status);
        } else if (index < (num_gpes + ACPI_NUM_FIXED_EVENTS))
                result = acpi_get_event_status(index - num_gpes, status);
 
-end:
        return result;
 }
 
index 57f52a2afa356788d4ee18f02867361da2b20a26..bcf0a9420619fa34a1dd7c17088b846693ae197d 100644 (file)
@@ -1003,7 +1003,7 @@ static int binder_dec_node(struct binder_node *node, int strong, int internal)
 
 
 static struct binder_ref *binder_get_ref(struct binder_proc *proc,
-                                        uint32_t desc)
+                                        uint32_t desc, bool need_strong_ref)
 {
        struct rb_node *n = proc->refs_by_desc.rb_node;
        struct binder_ref *ref;
@@ -1011,12 +1011,16 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc,
        while (n) {
                ref = rb_entry(n, struct binder_ref, rb_node_desc);
 
-               if (desc < ref->desc)
+               if (desc < ref->desc) {
                        n = n->rb_left;
-               else if (desc > ref->desc)
+               } else if (desc > ref->desc) {
                        n = n->rb_right;
-               else
+               } else if (need_strong_ref && !ref->strong) {
+                       binder_user_error("tried to use weak ref as strong ref\n");
+                       return NULL;
+               } else {
                        return ref;
+               }
        }
        return NULL;
 }
@@ -1286,7 +1290,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+                       struct binder_ref *ref = binder_get_ref(proc, fp->handle,
+                                               fp->type == BINDER_TYPE_HANDLE);
 
                        if (ref == NULL) {
                                pr_err("transaction release %d bad handle %d\n",
@@ -1381,7 +1386,7 @@ static void binder_transaction(struct binder_proc *proc,
                if (tr->target.handle) {
                        struct binder_ref *ref;
 
-                       ref = binder_get_ref(proc, tr->target.handle);
+                       ref = binder_get_ref(proc, tr->target.handle, true);
                        if (ref == NULL) {
                                binder_user_error("%d:%d got transaction to invalid handle\n",
                                        proc->pid, thread->pid);
@@ -1578,7 +1583,9 @@ static void binder_transaction(struct binder_proc *proc,
                                fp->type = BINDER_TYPE_HANDLE;
                        else
                                fp->type = BINDER_TYPE_WEAK_HANDLE;
+                       fp->binder = 0;
                        fp->handle = ref->desc;
+                       fp->cookie = 0;
                        binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                                       &thread->todo);
 
@@ -1590,7 +1597,8 @@ static void binder_transaction(struct binder_proc *proc,
                } break;
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
-                       struct binder_ref *ref = binder_get_ref(proc, fp->handle);
+                       struct binder_ref *ref = binder_get_ref(proc, fp->handle,
+                                               fp->type == BINDER_TYPE_HANDLE);
 
                        if (ref == NULL) {
                                binder_user_error("%d:%d got transaction with invalid handle, %d\n",
@@ -1625,7 +1633,9 @@ static void binder_transaction(struct binder_proc *proc,
                                        return_error = BR_FAILED_REPLY;
                                        goto err_binder_get_ref_for_node_failed;
                                }
+                               fp->binder = 0;
                                fp->handle = new_ref->desc;
+                               fp->cookie = 0;
                                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                                trace_binder_transaction_ref_to_ref(t, ref,
                                                                    new_ref);
@@ -1679,6 +1689,7 @@ static void binder_transaction(struct binder_proc *proc,
                        binder_debug(BINDER_DEBUG_TRANSACTION,
                                     "        fd %d -> %d\n", fp->handle, target_fd);
                        /* TODO: fput? */
+                       fp->binder = 0;
                        fp->handle = target_fd;
                } break;
 
@@ -1801,7 +1812,9 @@ static int binder_thread_write(struct binder_proc *proc,
                                                ref->desc);
                                }
                        } else
-                               ref = binder_get_ref(proc, target);
+                               ref = binder_get_ref(proc, target,
+                                                    cmd == BC_ACQUIRE ||
+                                                    cmd == BC_RELEASE);
                        if (ref == NULL) {
                                binder_user_error("%d:%d refcount change on invalid ref %d\n",
                                        proc->pid, thread->pid, target);
@@ -1997,7 +2010,7 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                                return -EFAULT;
                        ptr += sizeof(binder_uintptr_t);
-                       ref = binder_get_ref(proc, target);
+                       ref = binder_get_ref(proc, target, false);
                        if (ref == NULL) {
                                binder_user_error("%d:%d %s invalid ref %d\n",
                                        proc->pid, thread->pid,
index b79cb10e289e8a1eb52c2887b3e7c135952beb0f..bd370c98f77d2172afaa069fb159f22d463445e1 100644 (file)
@@ -4138,6 +4138,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         */
        { "ST380013AS",         "3.20",         ATA_HORKAGE_MAX_SEC_1024 },
 
+       /*
+        * Device times out with higher max sects.
+        * https://bugzilla.kernel.org/show_bug.cgi?id=121671
+        */
+       { "LITEON CX1-JB256-HP", NULL,          ATA_HORKAGE_MAX_SEC_1024 },
+
        /* Devices we expect to fail diagnostics */
 
        /* Devices where NCQ should be avoided */
index d95c5971c2256f20f473d5744b01fc54bbf9acf2..a00f7b79202b306f38229ea4a17d6f4aa61a0bd5 100644 (file)
@@ -335,7 +335,7 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
                return;
        }
 
-       unmap_kernel_range((unsigned long)cpu_addr, size);
+       unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size));
        vunmap(cpu_addr);
 }
 #endif
index 9fbafabd82d1ce1af0ccd5c54d62dd6d88745e6c..3e56e3dcf4cae7fd04ecc1f4d8245686d9885efd 100644 (file)
@@ -96,7 +96,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
                int ret;
 
                ret = of_irq_get(dev->dev.of_node, num);
-               if (ret >= 0 || ret == -EPROBE_DEFER)
+               if (ret > 0 || ret == -EPROBE_DEFER)
                        return ret;
        }
 
@@ -154,7 +154,7 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name)
                int ret;
 
                ret = of_irq_get_byname(dev->dev.of_node, name);
-               if (ret >= 0 || ret == -EPROBE_DEFER)
+               if (ret > 0 || ret == -EPROBE_DEFER)
                        return ret;
        }
 
index 38f156745d533a666deae90f167dd6d51d718d54..71df8f2afc6cd8f9766e6fa4f2e6788ff75a72c8 100644 (file)
@@ -8,8 +8,6 @@
 #include <linux/bcma/bcma.h>
 #include <linux/delay.h>
 
-#define BCMA_CORE_SIZE         0x1000
-
 #define bcma_err(bus, fmt, ...) \
        pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
 #define bcma_warn(bus, fmt, ...) \
index 79107597a594425196c6d3ecf17fbd930209219a..c306b483de60f0d2dc187b3b75b73aadb0b03fca 100644 (file)
@@ -2056,12 +2056,13 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
                return -EINVAL;
        }
 
-       /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
-        * supported by this firmware loading method. This check has been
-        * put in place to ensure correct forward compatibility options
-        * when newer hardware variants come along.
+       /* At the moment the iBT 3.0 hardware variants 0x0b (LnP/SfP)
+        * and 0x0c (WsP) are supported by this firmware loading method.
+        *
+        * This check has been put in place to ensure correct forward
+        * compatibility options when newer hardware variants come along.
         */
-       if (ver->hw_variant != 0x0b) {
+       if (ver->hw_variant != 0x0b && ver->hw_variant != 0x0c) {
                BT_ERR("%s: Unsupported Intel hardware variant (%u)",
                       hdev->name, ver->hw_variant);
                kfree_skb(skb);
index 4a414a5a31655a4d3d0a8a0b03749ef73ff14357..b9065506a847da6f3eaf0c6ccb1cfd2f3640d74a 100644 (file)
@@ -1234,8 +1234,7 @@ static int intel_probe(struct platform_device *pdev)
 
        idev->pdev = pdev;
 
-       idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset",
-                                             GPIOD_OUT_LOW);
+       idev->reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
        if (IS_ERR(idev->reset)) {
                dev_err(&pdev->dev, "Unable to retrieve gpio\n");
                return PTR_ERR(idev->reset);
@@ -1247,8 +1246,7 @@ static int intel_probe(struct platform_device *pdev)
 
                dev_err(&pdev->dev, "No IRQ, falling back to gpio-irq\n");
 
-               host_wake = devm_gpiod_get_optional(&pdev->dev, "host-wake",
-                                                   GPIOD_IN);
+               host_wake = devm_gpiod_get(&pdev->dev, "host-wake", GPIOD_IN);
                if (IS_ERR(host_wake)) {
                        dev_err(&pdev->dev, "Unable to retrieve IRQ\n");
                        goto no_irq;
index 7082c7268845639399d9ceab44471937011e1705..0f54cb7ddcbb7b7732192826b0d0589dc6e4480a 100644 (file)
@@ -187,6 +187,7 @@ struct arm_ccn {
        struct arm_ccn_component *xp;
 
        struct arm_ccn_dt dt;
+       int mn_id;
 };
 
 
@@ -326,6 +327,7 @@ struct arm_ccn_pmu_event {
 static ssize_t arm_ccn_pmu_event_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
+       struct arm_ccn *ccn = pmu_to_arm_ccn(dev_get_drvdata(dev));
        struct arm_ccn_pmu_event *event = container_of(attr,
                        struct arm_ccn_pmu_event, attr);
        ssize_t res;
@@ -352,6 +354,9 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
                        res += snprintf(buf + res, PAGE_SIZE - res,
                                        ",cmp_l=?,cmp_h=?,mask=?");
                break;
+       case CCN_TYPE_MN:
+               res += snprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id);
+               break;
        default:
                res += snprintf(buf + res, PAGE_SIZE - res, ",node=?");
                break;
@@ -381,9 +386,9 @@ static umode_t arm_ccn_pmu_events_is_visible(struct kobject *kobj,
 }
 
 static struct arm_ccn_pmu_event arm_ccn_pmu_events[] = {
-       CCN_EVENT_MN(eobarrier, "dir=0,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
-       CCN_EVENT_MN(ecbarrier, "dir=0,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
-       CCN_EVENT_MN(dvmop, "dir=0,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
+       CCN_EVENT_MN(eobarrier, "dir=1,vc=0,cmp_h=0x1c00", CCN_IDX_MASK_OPCODE),
+       CCN_EVENT_MN(ecbarrier, "dir=1,vc=0,cmp_h=0x1e00", CCN_IDX_MASK_OPCODE),
+       CCN_EVENT_MN(dvmop, "dir=1,vc=0,cmp_h=0x2800", CCN_IDX_MASK_OPCODE),
        CCN_EVENT_HNI(txdatflits, "dir=1,vc=3", CCN_IDX_MASK_ANY),
        CCN_EVENT_HNI(rxdatflits, "dir=0,vc=3", CCN_IDX_MASK_ANY),
        CCN_EVENT_HNI(txreqflits, "dir=1,vc=0", CCN_IDX_MASK_ANY),
@@ -757,6 +762,12 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
 
        /* Validate node/xp vs topology */
        switch (type) {
+       case CCN_TYPE_MN:
+               if (node_xp != ccn->mn_id) {
+                       dev_warn(ccn->dev, "Invalid MN ID %d!\n", node_xp);
+                       return -EINVAL;
+               }
+               break;
        case CCN_TYPE_XP:
                if (node_xp >= ccn->num_xps) {
                        dev_warn(ccn->dev, "Invalid XP ID %d!\n", node_xp);
@@ -884,6 +895,10 @@ static void arm_ccn_pmu_xp_dt_config(struct perf_event *event, int enable)
        struct arm_ccn_component *xp;
        u32 val, dt_cfg;
 
+       /* Nothing to do for cycle counter */
+       if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER)
+               return;
+
        if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP)
                xp = &ccn->xp[CCN_CONFIG_XP(event->attr.config)];
        else
@@ -986,7 +1001,7 @@ static void arm_ccn_pmu_xp_watchpoint_config(struct perf_event *event)
 
        /* Comparison values */
        writel(cmp_l & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_L(wp));
-       writel((cmp_l >> 32) & 0xefffffff,
+       writel((cmp_l >> 32) & 0x7fffffff,
                        source->base + CCN_XP_DT_CMP_VAL_L(wp) + 4);
        writel(cmp_h & 0xffffffff, source->base + CCN_XP_DT_CMP_VAL_H(wp));
        writel((cmp_h >> 32) & 0x0fffffff,
@@ -994,7 +1009,7 @@ static void arm_ccn_pmu_xp_watchpoint_config(struct perf_event *event)
 
        /* Mask */
        writel(mask_l & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_L(wp));
-       writel((mask_l >> 32) & 0xefffffff,
+       writel((mask_l >> 32) & 0x7fffffff,
                        source->base + CCN_XP_DT_CMP_MASK_L(wp) + 4);
        writel(mask_h & 0xffffffff, source->base + CCN_XP_DT_CMP_MASK_H(wp));
        writel((mask_h >> 32) & 0x0fffffff,
@@ -1368,6 +1383,8 @@ static int arm_ccn_init_nodes(struct arm_ccn *ccn, int region,
 
        switch (type) {
        case CCN_TYPE_MN:
+               ccn->mn_id = id;
+               return 0;
        case CCN_TYPE_DT:
                return 0;
        case CCN_TYPE_XP:
index aa30af5f0f2bf95288f6a2735b9b5e672f86fde0..7845a38b66041321111ee5114609cf5dd21f6bea 100644 (file)
@@ -118,6 +118,7 @@ static int exynos_rng_probe(struct platform_device *pdev)
 {
        struct exynos_rng *exynos_rng;
        struct resource *res;
+       int ret;
 
        exynos_rng = devm_kzalloc(&pdev->dev, sizeof(struct exynos_rng),
                                        GFP_KERNEL);
@@ -145,7 +146,13 @@ static int exynos_rng_probe(struct platform_device *pdev)
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
-       return devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
+       ret = devm_hwrng_register(&pdev->dev, &exynos_rng->rng);
+       if (ret) {
+               pm_runtime_dont_use_autosuspend(&pdev->dev);
+               pm_runtime_disable(&pdev->dev);
+       }
+
+       return ret;
 }
 
 #ifdef CONFIG_PM
index 8a1432e8bb800114241492e6db5cfdcc841ae8bd..f5c26a5f687582c1cbcd3ea981aae7a3e6738ac7 100644 (file)
@@ -384,7 +384,12 @@ static int omap_rng_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to runtime_get device: %d\n", ret);
+               pm_runtime_put_noidle(&pdev->dev);
+               goto err_ioremap;
+       }
 
        ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) :
                                get_omap_rng_device_details(priv);
@@ -435,8 +440,15 @@ static int __maybe_unused omap_rng_suspend(struct device *dev)
 static int __maybe_unused omap_rng_resume(struct device *dev)
 {
        struct omap_rng_dev *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0) {
+               dev_err(dev, "Failed to runtime_get device: %d\n", ret);
+               pm_runtime_put_noidle(dev);
+               return ret;
+       }
 
-       pm_runtime_get_sync(dev);
        priv->pdata->init(priv);
 
        return 0;
index b583e53366306db870a0d61918156f41985f075e..d93dfebae0bba58a7634d8dfc8e76aa97c0e515c 100644 (file)
@@ -722,15 +722,18 @@ retry:
        }
 }
 
-static void credit_entropy_bits_safe(struct entropy_store *r, int nbits)
+static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
 {
        const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1));
 
+       if (nbits < 0)
+               return -EINVAL;
+
        /* Cap the value to avoid overflows */
        nbits = min(nbits,  nbits_max);
-       nbits = max(nbits, -nbits_max);
 
        credit_entropy_bits(r, nbits);
+       return 0;
 }
 
 /*********************************************************************
@@ -945,6 +948,7 @@ void add_interrupt_randomness(int irq, int irq_flags)
        /* award one bit for the contents of the fast pool */
        credit_entropy_bits(r, credit + 1);
 }
+EXPORT_SYMBOL_GPL(add_interrupt_randomness);
 
 #ifdef CONFIG_BLOCK
 void add_disk_randomness(struct gendisk *disk)
@@ -1457,12 +1461,16 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 static ssize_t
 urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 {
+       static int maxwarn = 10;
        int ret;
 
-       if (unlikely(nonblocking_pool.initialized == 0))
-               printk_once(KERN_NOTICE "random: %s urandom read "
-                           "with %d bits of entropy available\n",
-                           current->comm, nonblocking_pool.entropy_total);
+       if (unlikely(nonblocking_pool.initialized == 0) &&
+           maxwarn > 0) {
+               maxwarn--;
+               printk(KERN_NOTICE "random: %s: uninitialized urandom read "
+                      "(%zd bytes read, %d bits of entropy available)\n",
+                      current->comm, nbytes, nonblocking_pool.entropy_total);
+       }
 
        nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
        ret = extract_entropy_user(&nonblocking_pool, buf, nbytes);
@@ -1542,8 +1550,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                        return -EPERM;
                if (get_user(ent_count, p))
                        return -EFAULT;
-               credit_entropy_bits_safe(&input_pool, ent_count);
-               return 0;
+               return credit_entropy_bits_safe(&input_pool, ent_count);
        case RNDADDENTROPY:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -1557,8 +1564,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                                    size);
                if (retval < 0)
                        return retval;
-               credit_entropy_bits_safe(&input_pool, ent_count);
-               return 0;
+               return credit_entropy_bits_safe(&input_pool, ent_count);
        case RNDZAPENTCNT:
        case RNDCLEARPOOL:
                /*
@@ -1868,12 +1874,18 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
 {
        struct entropy_store *poolp = &input_pool;
 
-       /* Suspend writing if we're above the trickle threshold.
-        * We'll be woken up again once below random_write_wakeup_thresh,
-        * or when the calling thread is about to terminate.
-        */
-       wait_event_interruptible(random_write_wait, kthread_should_stop() ||
+       if (unlikely(nonblocking_pool.initialized == 0))
+               poolp = &nonblocking_pool;
+       else {
+               /* Suspend writing if we're above the trickle
+                * threshold.  We'll be woken up again once below
+                * random_write_wakeup_thresh, or when the calling
+                * thread is about to terminate.
+                */
+               wait_event_interruptible(random_write_wait,
+                                        kthread_should_stop() ||
                        ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
+       }
        mix_pool_bytes(poolp, buffer, count);
        credit_entropy_bits(poolp, entropy);
 }
index de0337ebd6585b7a68aeabdd297bd611474b1bee..4f3137d9a35e1f0c4016040293ab3db583fbdbd2 100644 (file)
@@ -139,7 +139,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,
 
        /* atomic tpm command send and result receive */
        out_size = tpm_transmit(priv->chip, priv->data_buffer,
-                               sizeof(priv->data_buffer));
+                               sizeof(priv->data_buffer), 0);
        if (out_size < 0) {
                mutex_unlock(&priv->buffer_mutex);
                return out_size;
index c50637db3a8a9336f002d44046135bdb49fa7088..17abe52e6365b2363af3b4677615a726d412c051 100644 (file)
@@ -328,8 +328,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 /*
  * Internal kernel interface to transmit TPM commands
  */
-ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
-                    size_t bufsiz)
+ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
+                    unsigned int flags)
 {
        ssize_t rc;
        u32 count, ordinal;
@@ -348,7 +348,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
                return -E2BIG;
        }
 
-       mutex_lock(&chip->tpm_mutex);
+       if (!(flags & TPM_TRANSMIT_UNLOCKED))
+               mutex_lock(&chip->tpm_mutex);
 
        rc = chip->ops->send(chip, (u8 *) buf, count);
        if (rc < 0) {
@@ -391,20 +392,21 @@ out_recv:
                dev_err(chip->pdev,
                        "tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
-       mutex_unlock(&chip->tpm_mutex);
+       if (!(flags & TPM_TRANSMIT_UNLOCKED))
+               mutex_unlock(&chip->tpm_mutex);
        return rc;
 }
 
 #define TPM_DIGEST_SIZE 20
 #define TPM_RET_CODE_IDX 6
 
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
-                        int len, const char *desc)
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd,
+                        int len, unsigned int flags, const char *desc)
 {
-       struct tpm_output_header *header;
+       const struct tpm_output_header *header;
        int err;
 
-       len = tpm_transmit(chip, (u8 *) cmd, len);
+       len = tpm_transmit(chip, (const u8 *)cmd, len, flags);
        if (len <  0)
                return len;
        else if (len < TPM_HEADER_SIZE)
@@ -452,7 +454,8 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
                tpm_cmd.params.getcap_in.subcap = subcap_id;
        }
-       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
+                             desc);
        if (!rc)
                *cap = tpm_cmd.params.getcap_out.cap;
        return rc;
@@ -468,7 +471,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
        tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
        tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 
-       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
                              "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
@@ -489,7 +492,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
        start_cmd.header.in = tpm_startup_header;
 
        start_cmd.params.startup_in.startup_type = startup_type;
-       return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+       return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
                                "attempting to start the TPM");
 }
 
@@ -505,7 +508,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
        tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
        tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
        tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
-       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
+       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
+                             NULL);
 
        if (rc == TPM_ERR_INVALID_POSTINIT) {
                /* The TPM is not started, we are the first to talk to it.
@@ -519,7 +523,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
                tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
                rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-                                 NULL);
+                                     0, NULL);
        }
        if (rc) {
                dev_err(chip->pdev,
@@ -580,7 +584,7 @@ duration:
        tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
        tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
 
-       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
                              "attempting to determine the durations");
        if (rc)
                return rc;
@@ -636,7 +640,7 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
        struct tpm_cmd_t cmd;
 
        cmd.header.in = continue_selftest_header;
-       rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+       rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0,
                              "continue selftest");
        return rc;
 }
@@ -656,7 +660,7 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 
        cmd.header.in = pcrread_header;
        cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
-       rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
+       rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0,
                              "attempting to read a pcr value");
 
        if (rc == 0)
@@ -754,7 +758,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
        cmd.header.in = pcrextend_header;
        cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
        memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
-       rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+       rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0,
                              "attempting extend a PCR value");
 
        tpm_chip_put(chip);
@@ -793,7 +797,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
                /* Attempt to read a PCR value */
                cmd.header.in = pcrread_header;
                cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0);
-               rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE);
+               rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE, 0);
                /* Some buggy TPMs will not respond to tpm_tis_ready() for
                 * around 300ms while the self test is ongoing, keep trying
                 * until the self test duration expires. */
@@ -834,7 +838,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
        if (chip == NULL)
                return -ENODEV;
 
-       rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+       rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd");
 
        tpm_chip_put(chip);
        return rc;
@@ -936,14 +940,15 @@ int tpm_pm_suspend(struct device *dev)
                cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
                memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
                       TPM_DIGEST_SIZE);
-               rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+               rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0,
                                      "extending dummy pcr before suspend");
        }
 
        /* now do the actual savestate */
        for (try = 0; try < TPM_RETRY; try++) {
                cmd.header.in = savestate_header;
-               rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
+               rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0,
+                                     NULL);
 
                /*
                 * If the TPM indicates that it is too busy to respond to
@@ -1027,8 +1032,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
                tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
 
                err = tpm_transmit_cmd(chip, &tpm_cmd,
-                                  TPM_GETRANDOM_RESULT_SIZE + num_bytes,
-                                  "attempting get random");
+                                      TPM_GETRANDOM_RESULT_SIZE + num_bytes,
+                                      0, "attempting get random");
                if (err)
                        break;
 
index ee66fd4673f3596084f75c9033ea24b223ae11d2..f880856aa75e5885dffef99676cdf9a0277eddac 100644 (file)
@@ -39,7 +39,7 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
        struct tpm_chip *chip = dev_get_drvdata(dev);
 
        tpm_cmd.header.in = tpm_readpubek_header;
-       err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+       err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0,
                               "attempting to read the PUBEK");
        if (err)
                goto out;
index a4257a32964f40c189f7a1dc54bd252efa48532a..2216861f89f108b089db387072c33bd7a689fa3e 100644 (file)
@@ -498,11 +498,15 @@ extern struct class *tpm_class;
 extern dev_t tpm_devt;
 extern const struct file_operations tpm_fops;
 
+enum tpm_transmit_flags {
+       TPM_TRANSMIT_UNLOCKED   = BIT(0),
+};
+
+ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
+                    unsigned int flags);
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len,
+                        unsigned int flags, const char *desc);
 ssize_t        tpm_getcap(struct device *, __be32, cap_t *, const char *);
-ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
-                    size_t bufsiz);
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
-                        const char *desc);
 extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
index c12130485fc18e966c9e41736e57bd7fd0586082..cb7e4f6b70ba7afc2608bd118c25204b7643663e 100644 (file)
@@ -264,7 +264,7 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
               sizeof(cmd.params.pcrread_in.pcr_select));
        cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
                              "attempting to read a pcr value");
        if (rc == 0) {
                buf = cmd.params.pcrread_out.digest;
@@ -312,7 +312,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
        cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
        memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
                              "attempting extend a PCR value");
 
        return rc;
@@ -358,7 +358,7 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
                cmd.header.in = tpm2_getrandom_header;
                cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
 
-               err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+               err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
                                       "attempting get random");
                if (err)
                        break;
@@ -416,12 +416,12 @@ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
 }
 
 /**
- * tpm2_seal_trusted() - seal a trusted key
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @options: authentication values and other options
+ * tpm2_seal_trusted() - seal the payload of a trusted key
+ * @chip_num: TPM chip to use
  * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
  *
- * Returns < 0 on error and 0 on success.
+ * Return: < 0 on error and 0 on success.
  */
 int tpm2_seal_trusted(struct tpm_chip *chip,
                      struct trusted_key_payload *payload,
@@ -472,7 +472,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
                goto out;
        }
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "sealing data");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data");
        if (rc)
                goto out;
 
@@ -494,10 +494,18 @@ out:
        return rc;
 }
 
-static int tpm2_load(struct tpm_chip *chip,
-                    struct trusted_key_payload *payload,
-                    struct trusted_key_options *options,
-                    u32 *blob_handle)
+/**
+ * tpm2_load_cmd() - execute a TPM2_Load command
+ * @chip_num: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+static int tpm2_load_cmd(struct tpm_chip *chip,
+                        struct trusted_key_payload *payload,
+                        struct trusted_key_options *options,
+                        u32 *blob_handle, unsigned int flags)
 {
        struct tpm_buf buf;
        unsigned int private_len;
@@ -532,7 +540,7 @@ static int tpm2_load(struct tpm_chip *chip,
                goto out;
        }
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "loading blob");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob");
        if (!rc)
                *blob_handle = be32_to_cpup(
                        (__be32 *) &buf.data[TPM_HEADER_SIZE]);
@@ -546,7 +554,16 @@ out:
        return rc;
 }
 
-static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
+/**
+ * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
+ * @chip_num: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
+                                  unsigned int flags)
 {
        struct tpm_buf buf;
        int rc;
@@ -560,7 +577,8 @@ static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
 
        tpm_buf_append_u32(&buf, handle);
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "flushing context");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags,
+                             "flushing context");
        if (rc)
                dev_warn(chip->pdev, "0x%08x was not flushed, rc=%d\n", handle,
                         rc);
@@ -568,10 +586,18 @@ static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
        tpm_buf_destroy(&buf);
 }
 
-static int tpm2_unseal(struct tpm_chip *chip,
-                      struct trusted_key_payload *payload,
-                      struct trusted_key_options *options,
-                      u32 blob_handle)
+/**
+ * tpm2_unseal_cmd() - execute a TPM2_Unload command
+ * @chip_num: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+static int tpm2_unseal_cmd(struct tpm_chip *chip,
+                          struct trusted_key_payload *payload,
+                          struct trusted_key_options *options,
+                          u32 blob_handle, unsigned int flags)
 {
        struct tpm_buf buf;
        u16 data_len;
@@ -589,7 +615,7 @@ static int tpm2_unseal(struct tpm_chip *chip,
                             options->blobauth /* hmac */,
                             TPM_DIGEST_SIZE);
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "unsealing");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing");
        if (rc > 0)
                rc = -EPERM;
 
@@ -608,12 +634,12 @@ static int tpm2_unseal(struct tpm_chip *chip,
 }
 
 /**
- * tpm_unseal_trusted() - unseal a trusted key
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @options: authentication values and other options
+ * tpm_unseal_trusted() - unseal the payload of a trusted key
+ * @chip_num: TPM chip to use
  * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
  *
- * Returns < 0 on error and 0 on success.
+ * Return: < 0 on error and 0 on success.
  */
 int tpm2_unseal_trusted(struct tpm_chip *chip,
                        struct trusted_key_payload *payload,
@@ -622,14 +648,17 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
        u32 blob_handle;
        int rc;
 
-       rc = tpm2_load(chip, payload, options, &blob_handle);
+       mutex_lock(&chip->tpm_mutex);
+       rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
+                          TPM_TRANSMIT_UNLOCKED);
        if (rc)
-               return rc;
-
-       rc = tpm2_unseal(chip, payload, options, blob_handle);
-
-       tpm2_flush_context(chip, blob_handle);
+               goto out;
 
+       rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
+                            TPM_TRANSMIT_UNLOCKED);
+       tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
+out:
+       mutex_unlock(&chip->tpm_mutex);
        return rc;
 }
 
@@ -655,9 +684,9 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,  u32 *value,
        cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
        cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc);
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc);
        if (!rc)
-               *value = cmd.params.get_tpm_pt_out.value;
+               *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value);
 
        return rc;
 }
@@ -689,7 +718,7 @@ int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
        cmd.header.in = tpm2_startup_header;
 
        cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
-       return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+       return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
                                "attempting to start the TPM");
 }
 EXPORT_SYMBOL_GPL(tpm2_startup);
@@ -718,7 +747,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
        cmd.header.in = tpm2_shutdown_header;
        cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM");
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM");
 
        /* In places where shutdown command is sent there's no much we can do
         * except print the error code on a system failure.
@@ -784,7 +813,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
        cmd.header.in = tpm2_selftest_header;
        cmd.params.selftest_in.full_test = full;
 
-       rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE,
+       rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0,
                              "continue selftest");
 
        /* At least some prototype chips seem to give RC_TESTING error
@@ -836,7 +865,7 @@ int tpm2_do_selftest(struct tpm_chip *chip)
                cmd.params.pcrread_in.pcr_select[1] = 0x00;
                cmd.params.pcrread_in.pcr_select[2] = 0x00;
 
-               rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL);
+               rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL);
                if (rc < 0)
                        break;
 
@@ -885,7 +914,7 @@ int tpm2_probe(struct tpm_chip *chip)
        cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
        cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
 
-       rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd));
+       rc = tpm_transmit(chip, (const u8 *)&cmd, sizeof(cmd), 0);
        if (rc <  0)
                return rc;
        else if (rc < TPM_HEADER_SIZE)
index 61e64293b7654b36d5db6b320d1bc78100379eb3..2b21398c3adcfc4bd5aaa81f7fcc6a980b75834e 100644 (file)
@@ -149,6 +149,11 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
        struct crb_priv *priv = chip->vendor.priv;
        int rc = 0;
 
+       /* Zero the cancel register so that the next command will not get
+        * canceled.
+        */
+       iowrite32(0, &priv->cca->cancel);
+
        if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
                dev_err(&chip->dev,
                        "invalid command count value %x %zx\n",
@@ -182,8 +187,6 @@ static void crb_cancel(struct tpm_chip *chip)
 
        if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
                dev_err(&chip->dev, "ACPI Start failed\n");
-
-       iowrite32(0, &priv->cca->cancel);
 }
 
 static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
index bbf206e3da0d2aa12dcf8bd571fc7b22860f6eeb..ac9582de64a5224e4681494449563e30092810dc 100644 (file)
@@ -354,7 +354,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
 
        /* if read only, just return current value */
        if (divider->flags & CLK_DIVIDER_READ_ONLY) {
-               bestdiv = readl(divider->reg) >> divider->shift;
+               bestdiv = clk_readl(divider->reg) >> divider->shift;
                bestdiv &= div_mask(divider->width);
                bestdiv = _get_div(divider->table, bestdiv, divider->flags,
                        divider->width);
index 7bc1c4527ae48d0baad2ebb4e141385e695ff8f4..8b77abb6bc22942417dd662f76bf118b4849532a 100644 (file)
@@ -766,7 +766,11 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
        if (!hwc)
                return NULL;
 
-       hwc->reg = cg->regs + 0x20 * idx;
+       if (cg->info.flags & CG_VER3)
+               hwc->reg = cg->regs + 0x70000 + 0x20 * idx;
+       else
+               hwc->reg = cg->regs + 0x20 * idx;
+
        hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]];
 
        /*
index 27c0da29eca3dc6c67496ac45de696911f732955..b134a8b15e2c8ca95e0ae8aa1a95f2c958cc955d 100644 (file)
@@ -351,7 +351,8 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
                /* Set new divider */
                data = xgene_clk_read(pclk->param.divider_reg +
                                pclk->param.reg_divider_offset);
-               data &= ~((1 << pclk->param.reg_divider_width) - 1);
+               data &= ~(((1 << pclk->param.reg_divider_width) - 1)
+                               << pclk->param.reg_divider_shift);
                data |= divider;
                xgene_clk_write(data, pclk->param.divider_reg +
                                        pclk->param.reg_divider_offset);
index b0978d3b83e2dcdeb898dcf7233965dc9382b5c6..d302ed3b8225984498876724114cd415b514eb1d 100644 (file)
@@ -115,7 +115,7 @@ static void __init _mx35_clocks_init(void)
        }
 
        clk[ckih] = imx_clk_fixed("ckih", 24000000);
-       clk[ckil] = imx_clk_fixed("ckih", 32768);
+       clk[ckil] = imx_clk_fixed("ckil", 32768);
        clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL);
        clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL);
 
index c1935081d34aee3403d0ee5d6904b117bd5dfa12..aab64205d8663b8233a43491d4ce1cb722191ba1 100644 (file)
@@ -550,6 +550,24 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        if (IS_ENABLED(CONFIG_PCI_IMX6))
                clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
 
+       /*
+        * Initialize the GPU clock muxes, so that the maximum specified clock
+        * rates for the respective SoC are not exceeded.
+        */
+       if (clk_on_imx6dl()) {
+               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
+                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+               clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
+                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+       } else if (clk_on_imx6q()) {
+               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL],
+                              clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
+               clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL],
+                              clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+               clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL],
+                              clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+       }
+
        imx_register_uart_clocks(uart_clks);
 }
 CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
index bc24e5a002e77cad874a0c010fc55046aa66b0f4..3530fe33d5640a1e2c0d5abbe2938cc135e06c7f 100644 (file)
@@ -151,6 +151,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
                return NULL;
 
        init.name = name;
+       init.flags = 0;
        init.num_parents = num_parents;
        init.parent_names = parent_names;
        init.ops = &rockchip_mmc_clk_ops;
index 6f3719d73390fb64d9b7cc0ad83636f1efcbcf85..e84877a2caccf87759451070e1585c5af306fef5 100644 (file)
@@ -123,12 +123,16 @@ static struct clock_event_device sun4i_clockevent = {
        .set_next_event = sun4i_clkevt_next_event,
 };
 
+static void sun4i_timer_clear_interrupt(void)
+{
+       writel(TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_ST_REG);
+}
 
 static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *evt = (struct clock_event_device *)dev_id;
 
-       writel(0x1, timer_base + TIMER_IRQ_ST_REG);
+       sun4i_timer_clear_interrupt();
        evt->event_handler(evt);
 
        return IRQ_HANDLED;
@@ -193,6 +197,9 @@ static void __init sun4i_timer_init(struct device_node *node)
        /* Make sure timer is stopped before playing with interrupts */
        sun4i_clkevt_time_stop(0);
 
+       /* clear timer0 interrupt */
+       sun4i_timer_clear_interrupt();
+
        sun4i_clockevent.cpumask = cpu_possible_mask;
        sun4i_clockevent.irq = irq;
 
index e4dbeae587443ce1bf644756ed6fa91d3eb4c80e..d43c401ff19046ad40fb482498bb2f89e55f2df0 100644 (file)
@@ -119,6 +119,7 @@ config CPU_FREQ_DEFAULT_GOV_SCHED
          Use the CPUfreq governor 'sched' as default. This scales
          cpu frequency using CPU utilization estimates from the
          scheduler.
+
 endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
@@ -217,6 +218,7 @@ config CPU_FREQ_GOV_CONSERVATIVE
 config CPU_FREQ_GOV_SCHED
        bool "'sched' cpufreq governor"
        depends on CPU_FREQ
+       depends on SMP
        select CPU_FREQ_GOV_COMMON
        help
          'sched' - this governor scales cpu frequency from the
index 7264820e6443a65fdbd2587a5ee555a134f81cc5..7b728143440dab3b24032b95095c6fb5494d5434 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/tick.h>
+#ifdef CONFIG_SMP
 #include <linux/sched.h>
+#endif
 #include <trace/events/power.h>
 
 static LIST_HEAD(cpufreq_policy_list);
@@ -474,7 +476,9 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
 void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
                struct cpufreq_freqs *freqs)
 {
+#ifdef CONFIG_SMP
        int cpu;
+#endif
 
        /*
         * Catch double invocations of _begin() which lead to self-deadlock.
@@ -503,8 +507,10 @@ wait:
        spin_unlock(&policy->transition_lock);
 
        scale_freq_capacity(policy, freqs);
+#ifdef CONFIG_SMP
        for_each_cpu(cpu, policy->cpus)
                trace_cpu_capacity(capacity_curr_of(cpu), cpu);
+#endif
 
        cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
 }
index 4dbf1db16aca0e5d29d44b002a6d4ad0cae6d139..9cc8abd3d116e218d6dd5bb7f6344496652865b5 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 
 static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
 static DEFINE_MUTEX(userspace_mutex);
@@ -31,6 +32,7 @@ static DEFINE_MUTEX(userspace_mutex);
 static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
 {
        int ret = -EINVAL;
+       unsigned int *setspeed = policy->governor_data;
 
        pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
 
@@ -38,6 +40,8 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
        if (!per_cpu(cpu_is_managed, policy->cpu))
                goto err;
 
+       *setspeed = freq;
+
        ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
  err:
        mutex_unlock(&userspace_mutex);
@@ -49,19 +53,45 @@ static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
        return sprintf(buf, "%u\n", policy->cur);
 }
 
+static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy)
+{
+       unsigned int *setspeed;
+
+       setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL);
+       if (!setspeed)
+               return -ENOMEM;
+
+       policy->governor_data = setspeed;
+       return 0;
+}
+
 static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                                   unsigned int event)
 {
+       unsigned int *setspeed = policy->governor_data;
        unsigned int cpu = policy->cpu;
        int rc = 0;
 
+       if (event == CPUFREQ_GOV_POLICY_INIT)
+               return cpufreq_userspace_policy_init(policy);
+
+       if (!setspeed)
+               return -EINVAL;
+
        switch (event) {
+       case CPUFREQ_GOV_POLICY_EXIT:
+               mutex_lock(&userspace_mutex);
+               policy->governor_data = NULL;
+               kfree(setspeed);
+               mutex_unlock(&userspace_mutex);
+               break;
        case CPUFREQ_GOV_START:
                BUG_ON(!policy->cur);
                pr_debug("started managing cpu %u\n", cpu);
 
                mutex_lock(&userspace_mutex);
                per_cpu(cpu_is_managed, cpu) = 1;
+               *setspeed = policy->cur;
                mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_STOP:
@@ -69,20 +99,23 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
 
                mutex_lock(&userspace_mutex);
                per_cpu(cpu_is_managed, cpu) = 0;
+               *setspeed = 0;
                mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_LIMITS:
                mutex_lock(&userspace_mutex);
-               pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
-                       cpu, policy->min, policy->max,
-                       policy->cur);
+               pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
+                       cpu, policy->min, policy->max, policy->cur, *setspeed);
 
-               if (policy->max < policy->cur)
+               if (policy->max < *setspeed)
                        __cpufreq_driver_target(policy, policy->max,
                                                CPUFREQ_RELATION_H);
-               else if (policy->min > policy->cur)
+               else if (policy->min > *setspeed)
                        __cpufreq_driver_target(policy, policy->min,
                                                CPUFREQ_RELATION_L);
+               else
+                       __cpufreq_driver_target(policy, *setspeed,
+                                               CPUFREQ_RELATION_L);
                mutex_unlock(&userspace_mutex);
                break;
        }
index f53b02a6bc05b935f7ed9d8b9b5ff12d50eacc34..7ff8b15a34225cbf74130d8dc10fa0c9a1e769d6 100644 (file)
@@ -285,14 +285,14 @@ static void intel_pstate_hwp_set(void)
        int min, hw_min, max, hw_max, cpu, range, adj_range;
        u64 value, cap;
 
-       rdmsrl(MSR_HWP_CAPABILITIES, cap);
-       hw_min = HWP_LOWEST_PERF(cap);
-       hw_max = HWP_HIGHEST_PERF(cap);
-       range = hw_max - hw_min;
-
        get_online_cpus();
 
        for_each_online_cpu(cpu) {
+               rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap);
+               hw_min = HWP_LOWEST_PERF(cap);
+               hw_max = HWP_HIGHEST_PERF(cap);
+               range = hw_max - hw_min;
+
                rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
                adj_range = limits->min_perf_pct * range / 100;
                min = hw_min + adj_range;
@@ -662,7 +662,7 @@ static int core_get_max_pstate(void)
                        if (err)
                                goto skip_tar;
 
-                       tdp_msr = MSR_CONFIG_TDP_NOMINAL + tdp_ctrl;
+                       tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x3);
                        err = rdmsrl_safe(tdp_msr, &tdp_ratio);
                        if (err)
                                goto skip_tar;
index e342565e8715e95af6c76a80ca393d8fcfada66a..1855b9ee807f28fa0fb75212af944542f6d9f1ac 100644 (file)
@@ -135,6 +135,7 @@ static int __init arm_idle_init(void)
                dev = kzalloc(sizeof(*dev), GFP_KERNEL);
                if (!dev) {
                        pr_err("Failed to allocate cpuidle device\n");
+                       ret = -ENOMEM;
                        goto out_fail;
                }
                dev->cpu = cpu;
index ea8189f4b0212cc038f5f4363cf10f5e8a54099a..b3044219772cd7ac57e0bf2559eb7dea8caeca08 100644 (file)
@@ -441,6 +441,9 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
                               OP_ALG_AAI_CTR_MOD128);
        const bool is_rfc3686 = alg->caam.rfc3686;
 
+       if (!ctx->authsize)
+               return 0;
+
        /* NULL encryption / decryption */
        if (!ctx->enckeylen)
                return aead_null_set_sh_desc(aead);
@@ -553,7 +556,10 @@ skip_enc:
 
        /* Read and write assoclen bytes */
        append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
-       append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
+       if (alg->caam.geniv)
+               append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize);
+       else
+               append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
 
        /* Skip assoc data */
        append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
@@ -562,6 +568,14 @@ skip_enc:
        append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG |
                             KEY_VLF);
 
+       if (alg->caam.geniv) {
+               append_seq_load(desc, ivsize, LDST_CLASS_1_CCB |
+                               LDST_SRCDST_BYTE_CONTEXT |
+                               (ctx1_iv_off << LDST_OFFSET_SHIFT));
+               append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO |
+                           (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ivsize);
+       }
+
        /* Load Counter into CONTEXT1 reg */
        if (is_rfc3686)
                append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM |
@@ -614,7 +628,7 @@ skip_enc:
                keys_fit_inline = true;
 
        /* aead_givencrypt shared descriptor */
-       desc = ctx->sh_desc_givenc;
+       desc = ctx->sh_desc_enc;
 
        /* Note: Context registers are saved. */
        init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686);
@@ -645,13 +659,13 @@ copy_iv:
        append_operation(desc, ctx->class2_alg_type |
                         OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT);
 
-       /* ivsize + cryptlen = seqoutlen - authsize */
-       append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
-
        /* Read and write assoclen bytes */
        append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ);
        append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ);
 
+       /* ivsize + cryptlen = seqoutlen - authsize */
+       append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize);
+
        /* Skip assoc data */
        append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF);
 
@@ -697,7 +711,7 @@ copy_iv:
        ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc,
                                              desc_bytes(desc),
                                              DMA_TO_DEVICE);
-       if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) {
+       if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) {
                dev_err(jrdev, "unable to map shared descriptor\n");
                return -ENOMEM;
        }
@@ -2147,7 +2161,7 @@ static void init_authenc_job(struct aead_request *req,
 
        init_aead_job(req, edesc, all_contig, encrypt);
 
-       if (ivsize && (is_rfc3686 || !(alg->caam.geniv && encrypt)))
+       if (ivsize && ((is_rfc3686 && encrypt) || !alg->caam.geniv))
                append_load_as_imm(desc, req->iv, ivsize,
                                   LDST_CLASS_1_CCB |
                                   LDST_SRCDST_BYTE_CONTEXT |
@@ -2534,20 +2548,6 @@ static int aead_decrypt(struct aead_request *req)
        return ret;
 }
 
-static int aead_givdecrypt(struct aead_request *req)
-{
-       struct crypto_aead *aead = crypto_aead_reqtfm(req);
-       unsigned int ivsize = crypto_aead_ivsize(aead);
-
-       if (req->cryptlen < ivsize)
-               return -EINVAL;
-
-       req->cryptlen -= ivsize;
-       req->assoclen += ivsize;
-
-       return aead_decrypt(req);
-}
-
 /*
  * allocate and map the ablkcipher extended descriptor for ablkcipher
  */
@@ -3207,7 +3207,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = AES_BLOCK_SIZE,
                        .maxauthsize = MD5_DIGEST_SIZE,
                },
@@ -3253,7 +3253,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = AES_BLOCK_SIZE,
                        .maxauthsize = SHA1_DIGEST_SIZE,
                },
@@ -3299,7 +3299,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = AES_BLOCK_SIZE,
                        .maxauthsize = SHA224_DIGEST_SIZE,
                },
@@ -3345,7 +3345,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = AES_BLOCK_SIZE,
                        .maxauthsize = SHA256_DIGEST_SIZE,
                },
@@ -3391,7 +3391,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = AES_BLOCK_SIZE,
                        .maxauthsize = SHA384_DIGEST_SIZE,
                },
@@ -3437,7 +3437,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = AES_BLOCK_SIZE,
                        .maxauthsize = SHA512_DIGEST_SIZE,
                },
@@ -3483,7 +3483,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES3_EDE_BLOCK_SIZE,
                        .maxauthsize = MD5_DIGEST_SIZE,
                },
@@ -3531,7 +3531,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES3_EDE_BLOCK_SIZE,
                        .maxauthsize = SHA1_DIGEST_SIZE,
                },
@@ -3579,7 +3579,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES3_EDE_BLOCK_SIZE,
                        .maxauthsize = SHA224_DIGEST_SIZE,
                },
@@ -3627,7 +3627,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES3_EDE_BLOCK_SIZE,
                        .maxauthsize = SHA256_DIGEST_SIZE,
                },
@@ -3675,7 +3675,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES3_EDE_BLOCK_SIZE,
                        .maxauthsize = SHA384_DIGEST_SIZE,
                },
@@ -3723,7 +3723,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES3_EDE_BLOCK_SIZE,
                        .maxauthsize = SHA512_DIGEST_SIZE,
                },
@@ -3769,7 +3769,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES_BLOCK_SIZE,
                        .maxauthsize = MD5_DIGEST_SIZE,
                },
@@ -3815,7 +3815,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES_BLOCK_SIZE,
                        .maxauthsize = SHA1_DIGEST_SIZE,
                },
@@ -3861,7 +3861,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES_BLOCK_SIZE,
                        .maxauthsize = SHA224_DIGEST_SIZE,
                },
@@ -3907,7 +3907,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES_BLOCK_SIZE,
                        .maxauthsize = SHA256_DIGEST_SIZE,
                },
@@ -3953,7 +3953,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES_BLOCK_SIZE,
                        .maxauthsize = SHA384_DIGEST_SIZE,
                },
@@ -3999,7 +3999,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = DES_BLOCK_SIZE,
                        .maxauthsize = SHA512_DIGEST_SIZE,
                },
@@ -4048,7 +4048,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = CTR_RFC3686_IV_SIZE,
                        .maxauthsize = MD5_DIGEST_SIZE,
                },
@@ -4099,7 +4099,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = CTR_RFC3686_IV_SIZE,
                        .maxauthsize = SHA1_DIGEST_SIZE,
                },
@@ -4150,7 +4150,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = CTR_RFC3686_IV_SIZE,
                        .maxauthsize = SHA224_DIGEST_SIZE,
                },
@@ -4201,7 +4201,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = CTR_RFC3686_IV_SIZE,
                        .maxauthsize = SHA256_DIGEST_SIZE,
                },
@@ -4252,7 +4252,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = CTR_RFC3686_IV_SIZE,
                        .maxauthsize = SHA384_DIGEST_SIZE,
                },
@@ -4303,7 +4303,7 @@ static struct caam_aead_alg driver_aeads[] = {
                        .setkey = aead_setkey,
                        .setauthsize = aead_setauthsize,
                        .encrypt = aead_encrypt,
-                       .decrypt = aead_givdecrypt,
+                       .decrypt = aead_decrypt,
                        .ivsize = CTR_RFC3686_IV_SIZE,
                        .maxauthsize = SHA512_DIGEST_SIZE,
                },
index 49106ea42887097a152ec21b7457004eec9f7fbd..99d5e11db194d4ecb0557949b0fd2dfcb0d59dc4 100644 (file)
@@ -1873,6 +1873,7 @@ caam_hash_alloc(struct caam_hash_template *template,
                         template->name);
                snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
                         template->driver_name);
+               t_alg->ahash_alg.setkey = NULL;
        }
        alg->cra_module = THIS_MODULE;
        alg->cra_init = caam_hash_cra_init;
index 9ef51fafdbffaef11b800619818e10ae5f52cc17..6e105e87b8ff660b9908afd8b525321f471c145c 100644 (file)
@@ -442,6 +442,14 @@ static int nx842_powernv_function(const unsigned char *in, unsigned int inlen,
                             (unsigned int)ccw,
                             (unsigned int)be32_to_cpu(crb->ccw));
 
+       /*
+        * NX842 coprocessor sets 3rd bit in CR register with XER[S0].
+        * XER[S0] is the integer summary overflow bit which is nothing
+        * to do NX. Since this bit can be set with other return values,
+        * mask this bit.
+        */
+       ret &= ~ICSWX_XERS0;
+
        switch (ret) {
        case ICSWX_INITIATED:
                ret = wait_for_csb(wmem, csb);
@@ -454,10 +462,6 @@ static int nx842_powernv_function(const unsigned char *in, unsigned int inlen,
                pr_err_ratelimited("ICSWX rejected\n");
                ret = -EPROTO;
                break;
-       default:
-               pr_err_ratelimited("Invalid ICSWX return code %x\n", ret);
-               ret = -EPROTO;
-               break;
        }
 
        if (!ret)
index 0794f1cc00182f986f03673a1e2305ea1e15e094..42f0f229f7f776785b03bb1d4b80f7505dcd0502 100644 (file)
@@ -392,7 +392,7 @@ static void nx_of_update_msc(struct device   *dev,
                     ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) &&
                     i < msc->triplets;
                     i++) {
-                       if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) {
+                       if (msc->fc >= NX_MAX_FC || msc->mode >= NX_MAX_MODE) {
                                dev_err(dev, "unknown function code/mode "
                                        "combo: %d/%d (ignored)\n", msc->fc,
                                        msc->mode);
index 59e4c3af15edb10fe46f4e6afb0ad2d18bc92760..367b6661ee041a469f4da67775a02da0d9ff893e 100644 (file)
@@ -1262,8 +1262,8 @@ static struct crypto_alg qat_algs[] = { {
                        .setkey = qat_alg_ablkcipher_xts_setkey,
                        .decrypt = qat_alg_ablkcipher_decrypt,
                        .encrypt = qat_alg_ablkcipher_encrypt,
-                       .min_keysize = AES_MIN_KEY_SIZE,
-                       .max_keysize = AES_MAX_KEY_SIZE,
+                       .min_keysize = 2 * AES_MIN_KEY_SIZE,
+                       .max_keysize = 2 * AES_MAX_KEY_SIZE,
                        .ivsize = AES_BLOCK_SIZE,
                },
        },
index f3801b983f4222fb874fbb2771967fa62debd525..3f8bb9a40df1268eda70f23bef13512308f73d91 100644 (file)
@@ -191,7 +191,7 @@ struct crypto_alg p8_aes_cbc_alg = {
        .cra_init = p8_aes_cbc_init,
        .cra_exit = p8_aes_cbc_exit,
        .cra_blkcipher = {
-                         .ivsize = 0,
+                         .ivsize = AES_BLOCK_SIZE,
                          .min_keysize = AES_MIN_KEY_SIZE,
                          .max_keysize = AES_MAX_KEY_SIZE,
                          .setkey = p8_aes_cbc_setkey,
index 404a1b69a3ab90511fbdee5cdd1994004c71e762..72f138985e1835675f7b4a54362b1e43ffd85a5f 100644 (file)
@@ -175,7 +175,7 @@ struct crypto_alg p8_aes_ctr_alg = {
        .cra_init = p8_aes_ctr_init,
        .cra_exit = p8_aes_ctr_exit,
        .cra_blkcipher = {
-                         .ivsize = 0,
+                         .ivsize = AES_BLOCK_SIZE,
                          .min_keysize = AES_MIN_KEY_SIZE,
                          .max_keysize = AES_MAX_KEY_SIZE,
                          .setkey = p8_aes_ctr_setkey,
index 2183a2e77641e0682ca113951430765bcbcca4fc..9cb3a0b715e231cdcd150fda81bac4701989ec3d 100644 (file)
 #include <linux/hardirq.h>
 #include <asm/switch_to.h>
 #include <crypto/aes.h>
+#include <crypto/ghash.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/internal/hash.h>
 #include <crypto/b128ops.h>
 
 #define IN_INTERRUPT in_interrupt()
 
-#define GHASH_BLOCK_SIZE (16)
-#define GHASH_DIGEST_SIZE (16)
-#define GHASH_KEY_LEN (16)
-
 void gcm_init_p8(u128 htable[16], const u64 Xi[2]);
 void gcm_gmult_p8(u64 Xi[2], const u128 htable[16]);
 void gcm_ghash_p8(u64 Xi[2], const u128 htable[16],
@@ -55,16 +52,11 @@ struct p8_ghash_desc_ctx {
 
 static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
 {
-       const char *alg;
+       const char *alg = "ghash-generic";
        struct crypto_shash *fallback;
        struct crypto_shash *shash_tfm = __crypto_shash_cast(tfm);
        struct p8_ghash_ctx *ctx = crypto_tfm_ctx(tfm);
 
-       if (!(alg = crypto_tfm_alg_name(tfm))) {
-               printk(KERN_ERR "Failed to get algorithm name.\n");
-               return -ENOENT;
-       }
-
        fallback = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
        if (IS_ERR(fallback)) {
                printk(KERN_ERR
@@ -78,10 +70,18 @@ static int p8_ghash_init_tfm(struct crypto_tfm *tfm)
        crypto_shash_set_flags(fallback,
                               crypto_shash_get_flags((struct crypto_shash
                                                       *) tfm));
-       ctx->fallback = fallback;
 
-       shash_tfm->descsize = sizeof(struct p8_ghash_desc_ctx)
-           + crypto_shash_descsize(fallback);
+       /* Check if the descsize defined in the algorithm is still enough. */
+       if (shash_tfm->descsize < sizeof(struct p8_ghash_desc_ctx)
+           + crypto_shash_descsize(fallback)) {
+               printk(KERN_ERR
+                      "Desc size of the fallback implementation (%s) does not match the expected value: %lu vs %u\n",
+                      alg,
+                      shash_tfm->descsize - sizeof(struct p8_ghash_desc_ctx),
+                      crypto_shash_descsize(fallback));
+               return -EINVAL;
+       }
+       ctx->fallback = fallback;
 
        return 0;
 }
@@ -113,7 +113,7 @@ static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
 {
        struct p8_ghash_ctx *ctx = crypto_tfm_ctx(crypto_shash_tfm(tfm));
 
-       if (keylen != GHASH_KEY_LEN)
+       if (keylen != GHASH_BLOCK_SIZE)
                return -EINVAL;
 
        preempt_disable();
@@ -215,7 +215,8 @@ struct shash_alg p8_ghash_alg = {
        .update = p8_ghash_update,
        .final = p8_ghash_final,
        .setkey = p8_ghash_setkey,
-       .descsize = sizeof(struct p8_ghash_desc_ctx),
+       .descsize = sizeof(struct p8_ghash_desc_ctx)
+               + sizeof(struct ghash_desc_ctx),
        .base = {
                 .cra_name = "ghash",
                 .cra_driver_name = "p8_ghash",
index b9997335f1937eb8694321ef0e37c66c8877a6c2..b18e67d0e065d897bd34d4e2b255056293a17550 100644 (file)
@@ -139,6 +139,26 @@ my $vmr = sub {
     "  vor     $vx,$vy,$vy";
 };
 
+# Some ABIs specify vrsave, special-purpose register #256, as reserved
+# for system use.
+my $no_vrsave = ($flavour =~ /linux-ppc64le/);
+my $mtspr = sub {
+    my ($f,$idx,$ra) = @_;
+    if ($idx == 256 && $no_vrsave) {
+       "       or      $ra,$ra,$ra";
+    } else {
+       "       mtspr   $idx,$ra";
+    }
+};
+my $mfspr = sub {
+    my ($f,$rd,$idx) = @_;
+    if ($idx == 256 && $no_vrsave) {
+       "       li      $rd,-1";
+    } else {
+       "       mfspr   $rd,$idx";
+    }
+};
+
 # PowerISA 2.06 stuff
 sub vsxmem_op {
     my ($f, $vrt, $ra, $rb, $op) = @_;
index 02f9aa4ebe05fef65fbdf5d5a55d1213b296541e..9d05d7dbcfa94fc83f2634e4b5eddb6162f905a2 100644 (file)
@@ -242,7 +242,7 @@ struct at_xdmac_lld {
        u32             mbr_dus;        /* Destination Microblock Stride Register */
 };
 
-
+/* 64-bit alignment needed to update CNDA and CUBC registers in an atomic way. */
 struct at_xdmac_desc {
        struct at_xdmac_lld             lld;
        enum dma_transfer_direction     direction;
@@ -253,7 +253,7 @@ struct at_xdmac_desc {
        unsigned int                    xfer_size;
        struct list_head                descs_list;
        struct list_head                xfer_node;
-};
+} __aligned(sizeof(u64));
 
 static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb)
 {
@@ -1183,8 +1183,8 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
        desc->lld.mbr_cfg = chan_cc;
 
        dev_dbg(chan2dev(chan),
-               "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
-               __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc,
+               "%s: lld: mbr_da=%pad, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+               __func__, &desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
                desc->lld.mbr_cfg);
 
        return desc;
@@ -1388,6 +1388,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        u32                     cur_nda, check_nda, cur_ubc, mask, value;
        u8                      dwidth = 0;
        unsigned long           flags;
+       bool                    initd;
 
        ret = dma_cookie_status(chan, cookie, txstate);
        if (ret == DMA_COMPLETE)
@@ -1412,7 +1413,16 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        residue = desc->xfer_size;
        /*
         * Flush FIFO: only relevant when the transfer is source peripheral
-        * synchronized.
+        * synchronized. Flush is needed before reading CUBC because data in
+        * the FIFO are not reported by CUBC. Reporting a residue of the
+        * transfer length while we have data in FIFO can cause issue.
+        * Usecase: atmel USART has a timeout which means I have received
+        * characters but there is no more character received for a while. On
+        * timeout, it requests the residue. If the data are in the DMA FIFO,
+        * we will return a residue of the transfer length. It means no data
+        * received. If an application is waiting for these data, it will hang
+        * since we won't have another USART timeout without receiving new
+        * data.
         */
        mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
        value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
@@ -1423,34 +1433,43 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        }
 
        /*
-        * When processing the residue, we need to read two registers but we
-        * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where
-        * we stand in the descriptor list and AT_XDMAC_CUBC is used
-        * to know how many data are remaining for the current descriptor.
-        * Since the dma channel is not paused to not loose data, between the
-        * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of
-        * descriptor.
-        * For that reason, after reading AT_XDMAC_CUBC, we check if we are
-        * still using the same descriptor by reading a second time
-        * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to
-        * read again AT_XDMAC_CUBC.
+        * The easiest way to compute the residue should be to pause the DMA
+        * but doing this can lead to miss some data as some devices don't
+        * have FIFO.
+        * We need to read several registers because:
+        * - DMA is running therefore a descriptor change is possible while
+        * reading these registers
+        * - When the block transfer is done, the value of the CUBC register
+        * is set to its initial value until the fetch of the next descriptor.
+        * This value will corrupt the residue calculation so we have to skip
+        * it.
+        *
+        * INITD --------                    ------------
+        *              |____________________|
+        *       _______________________  _______________
+        * NDA       @desc2             \/   @desc3
+        *       _______________________/\_______________
+        *       __________  ___________  _______________
+        * CUBC       0    \/ MAX desc1 \/  MAX desc2
+        *       __________/\___________/\_______________
+        *
+        * Since descriptors are aligned on 64 bits, we can assume that
+        * the update of NDA and CUBC is atomic.
         * Memory barriers are used to ensure the read order of the registers.
-        * A max number of retries is set because unlikely it can never ends if
-        * we are transferring a lot of data with small buffers.
+        * A max number of retries is set because unlikely it could never ends.
         */
-       cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
-       rmb();
-       cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
        for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
-               rmb();
                check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
-
-               if (likely(cur_nda == check_nda))
-                       break;
-
-               cur_nda = check_nda;
+               rmb();
+               initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
                rmb();
                cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
+               rmb();
+               cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
+               rmb();
+
+               if ((check_nda == cur_nda) && initd)
+                       break;
        }
 
        if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) {
@@ -1458,6 +1477,19 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
                goto spin_unlock;
        }
 
+       /*
+        * Flush FIFO: only relevant when the transfer is source peripheral
+        * synchronized. Another flush is needed here because CUBC is updated
+        * when the controller sends the data write command. It can lead to
+        * report data that are not written in the memory or the device. The
+        * FIFO flush ensures that data are really written.
+        */
+       if ((desc->lld.mbr_cfg & mask) == value) {
+               at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
+               while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
+                       cpu_relax();
+       }
+
        /*
         * Remove size of all microblocks already transferred and the current
         * one. Then add the remaining size to transfer of the current
@@ -2023,7 +2055,7 @@ err_dma_unregister:
 err_clk_disable:
        clk_disable_unprepare(atxdmac->clk);
 err_free_irq:
-       free_irq(atxdmac->irq, atxdmac->dma.dev);
+       free_irq(atxdmac->irq, atxdmac);
        return ret;
 }
 
@@ -2039,7 +2071,7 @@ static int at_xdmac_remove(struct platform_device *pdev)
 
        synchronize_irq(atxdmac->irq);
 
-       free_irq(atxdmac->irq, atxdmac->dma.dev);
+       free_irq(atxdmac->irq, atxdmac);
 
        for (i = 0; i < atxdmac->dma.chancnt; i++) {
                struct at_xdmac_chan *atchan = &atxdmac->chan[i];
index 2bf37e68ad0f1529e472a141031d56586ac21e21..dd184b50e5b40a508c1bdacee874b6464d2b1055 100644 (file)
@@ -286,22 +286,21 @@ static void ipu_irq_handler(struct irq_desc *desc)
                raw_spin_unlock(&bank_lock);
                while ((line = ffs(status))) {
                        struct ipu_irq_map *map;
-                       unsigned int irq = NO_IRQ;
+                       unsigned int irq;
 
                        line--;
                        status &= ~(1UL << line);
 
                        raw_spin_lock(&bank_lock);
                        map = src2map(32 * i + line);
-                       if (map)
-                               irq = map->irq;
-                       raw_spin_unlock(&bank_lock);
-
                        if (!map) {
+                               raw_spin_unlock(&bank_lock);
                                pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
                                       line, i);
                                continue;
                        }
+                       irq = map->irq;
+                       raw_spin_unlock(&bank_lock);
                        generic_handle_irq(irq);
                }
        }
index f1bcc2a163b30cef09b3d682b399037e2b9268c3..b1bc945f008f0f2bb454595621b1e4384c064d4f 100644 (file)
@@ -600,27 +600,30 @@ static irqreturn_t usb_dmac_isr_channel(int irq, void *dev)
 {
        struct usb_dmac_chan *chan = dev;
        irqreturn_t ret = IRQ_NONE;
-       u32 mask = USB_DMACHCR_TE;
-       u32 check_bits = USB_DMACHCR_TE | USB_DMACHCR_SP;
+       u32 mask = 0;
        u32 chcr;
+       bool xfer_end = false;
 
        spin_lock(&chan->vc.lock);
 
        chcr = usb_dmac_chan_read(chan, USB_DMACHCR);
-       if (chcr & check_bits)
-               mask |= USB_DMACHCR_DE | check_bits;
+       if (chcr & (USB_DMACHCR_TE | USB_DMACHCR_SP)) {
+               mask |= USB_DMACHCR_DE | USB_DMACHCR_TE | USB_DMACHCR_SP;
+               if (chcr & USB_DMACHCR_DE)
+                       xfer_end = true;
+               ret |= IRQ_HANDLED;
+       }
        if (chcr & USB_DMACHCR_NULL) {
                /* An interruption of TE will happen after we set FTE */
                mask |= USB_DMACHCR_NULL;
                chcr |= USB_DMACHCR_FTE;
                ret |= IRQ_HANDLED;
        }
-       usb_dmac_chan_write(chan, USB_DMACHCR, chcr & ~mask);
+       if (mask)
+               usb_dmac_chan_write(chan, USB_DMACHCR, chcr & ~mask);
 
-       if (chcr & check_bits) {
+       if (xfer_end)
                usb_dmac_isr_transfer_end(chan);
-               ret |= IRQ_HANDLED;
-       }
 
        spin_unlock(&chan->vc.lock);
 
index 1b2c2187b34708215045d3413b28e4c7baa05c1a..dc68394da682f4ed43b5dc77017abeffd7c460cf 100644 (file)
@@ -966,7 +966,7 @@ static void edac_inc_ue_error(struct mem_ctl_info *mci,
        mci->ue_mc += count;
 
        if (!enable_per_layer_report) {
-               mci->ce_noinfo_count += count;
+               mci->ue_noinfo_count += count;
                return;
        }
 
index 58aed67b7eba499c126a5d52cf3b26cd5497c2dc..3c8f19f5ac8183ed2dd2fd13fce9c89c9896a7e4 100644 (file)
@@ -313,7 +313,6 @@ static struct device_type csrow_attr_type = {
  * possible dynamic channel DIMM Label attribute files
  *
  */
-
 DEVICE_CHANNEL(ch0_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 0);
 DEVICE_CHANNEL(ch1_dimm_label, S_IRUGO | S_IWUSR,
@@ -326,6 +325,10 @@ DEVICE_CHANNEL(ch4_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 4);
 DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR,
        channel_dimm_label_show, channel_dimm_label_store, 5);
+DEVICE_CHANNEL(ch6_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 6);
+DEVICE_CHANNEL(ch7_dimm_label, S_IRUGO | S_IWUSR,
+       channel_dimm_label_show, channel_dimm_label_store, 7);
 
 /* Total possible dynamic DIMM Label attribute file table */
 static struct attribute *dynamic_csrow_dimm_attr[] = {
@@ -335,6 +338,8 @@ static struct attribute *dynamic_csrow_dimm_attr[] = {
        &dev_attr_legacy_ch3_dimm_label.attr.attr,
        &dev_attr_legacy_ch4_dimm_label.attr.attr,
        &dev_attr_legacy_ch5_dimm_label.attr.attr,
+       &dev_attr_legacy_ch6_dimm_label.attr.attr,
+       &dev_attr_legacy_ch7_dimm_label.attr.attr,
        NULL
 };
 
@@ -351,6 +356,10 @@ DEVICE_CHANNEL(ch4_ce_count, S_IRUGO,
                   channel_ce_count_show, NULL, 4);
 DEVICE_CHANNEL(ch5_ce_count, S_IRUGO,
                   channel_ce_count_show, NULL, 5);
+DEVICE_CHANNEL(ch6_ce_count, S_IRUGO,
+                  channel_ce_count_show, NULL, 6);
+DEVICE_CHANNEL(ch7_ce_count, S_IRUGO,
+                  channel_ce_count_show, NULL, 7);
 
 /* Total possible dynamic ce_count attribute file table */
 static struct attribute *dynamic_csrow_ce_count_attr[] = {
@@ -360,6 +369,8 @@ static struct attribute *dynamic_csrow_ce_count_attr[] = {
        &dev_attr_legacy_ch3_ce_count.attr.attr,
        &dev_attr_legacy_ch4_ce_count.attr.attr,
        &dev_attr_legacy_ch5_ce_count.attr.attr,
+       &dev_attr_legacy_ch6_ce_count.attr.attr,
+       &dev_attr_legacy_ch7_ce_count.attr.attr,
        NULL
 };
 
@@ -371,9 +382,16 @@ static umode_t csrow_dev_is_visible(struct kobject *kobj,
 
        if (idx >= csrow->nr_channels)
                return 0;
+
+       if (idx >= ARRAY_SIZE(dynamic_csrow_ce_count_attr) - 1) {
+               WARN_ONCE(1, "idx: %d\n", idx);
+               return 0;
+       }
+
        /* Only expose populated DIMMs */
        if (!csrow->channels[idx]->dimm->nr_pages)
                return 0;
+
        return attr->mode;
 }
 
index ec379a4164cc07474fd5f2c193cbe6437df0e6fd..f292917b00e7142425fd6676ee48bbd3050b8946 100644 (file)
@@ -18,3 +18,6 @@ obj-$(CONFIG_EFI_RUNTIME_MAP)         += runtime-map.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)     += runtime-wrappers.o
 obj-$(CONFIG_EFI_STUB)                 += libstub/
 obj-$(CONFIG_EFI_FAKE_MEMMAP)          += fake_mem.o
+
+arm-obj-$(CONFIG_EFI)                  := arm-init.o arm-runtime.o
+obj-$(CONFIG_ARM64)                    += $(arm-obj-y)
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
new file mode 100644 (file)
index 0000000..9e15d57
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013 - 2015 Linaro 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.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+
+#include <asm/efi.h>
+
+struct efi_memory_map memmap;
+
+u64 efi_system_table;
+
+static int __init is_normal_ram(efi_memory_desc_t *md)
+{
+       if (md->attribute & EFI_MEMORY_WB)
+               return 1;
+       return 0;
+}
+
+/*
+ * Translate a EFI virtual address into a physical address: this is necessary,
+ * as some data members of the EFI system table are virtually remapped after
+ * SetVirtualAddressMap() has been called.
+ */
+static phys_addr_t efi_to_phys(unsigned long addr)
+{
+       efi_memory_desc_t *md;
+
+       for_each_efi_memory_desc(&memmap, md) {
+               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+                       continue;
+               if (md->virt_addr == 0)
+                       /* no virtual mapping has been installed by the stub */
+                       break;
+               if (md->virt_addr <= addr &&
+                   (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
+                       return md->phys_addr + addr - md->virt_addr;
+       }
+       return addr;
+}
+
+static int __init uefi_init(void)
+{
+       efi_char16_t *c16;
+       void *config_tables;
+       size_t table_size;
+       char vendor[100] = "unknown";
+       int i, retval;
+
+       efi.systab = early_memremap(efi_system_table,
+                                   sizeof(efi_system_table_t));
+       if (efi.systab == NULL) {
+               pr_warn("Unable to map EFI system table.\n");
+               return -ENOMEM;
+       }
+
+       set_bit(EFI_BOOT, &efi.flags);
+       if (IS_ENABLED(CONFIG_64BIT))
+               set_bit(EFI_64BIT, &efi.flags);
+
+       /*
+        * Verify the EFI Table
+        */
+       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+               pr_err("System table signature incorrect\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       if ((efi.systab->hdr.revision >> 16) < 2)
+               pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
+                       efi.systab->hdr.revision >> 16,
+                       efi.systab->hdr.revision & 0xffff);
+
+       /* Show what we know for posterity */
+       c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
+                            sizeof(vendor) * sizeof(efi_char16_t));
+       if (c16) {
+               for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+                       vendor[i] = c16[i];
+               vendor[i] = '\0';
+               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
+       }
+
+       pr_info("EFI v%u.%.02u by %s\n",
+               efi.systab->hdr.revision >> 16,
+               efi.systab->hdr.revision & 0xffff, vendor);
+
+       table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
+       config_tables = early_memremap(efi_to_phys(efi.systab->tables),
+                                      table_size);
+       if (config_tables == NULL) {
+               pr_warn("Unable to map EFI config table array.\n");
+               retval = -ENOMEM;
+               goto out;
+       }
+       retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
+                                        sizeof(efi_config_table_t), NULL);
+
+       early_memunmap(config_tables, table_size);
+out:
+       early_memunmap(efi.systab,  sizeof(efi_system_table_t));
+       return retval;
+}
+
+/*
+ * Return true for RAM regions we want to permanently reserve.
+ */
+static __init int is_reserve_region(efi_memory_desc_t *md)
+{
+       switch (md->type) {
+       case EFI_LOADER_CODE:
+       case EFI_LOADER_DATA:
+       case EFI_BOOT_SERVICES_CODE:
+       case EFI_BOOT_SERVICES_DATA:
+       case EFI_CONVENTIONAL_MEMORY:
+       case EFI_PERSISTENT_MEMORY:
+               return 0;
+       default:
+               break;
+       }
+       return is_normal_ram(md);
+}
+
+static __init void reserve_regions(void)
+{
+       efi_memory_desc_t *md;
+       u64 paddr, npages, size;
+
+       if (efi_enabled(EFI_DBG))
+               pr_info("Processing EFI memory map:\n");
+
+       for_each_efi_memory_desc(&memmap, md) {
+               paddr = md->phys_addr;
+               npages = md->num_pages;
+
+               if (efi_enabled(EFI_DBG)) {
+                       char buf[64];
+
+                       pr_info("  0x%012llx-0x%012llx %s",
+                               paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
+                               efi_md_typeattr_format(buf, sizeof(buf), md));
+               }
+
+               memrange_efi_to_native(&paddr, &npages);
+               size = npages << PAGE_SHIFT;
+
+               if (is_normal_ram(md))
+                       early_init_dt_add_memory_arch(paddr, size);
+
+               if (is_reserve_region(md)) {
+                       memblock_mark_nomap(paddr, size);
+                       if (efi_enabled(EFI_DBG))
+                               pr_cont("*");
+               }
+
+               if (efi_enabled(EFI_DBG))
+                       pr_cont("\n");
+       }
+
+       set_bit(EFI_MEMMAP, &efi.flags);
+}
+
+void __init efi_init(void)
+{
+       struct efi_fdt_params params;
+
+       /* Grab UEFI information placed in FDT by stub */
+       if (!efi_get_fdt_params(&params))
+               return;
+
+       efi_system_table = params.system_table;
+
+       memmap.phys_map = params.mmap;
+       memmap.map = early_memremap(params.mmap, params.mmap_size);
+       if (memmap.map == NULL) {
+               /*
+               * If we are booting via UEFI, the UEFI memory map is the only
+               * description of memory we have, so there is little point in
+               * proceeding if we cannot access it.
+               */
+               panic("Unable to map EFI memory map.\n");
+       }
+       memmap.map_end = memmap.map + params.mmap_size;
+       memmap.desc_size = params.desc_size;
+       memmap.desc_version = params.desc_ver;
+
+       if (uefi_init() < 0)
+               return;
+
+       reserve_regions();
+       early_memunmap(memmap.map, params.mmap_size);
+       memblock_mark_nomap(params.mmap & PAGE_MASK,
+                           PAGE_ALIGN(params.mmap_size +
+                                      (params.mmap & ~PAGE_MASK)));
+}
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
new file mode 100644 (file)
index 0000000..6ae21e4
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013, 2014 Linaro 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.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/preempt.h>
+#include <linux/rbtree.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/efi.h>
+#include <asm/mmu.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+extern u64 efi_system_table;
+
+static struct mm_struct efi_mm = {
+       .mm_rb                  = RB_ROOT,
+       .mm_users               = ATOMIC_INIT(2),
+       .mm_count               = ATOMIC_INIT(1),
+       .mmap_sem               = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
+       .page_table_lock        = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
+       .mmlist                 = LIST_HEAD_INIT(efi_mm.mmlist),
+};
+
+static bool __init efi_virtmap_init(void)
+{
+       efi_memory_desc_t *md;
+
+       efi_mm.pgd = pgd_alloc(&efi_mm);
+       init_new_context(NULL, &efi_mm);
+
+       for_each_efi_memory_desc(&memmap, md) {
+               phys_addr_t phys = md->phys_addr;
+               int ret;
+
+               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+                       continue;
+               if (md->virt_addr == 0)
+                       return false;
+
+               ret = efi_create_mapping(&efi_mm, md);
+               if  (!ret) {
+                       pr_info("  EFI remap %pa => %p\n",
+                               &phys, (void *)(unsigned long)md->virt_addr);
+               } else {
+                       pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
+                               &phys, ret);
+                       return false;
+               }
+       }
+       return true;
+}
+
+/*
+ * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
+ * non-early mapping of the UEFI system table and virtual mappings for all
+ * EFI_MEMORY_RUNTIME regions.
+ */
+static int __init arm_enable_runtime_services(void)
+{
+       u64 mapsize;
+
+       if (!efi_enabled(EFI_BOOT)) {
+               pr_info("EFI services will not be available.\n");
+               return 0;
+       }
+
+       if (efi_runtime_disabled()) {
+               pr_info("EFI runtime services will be disabled.\n");
+               return 0;
+       }
+
+       pr_info("Remapping and enabling EFI services.\n");
+
+       mapsize = memmap.map_end - memmap.map;
+       memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
+                                                  mapsize);
+       if (!memmap.map) {
+               pr_err("Failed to remap EFI memory map\n");
+               return -ENOMEM;
+       }
+       memmap.map_end = memmap.map + mapsize;
+       efi.memmap = &memmap;
+
+       efi.systab = (__force void *)ioremap_cache(efi_system_table,
+                                                  sizeof(efi_system_table_t));
+       if (!efi.systab) {
+               pr_err("Failed to remap EFI System Table\n");
+               return -ENOMEM;
+       }
+       set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
+       if (!efi_virtmap_init()) {
+               pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
+               return -ENOMEM;
+       }
+
+       /* Set up runtime services function pointers */
+       efi_native_runtime_setup();
+       set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
+       efi.runtime_version = efi.systab->hdr.revision;
+
+       return 0;
+}
+early_initcall(arm_enable_runtime_services);
+
+void efi_virtmap_load(void)
+{
+       preempt_disable();
+       efi_set_pgd(&efi_mm);
+}
+
+void efi_virtmap_unload(void)
+{
+       efi_set_pgd(current->active_mm);
+       preempt_enable();
+}
index 3b52677f459ae24b2dd2dcd75b0c4fe95beeb64c..c51f3b2fe3c0868fe643ebe2b1d18554b61e1ca8 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
+#include <asm/early_ioremap.h>
+
 struct efi __read_mostly efi = {
        .mps                    = EFI_INVALID_TABLE_ADDR,
        .acpi                   = EFI_INVALID_TABLE_ADDR,
index b18bea08ff253398db70846445dca4ee3ea0eafc..469dc378adeb9476585c784676ecf5523877e59e 100644 (file)
@@ -50,6 +50,7 @@ config GPIO_DEVRES
 config OF_GPIO
        def_bool y
        depends on OF
+       depends on HAS_IOMEM
 
 config GPIO_ACPI
        def_bool y
index 70097472b02cc7cb9332f9e59cac750720e21c54..c50e930d97d3fc48f1f3e5c771d4bfd744f5a512 100644 (file)
@@ -17,7 +17,6 @@
  * Moorestown platform Langwell chip.
  * Medfield platform Penwell chip.
  * Clovertrail platform Cloverview chip.
- * Merrifield platform Tangier chip.
  */
 
 #include <linux/module.h>
@@ -64,10 +63,6 @@ enum GPIO_REG {
 /* intel_mid gpio driver data */
 struct intel_mid_gpio_ddata {
        u16 ngpio;              /* number of gpio pins */
-       u32 gplr_offset;        /* offset of first GPLR register from base */
-       u32 flis_base;          /* base address of FLIS registers */
-       u32 flis_len;           /* length of FLIS registers */
-       u32 (*get_flis_offset)(int gpio);
        u32 chip_irq_type;      /* chip interrupt type */
 };
 
@@ -257,15 +252,6 @@ static const struct intel_mid_gpio_ddata gpio_cloverview_core = {
        .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
 };
 
-static const struct intel_mid_gpio_ddata gpio_tangier = {
-       .ngpio = 192,
-       .gplr_offset = 4,
-       .flis_base = 0xff0c0000,
-       .flis_len = 0x8000,
-       .get_flis_offset = NULL,
-       .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
-};
-
 static const struct pci_device_id intel_gpio_ids[] = {
        {
                /* Lincroft */
@@ -292,11 +278,6 @@ static const struct pci_device_id intel_gpio_ids[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
                .driver_data = (kernel_ulong_t)&gpio_cloverview_core,
        },
-       {
-               /* Tangier */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199),
-               .driver_data = (kernel_ulong_t)&gpio_tangier,
-       },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
index 48ef368347ab2cd63cdb1d4f922572c608af9e89..9e02cb6afb0bb15872581684d0c806dff4596c51 100644 (file)
@@ -329,7 +329,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
                                irq_hw_number_t hwirq)
 {
        irq_set_chip_data(irq, h->host_data);
-       irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq);
+       irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq);
 
        return 0;
 }
index 2d4892cc70fb0c4acc149dd6a9864439644a1673..c844d7eccb6c33e3626a212209c981403489e835 100644 (file)
@@ -86,7 +86,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
 #define MAX_BANK 5
 #define BANK_SZ 8
 
-#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
 
 struct pca953x_chip {
        unsigned gpio_start;
index 990fa9023e2228a82d1138cb8f25bfeb75dab23d..3b6bce0518abfcf8a127dca1428bb69ebde52869 100644 (file)
@@ -155,7 +155,7 @@ static int sa1100_gpio_irqdomain_map(struct irq_domain *d,
 {
        irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip,
                                 handle_edge_irq);
-       irq_set_noprobe(irq);
+       irq_set_probe(irq);
 
        return 0;
 }
index 053fc2f465dfe663df9c75205e9806fa51c6d497..ff5566c69f7d2a7840d188ad8d69e48f49442fa2 100644 (file)
@@ -710,9 +710,9 @@ int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev);
 void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev);
 int amdgpu_gart_init(struct amdgpu_device *adev);
 void amdgpu_gart_fini(struct amdgpu_device *adev);
-void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
+void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
                        int pages);
-int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset,
+int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
                     int pages, struct page **pagelist,
                     dma_addr_t *dma_addr, uint32_t flags);
 
index 9416e0f5c1db2bf8c5601ddee999b1ade5efabc0..51a9942cdb40f48044b85e98fef482b20bf9d6b8 100644 (file)
@@ -331,6 +331,19 @@ bool amdgpu_atombios_get_connector_info_from_object_table(struct amdgpu_device *
                            (le16_to_cpu(path->usConnObjectId) &
                             OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
 
+                       /* Skip TV/CV support */
+                       if ((le16_to_cpu(path->usDeviceTag) ==
+                            ATOM_DEVICE_TV1_SUPPORT) ||
+                           (le16_to_cpu(path->usDeviceTag) ==
+                            ATOM_DEVICE_CV_SUPPORT))
+                               continue;
+
+                       if (con_obj_id >= ARRAY_SIZE(object_connector_convert)) {
+                               DRM_ERROR("invalid con_obj_id %d for device tag 0x%04x\n",
+                                         con_obj_id, le16_to_cpu(path->usDeviceTag));
+                               continue;
+                       }
+
                        connector_type =
                                object_connector_convert[con_obj_id];
                        connector_object_id = con_obj_id;
@@ -566,28 +579,19 @@ int amdgpu_atombios_get_clock_info(struct amdgpu_device *adev)
                    le16_to_cpu(firmware_info->info.usReferenceClock);
                ppll->reference_div = 0;
 
-               if (crev < 2)
-                       ppll->pll_out_min =
-                               le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
-               else
-                       ppll->pll_out_min =
-                               le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
+               ppll->pll_out_min =
+                       le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
                ppll->pll_out_max =
                    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
 
-               if (crev >= 4) {
-                       ppll->lcd_pll_out_min =
-                               le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
-                       if (ppll->lcd_pll_out_min == 0)
-                               ppll->lcd_pll_out_min = ppll->pll_out_min;
-                       ppll->lcd_pll_out_max =
-                               le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
-                       if (ppll->lcd_pll_out_max == 0)
-                               ppll->lcd_pll_out_max = ppll->pll_out_max;
-               } else {
+               ppll->lcd_pll_out_min =
+                       le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
+               if (ppll->lcd_pll_out_min == 0)
                        ppll->lcd_pll_out_min = ppll->pll_out_min;
+               ppll->lcd_pll_out_max =
+                       le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100;
+               if (ppll->lcd_pll_out_max == 0)
                        ppll->lcd_pll_out_max = ppll->pll_out_max;
-               }
 
                if (ppll->pll_out_min == 0)
                        ppll->pll_out_min = 64800;
index 5a8fbadbd27b4ca0ed663f4ad9cad804b9aae87f..29adbbe225c4ac0599d6ed6643306e43fa9e7038 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 
 #include "amdgpu_acpi.h"
 
@@ -256,6 +257,10 @@ static int amdgpu_atpx_set_discrete_state(struct amdgpu_atpx *atpx, u8 state)
                if (!info)
                        return -EIO;
                kfree(info);
+
+               /* 200ms delay is required after off */
+               if (state == 0)
+                       msleep(200);
        }
        return 0;
 }
index 7ef2c13921b4c244f51ad2f75891a0b91019184c..9300833369688ddf2d886f8c63edfcc97a0b83e8 100644 (file)
@@ -1690,7 +1690,6 @@ amdgpu_connector_add(struct amdgpu_device *adev,
                                                   DRM_MODE_SCALE_NONE);
                        /* no HPD on analog connectors */
                        amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE;
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
                        connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
                        break;
@@ -1893,8 +1892,10 @@ amdgpu_connector_add(struct amdgpu_device *adev,
        }
 
        if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE) {
-               if (i2c_bus->valid)
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+               if (i2c_bus->valid) {
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+                                           DRM_CONNECTOR_POLL_DISCONNECT;
+               }
        } else
                connector->polled = DRM_CONNECTOR_POLL_HPD;
 
index c961fe093e12fb3d7fc4f71b358ef594bfc8621c..16302f7d59f6cb7a51e8d61672759ec03f2e4346 100644 (file)
@@ -1793,7 +1793,23 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        }
 
        drm_kms_helper_poll_enable(dev);
+
+       /*
+        * Most of the connector probing functions try to acquire runtime pm
+        * refs to ensure that the GPU is powered on when connector polling is
+        * performed. Since we're calling this from a runtime PM callback,
+        * trying to acquire rpm refs will cause us to deadlock.
+        *
+        * Since we're guaranteed to be holding the rpm lock, it's safe to
+        * temporarily disable the rpm helpers so this doesn't deadlock us.
+        */
+#ifdef CONFIG_PM
+       dev->dev->power.disable_depth++;
+#endif
        drm_helper_hpd_irq_event(dev);
+#ifdef CONFIG_PM
+       dev->dev->power.disable_depth--;
+#endif
 
        if (fbcon) {
                amdgpu_fbdev_set_suspend(adev, 0);
index fe36caf1b7d7b084762d19fb7fa6516a42dd3fa3..14f57d9915e3fc0aa8d5a8e77b734073f05ecb9b 100644 (file)
@@ -113,24 +113,26 @@ void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
        printk("\n");
 }
 
+
 u32 amdgpu_dpm_get_vblank_time(struct amdgpu_device *adev)
 {
        struct drm_device *dev = adev->ddev;
        struct drm_crtc *crtc;
        struct amdgpu_crtc *amdgpu_crtc;
-       u32 line_time_us, vblank_lines;
+       u32 vblank_in_pixels;
        u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
 
        if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        amdgpu_crtc = to_amdgpu_crtc(crtc);
                        if (crtc->enabled && amdgpu_crtc->enabled && amdgpu_crtc->hw_mode.clock) {
-                               line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
-                                       amdgpu_crtc->hw_mode.clock;
-                               vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
+                               vblank_in_pixels =
+                                       amdgpu_crtc->hw_mode.crtc_htotal *
+                                       (amdgpu_crtc->hw_mode.crtc_vblank_end -
                                        amdgpu_crtc->hw_mode.crtc_vdisplay +
-                                       (amdgpu_crtc->v_border * 2);
-                               vblank_time_us = vblank_lines * line_time_us;
+                                       (amdgpu_crtc->v_border * 2));
+
+                               vblank_time_us = vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock;
                                break;
                        }
                }
index 7312d729d30013d3e741f3dbda39f58f7d8d6357..22a613a95bf0620208962c327993f60e9337ce38 100644 (file)
@@ -221,7 +221,7 @@ void amdgpu_gart_table_vram_free(struct amdgpu_device *adev)
  * Unbinds the requested pages from the gart page table and
  * replaces them with the dummy page (all asics).
  */
-void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
+void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
                        int pages)
 {
        unsigned t;
@@ -269,7 +269,7 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset,
  * (all asics).
  * Returns 0 for success, -EINVAL for failure.
  */
-int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset,
+int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
                     int pages, struct page **pagelist, dma_addr_t *dma_addr,
                     uint32_t flags)
 {
index 9e25edafa7210000d1bfad1959f82725228e91df..c77a1ebfc632ce981d6b8318768b28ce76890de2 100644 (file)
@@ -288,7 +288,7 @@ void amdgpu_ib_pool_fini(struct amdgpu_device *adev)
 int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
 {
        unsigned i;
-       int r;
+       int r, ret = 0;
 
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
                struct amdgpu_ring *ring = adev->rings[i];
@@ -309,10 +309,11 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
                        } else {
                                /* still not good, but we can live with it */
                                DRM_ERROR("amdgpu: failed testing IB on ring %d (%d).\n", i, r);
+                               ret = r;
                        }
                }
        }
-       return 0;
+       return ret;
 }
 
 /*
index 4488e82f87b01475a43a789280c6f809452530df..a5c824078472637aad30ce3c13f3e879a539c7f2 100644 (file)
@@ -227,7 +227,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        type = AMD_IP_BLOCK_TYPE_UVD;
                        ring_mask = adev->uvd.ring.ready ? 1 : 0;
                        ib_start_alignment = AMDGPU_GPU_PAGE_SIZE;
-                       ib_size_alignment = 8;
+                       ib_size_alignment = 16;
                        break;
                case AMDGPU_HW_IP_VCE:
                        type = AMD_IP_BLOCK_TYPE_VCE;
index 1cbb16e153079e7463a0ac070d1a19461deb588e..475c38fe92453d36899c75c01dc09a461e5f7dca 100644 (file)
@@ -233,8 +233,8 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo,
 
        adev = amdgpu_get_adev(bo->bdev);
        ring = adev->mman.buffer_funcs_ring;
-       old_start = old_mem->start << PAGE_SHIFT;
-       new_start = new_mem->start << PAGE_SHIFT;
+       old_start = (u64)old_mem->start << PAGE_SHIFT;
+       new_start = (u64)new_mem->start << PAGE_SHIFT;
 
        switch (old_mem->mem_type) {
        case TTM_PL_VRAM:
index 92b6acadfc5270188b958049e4a468ead9f21ddc..21aacc1f45c1fd7afded7f6088c8a365e9005224 100644 (file)
@@ -243,7 +243,7 @@ static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STA
 
 /* convert bits per color to bits per pixel */
 /* get bpc from the EDID */
-static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
+static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
 {
        if (bpc == 0)
                return 24;
@@ -251,64 +251,32 @@ static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
                return bpc * 3;
 }
 
-/* get the max pix clock supported by the link rate and lane num */
-static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate,
-                                           int lane_num,
-                                           int bpp)
-{
-       return (link_rate * lane_num * 8) / bpp;
-}
-
 /***** amdgpu specific DP functions *****/
 
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector,
+static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
                                                 const u8 dpcd[DP_DPCD_SIZE],
-                                                int pix_clock)
-{
-       int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
-       int max_link_rate = drm_dp_max_link_rate(dpcd);
-       int max_lane_num = drm_dp_max_lane_count(dpcd);
-       int lane_num;
-       int max_dp_pix_clock;
-
-       for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
-               max_dp_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
-               if (pix_clock <= max_dp_pix_clock)
-                       break;
-       }
-
-       return lane_num;
-}
-
-static int amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector,
-                                               const u8 dpcd[DP_DPCD_SIZE],
-                                               int pix_clock)
+                                                unsigned pix_clock,
+                                                unsigned *dp_lanes, unsigned *dp_rate)
 {
-       int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
-       int lane_num, max_pix_clock;
-
-       if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
-           ENCODER_OBJECT_ID_NUTMEG)
-               return 270000;
-
-       lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock);
-       max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp);
-       if (pix_clock <= max_pix_clock)
-               return 162000;
-       max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp);
-       if (pix_clock <= max_pix_clock)
-               return 270000;
-       if (amdgpu_connector_is_dp12_capable(connector)) {
-               max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp);
-               if (pix_clock <= max_pix_clock)
-                       return 540000;
+       unsigned bpp =
+               amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
+       static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+       unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+       unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+       unsigned lane_num, i, max_pix_clock;
+
+       for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+               for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+                       max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+                       if (max_pix_clock >= pix_clock) {
+                               *dp_lanes = lane_num;
+                               *dp_rate = link_rates[i];
+                               return 0;
+                       }
+               }
        }
 
-       return drm_dp_max_link_rate(dpcd);
+       return -EINVAL;
 }
 
 static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
@@ -422,6 +390,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
 {
        struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
        struct amdgpu_connector_atom_dig *dig_connector;
+       int ret;
 
        if (!amdgpu_connector->con_priv)
                return;
@@ -429,10 +398,14 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
 
        if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
            (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-               dig_connector->dp_clock =
-                       amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
-               dig_connector->dp_lane_count =
-                       amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+               ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
+                                                           mode->clock,
+                                                           &dig_connector->dp_lane_count,
+                                                           &dig_connector->dp_clock);
+               if (ret) {
+                       dig_connector->dp_clock = 0;
+                       dig_connector->dp_lane_count = 0;
+               }
        }
 }
 
@@ -441,14 +414,17 @@ int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
 {
        struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
        struct amdgpu_connector_atom_dig *dig_connector;
-       int dp_clock;
+       unsigned dp_lanes, dp_clock;
+       int ret;
 
        if (!amdgpu_connector->con_priv)
                return MODE_CLOCK_HIGH;
        dig_connector = amdgpu_connector->con_priv;
 
-       dp_clock =
-               amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+       ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
+                                                   mode->clock, &dp_lanes, &dp_clock);
+       if (ret)
+               return MODE_CLOCK_HIGH;
 
        if ((dp_clock == 540000) &&
            (!amdgpu_connector_is_dp12_capable(connector)))
index 1cd6de575305aa3f657fa1a7f5a70232b272d739..542517d4e5840139b69d2c5e5f144d50b33e625c 100644 (file)
@@ -98,6 +98,7 @@ amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encode
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
                        if (dig->backlight_level == 0)
                                amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
                                                                       ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
index 5f712ceddf08e4765fb544aff0cad26e6bbcd890..c568293cb6c1a40ee6786a81cc00cec9b6aaac8e 100644 (file)
@@ -52,6 +52,7 @@ static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev);
 static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev);
 static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev);
 static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev);
+static int cik_sdma_soft_reset(void *handle);
 
 MODULE_FIRMWARE("radeon/bonaire_sdma.bin");
 MODULE_FIRMWARE("radeon/bonaire_sdma1.bin");
@@ -1030,6 +1031,8 @@ static int cik_sdma_resume(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       cik_sdma_soft_reset(handle);
+
        return cik_sdma_hw_init(adev);
 }
 
index 8035d4d6a4f57f9ff880d8fe1895285734a9bb2b..653917a3bcc2fdd031d60e055067c145ef8c6950 100644 (file)
@@ -1955,10 +1955,8 @@ static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
                }
        } else { /*pi->caps_vce_pg*/
                cz_update_vce_dpm(adev);
-               cz_enable_vce_dpm(adev, true);
+               cz_enable_vce_dpm(adev, !gate);
        }
-
-       return;
 }
 
 const struct amd_ip_funcs cz_dpm_ip_funcs = {
index 093599aba64b9e0ff0e0a4ba1f43e936903707fa..75b7b4d1e5c7aacd13bf5684e94cc9fb45d3798e 100644 (file)
@@ -419,16 +419,6 @@ static void dce_v10_0_hpd_init(struct amdgpu_device *adev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
-                        * aux dp channel on imac and help (but not completely fix)
-                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-                        * also avoid interrupt storms during dpms.
-                        */
-                       continue;
-               }
-
                switch (amdgpu_connector->hpd.hpd) {
                case AMDGPU_HPD_1:
                        idx = 0;
@@ -452,6 +442,19 @@ static void dce_v10_0_hpd_init(struct amdgpu_device *adev)
                        continue;
                }
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+                       tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+                       WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+                       continue;
+               }
+
                tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
                tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
                WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
index 8701661a88680d393f062ba55b7ff10d2fbf3f06..af30e3f95eab18b7be67658090b0f2af6ff1a974 100644 (file)
@@ -409,16 +409,6 @@ static void dce_v11_0_hpd_init(struct amdgpu_device *adev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
-                        * aux dp channel on imac and help (but not completely fix)
-                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-                        * also avoid interrupt storms during dpms.
-                        */
-                       continue;
-               }
-
                switch (amdgpu_connector->hpd.hpd) {
                case AMDGPU_HPD_1:
                        idx = 0;
@@ -442,6 +432,19 @@ static void dce_v11_0_hpd_init(struct amdgpu_device *adev)
                        continue;
                }
 
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       tmp = RREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx]);
+                       tmp = REG_SET_FIELD(tmp, DC_HPD_INT_CONTROL, DC_HPD_INT_EN, 0);
+                       WREG32(mmDC_HPD_INT_CONTROL + hpd_offsets[idx], tmp);
+                       continue;
+               }
+
                tmp = RREG32(mmDC_HPD_CONTROL + hpd_offsets[idx]);
                tmp = REG_SET_FIELD(tmp, DC_HPD_CONTROL, DC_HPD_EN, 1);
                WREG32(mmDC_HPD_CONTROL + hpd_offsets[idx], tmp);
@@ -3030,6 +3033,7 @@ static int dce_v11_0_sw_fini(void *handle)
 
        dce_v11_0_afmt_fini(adev);
 
+       drm_mode_config_cleanup(adev->ddev);
        adev->mode_info.mode_config_initialized = false;
 
        return 0;
index d0e128c248134e8a6fb9c9e4311e52bd7af0aceb..967a2d3482ae52fd55ccd07627ce1eeae352da2f 100644 (file)
@@ -392,15 +392,6 @@ static void dce_v8_0_hpd_init(struct amdgpu_device *adev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
-               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
-                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
-                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
-                        * aux dp channel on imac and help (but not completely fix)
-                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
-                        * also avoid interrupt storms during dpms.
-                        */
-                       continue;
-               }
                switch (amdgpu_connector->hpd.hpd) {
                case AMDGPU_HPD_1:
                        WREG32(mmDC_HPD1_CONTROL, tmp);
@@ -423,6 +414,45 @@ static void dce_v8_0_hpd_init(struct amdgpu_device *adev)
                default:
                        break;
                }
+
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+                   connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+                       /* don't try to enable hpd on eDP or LVDS avoid breaking the
+                        * aux dp channel on imac and help (but not completely fix)
+                        * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+                        * also avoid interrupt storms during dpms.
+                        */
+                       u32 dc_hpd_int_cntl_reg, dc_hpd_int_cntl;
+
+                       switch (amdgpu_connector->hpd.hpd) {
+                       case AMDGPU_HPD_1:
+                               dc_hpd_int_cntl_reg = mmDC_HPD1_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_2:
+                               dc_hpd_int_cntl_reg = mmDC_HPD2_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_3:
+                               dc_hpd_int_cntl_reg = mmDC_HPD3_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_4:
+                               dc_hpd_int_cntl_reg = mmDC_HPD4_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_5:
+                               dc_hpd_int_cntl_reg = mmDC_HPD5_INT_CONTROL;
+                               break;
+                       case AMDGPU_HPD_6:
+                               dc_hpd_int_cntl_reg = mmDC_HPD6_INT_CONTROL;
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       dc_hpd_int_cntl = RREG32(dc_hpd_int_cntl_reg);
+                       dc_hpd_int_cntl &= ~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK;
+                       WREG32(dc_hpd_int_cntl_reg, dc_hpd_int_cntl);
+                       continue;
+               }
+
                dce_v8_0_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
                amdgpu_irq_get(adev, &adev->hpd_irq, amdgpu_connector->hpd.hpd);
        }
index ea87033bfaf6eb1a8da77a73c3ac9b1766afcade..df17fababbd66b92bdb8974fc8c878b39e004e2e 100644 (file)
@@ -167,6 +167,7 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev)
                break;
        case CHIP_KAVERI:
        case CHIP_KABINI:
+       case CHIP_MULLINS:
                return 0;
        default: BUG();
        }
index 4dc90479568b24cc06b3724d3c47777460a4af94..621198cd0977d83634414cabb1ce8750480b42b3 100644 (file)
@@ -316,19 +316,19 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
                        u32 *coeff_tab = heo_upscaling_ycoef;
                        u32 max_memsize;
 
-                       if (state->crtc_w < state->src_w)
+                       if (state->crtc_h < state->src_h)
                                coeff_tab = heo_downscaling_ycoef;
                        for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
                                atmel_hlcdc_layer_update_cfg(&plane->layer,
                                                             33 + i,
                                                             0xffffffff,
                                                             coeff_tab[i]);
-                       factor = ((8 * 256 * state->src_w) - (256 * 4)) /
-                                state->crtc_w;
+                       factor = ((8 * 256 * state->src_h) - (256 * 4)) /
+                                state->crtc_h;
                        factor++;
-                       max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
+                       max_memsize = ((factor * state->crtc_h) + (256 * 4)) /
                                      2048;
-                       if (max_memsize > state->src_w)
+                       if (max_memsize > state->src_h)
                                factor--;
                        factor_reg |= (factor << 16) | 0x80000000;
                }
index bdcf366edb6f528bc96e45fe3bc998be0cbe2d8c..3f44b62b023e9360eb90d82ecb354c5f3bbfd02b 100644 (file)
@@ -108,7 +108,6 @@ steal_encoder(struct drm_atomic_state *state,
        struct drm_crtc_state *crtc_state;
        struct drm_connector *connector;
        struct drm_connector_state *connector_state;
-       int ret;
 
        /*
         * We can only steal an encoder coming from a connector, which means we
@@ -139,9 +138,6 @@ steal_encoder(struct drm_atomic_state *state,
                if (IS_ERR(connector_state))
                        return PTR_ERR(connector_state);
 
-               ret = drm_atomic_set_crtc_for_connector(connector_state, NULL);
-               if (ret)
-                       return ret;
                connector_state->best_encoder = NULL;
        }
 
index 6743ff7dccfa30b2997d2529d97747d5261d5ad9..7f4a6c55031938c93b00bec6a954050cff9f347d 100644 (file)
@@ -136,6 +136,7 @@ drm_clflush_virt_range(void *addr, unsigned long length)
                mb();
                for (; addr < end; addr += size)
                        clflushopt(addr);
+               clflushopt(end - 1); /* force serialisation */
                mb();
                return;
        }
index 4900d2f76e2494a37fc0940290c55493ae4cfb44..29d13ef24996f87feb2f9e16d232487d189531d6 100644 (file)
@@ -5365,6 +5365,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        unsigned long flags;
        int ret = -EINVAL;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
            page_flip->reserved != 0)
                return -EINVAL;
index d5d2c03fd1369b904e31af5184c05e4b9da0f82d..8c9ac021608f3aee7280ff5816de1441716bff4f 100644 (file)
@@ -73,6 +73,8 @@
 #define EDID_QUIRK_FORCE_8BPC                  (1 << 8)
 /* Force 12bpc */
 #define EDID_QUIRK_FORCE_12BPC                 (1 << 9)
+/* Force 6bpc */
+#define EDID_QUIRK_FORCE_6BPC                  (1 << 10)
 
 struct detailed_mode_closure {
        struct drm_connector *connector;
@@ -99,6 +101,9 @@ static struct edid_quirk {
        /* Unknown Acer */
        { "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED },
 
+       /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
+       { "AEO", 0, EDID_QUIRK_FORCE_6BPC },
+
        /* Belinea 10 15 55 */
        { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
        { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
@@ -3820,6 +3825,9 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 
        drm_add_display_info(edid, &connector->display_info, connector);
 
+       if (quirks & EDID_QUIRK_FORCE_6BPC)
+               connector->display_info.bpc = 6;
+
        if (quirks & EDID_QUIRK_FORCE_8BPC)
                connector->display_info.bpc = 8;
 
index c7de454e8e889591453612633e87e69b329c1ee0..b205224f1a44accecf2f688cae137485095da82e 100644 (file)
@@ -338,27 +338,32 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
        spin_unlock(&file_priv->table_lock);
        idr_preload_end();
        mutex_unlock(&dev->object_name_lock);
-       if (ret < 0) {
-               drm_gem_object_handle_unreference_unlocked(obj);
-               return ret;
-       }
+       if (ret < 0)
+               goto err_unref;
+
        *handlep = ret;
 
        ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp);
-       if (ret) {
-               drm_gem_handle_delete(file_priv, *handlep);
-               return ret;
-       }
+       if (ret)
+               goto err_remove;
 
        if (dev->driver->gem_open_object) {
                ret = dev->driver->gem_open_object(obj, file_priv);
-               if (ret) {
-                       drm_gem_handle_delete(file_priv, *handlep);
-                       return ret;
-               }
+               if (ret)
+                       goto err_revoke;
        }
 
        return 0;
+
+err_revoke:
+       drm_vma_node_revoke(&obj->vma_node, file_priv->filp);
+err_remove:
+       spin_lock(&file_priv->table_lock);
+       idr_remove(&file_priv->object_idr, *handlep);
+       spin_unlock(&file_priv->table_lock);
+err_unref:
+       drm_gem_object_handle_unreference_unlocked(obj);
+       return ret;
 }
 
 /**
index 57676f8d7ecfe70c54fd79a3d714f196ff1406a5..a6289752be16d20423e3439af521db5507854bd0 100644 (file)
@@ -1015,6 +1015,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
        return 0;
 }
 
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
 typedef struct drm_mode_fb_cmd232 {
        u32 fb_id;
        u32 width;
@@ -1071,6 +1072,7 @@ static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
 
        return 0;
 }
+#endif
 
 static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
@@ -1104,7 +1106,9 @@ static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW32)] = compat_drm_update_draw,
 #endif
        [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
        [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB232)] = compat_drm_mode_addfb2,
+#endif
 };
 
 /**
index 21eda25e6522be3103229e3e4214ff57cb2fb43d..4675bd3b050b902e171055c5ef5311af55f9cd37 100644 (file)
@@ -339,14 +339,17 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
  * using the PRIME helpers.
  */
 struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-                                    struct drm_gem_object *obj, int flags)
+                                    struct drm_gem_object *obj,
+                                    int flags)
 {
-       DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-
-       exp_info.ops = &drm_gem_prime_dmabuf_ops;
-       exp_info.size = obj->size;
-       exp_info.flags = flags;
-       exp_info.priv = obj;
+       struct dma_buf_export_info exp_info = {
+               .exp_name = KBUILD_MODNAME, /* white lie for debug */
+               .owner = dev->driver->fops->owner,
+               .ops = &drm_gem_prime_dmabuf_ops,
+               .size = obj->size,
+               .flags = flags,
+               .priv = obj,
+       };
 
        if (dev->driver->gem_prime_res_obj)
                exp_info.resv = dev->driver->gem_prime_res_obj(obj);
index 7bb1f1aff932f3dc13b9884661e37982a5678c26..c52f9adf5e04c620cee1043edaa84f828ccffb43 100644 (file)
@@ -220,7 +220,7 @@ i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
  * FIXME: This is the old dp aux helper, gma500 is the last driver that needs to
  * be ported over to the new helper code in drm_dp_helper.c like i915 or radeon.
  */
-static int __deprecated
+static int
 i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
 {
        int error;
index d3ce4da6a6ade3740405b5e98968707a958a07ae..fb9f647bb5cd6fde9454ae9de9395bdc94b06b10 100644 (file)
@@ -2150,21 +2150,19 @@ struct drm_i915_gem_object {
        /** Record of address bit 17 of each page at last unbind. */
        unsigned long *bit_17;
 
-       union {
-               /** for phy allocated objects */
-               struct drm_dma_handle *phys_handle;
-
-               struct i915_gem_userptr {
-                       uintptr_t ptr;
-                       unsigned read_only :1;
-                       unsigned workers :4;
+       struct i915_gem_userptr {
+               uintptr_t ptr;
+               unsigned read_only :1;
+               unsigned workers :4;
 #define I915_GEM_USERPTR_MAX_WORKERS 15
 
-                       struct i915_mm_struct *mm;
-                       struct i915_mmu_object *mmu_object;
-                       struct work_struct *work;
-               } userptr;
-       };
+               struct i915_mm_struct *mm;
+               struct i915_mmu_object *mmu_object;
+               struct work_struct *work;
+       } userptr;
+
+       /** for phys allocated objects */
+       struct drm_dma_handle *phys_handle;
 };
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
@@ -3313,6 +3311,9 @@ static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
 }
 extern void intel_i2c_reset(struct drm_device *dev);
 
+/* intel_bios.c */
+bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port);
+
 /* intel_opregion.c */
 #ifdef CONFIG_ACPI
 extern int intel_opregion_setup(struct drm_device *dev);
index 6ed7d63a0688384830894f4a455463bd7e9e060c..201947b4377c769d9393d718fc5b35c5000328ed 100644 (file)
@@ -513,9 +513,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
                                return ret;
 
                        if (r->presumed_offset != offset &&
-                           __copy_to_user_inatomic(&user_relocs->presumed_offset,
-                                                   &r->presumed_offset,
-                                                   sizeof(r->presumed_offset))) {
+                           __put_user(r->presumed_offset, &user_relocs->presumed_offset)) {
                                return -EFAULT;
                        }
 
index 86c7500454b4d1b3928dc41f37ab9aa6917fd557..b37fe0df743e79948fdaaf808406b1773ef5dd55 100644 (file)
@@ -2747,6 +2747,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
                struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
 
                ppgtt->base.cleanup(&ppgtt->base);
+               kfree(ppgtt);
        }
 
        if (drm_mm_initialized(&vm->mm)) {
index 87e919a06b277fea6cfade79445a165bac925056..5d2323a40c25e25b318ab9539b0a48699c636ff7 100644 (file)
@@ -108,17 +108,28 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
                pci_read_config_dword(dev->pdev, 0x5c, &base);
                base &= ~((1<<20) - 1);
        } else if (IS_I865G(dev)) {
+               u32 tseg_size = 0;
                u16 toud = 0;
+               u8 tmp;
+
+               pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+                                        I845_ESMRAMC, &tmp);
+
+               if (tmp & TSEG_ENABLE) {
+                       switch (tmp & I845_TSEG_SIZE_MASK) {
+                       case I845_TSEG_SIZE_512K:
+                               tseg_size = KB(512);
+                               break;
+                       case I845_TSEG_SIZE_1M:
+                               tseg_size = MB(1);
+                               break;
+                       }
+               }
 
-               /*
-                * FIXME is the graphics stolen memory region
-                * always at TOUD? Ie. is it always the last
-                * one to be allocated by the BIOS?
-                */
                pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
                                         I865_TOUD, &toud);
 
-               base = toud << 16;
+               base = (toud << 16) + tseg_size;
        } else if (IS_I85X(dev)) {
                u32 tseg_size = 0;
                u32 tom;
index 9ed9f6dde86f646e0b3ae540a179e5efe2d112b8..cace154bbdc0716b192a0268de600c8af1d15e32 100644 (file)
@@ -3240,19 +3240,20 @@ enum skl_disp_power_wells {
 
 #define PORT_HOTPLUG_STAT      (dev_priv->info.display_mmio_offset + 0x61114)
 /*
- * HDMI/DP bits are gen4+
+ * HDMI/DP bits are g4x+
  *
  * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
  * Please check the detailed lore in the commit message for for experimental
  * evidence.
  */
-#define   PORTD_HOTPLUG_LIVE_STATUS_G4X                (1 << 29)
+/* Bspec says GM45 should match G4X/VLV/CHV, but reality disagrees */
+#define   PORTD_HOTPLUG_LIVE_STATUS_GM45       (1 << 29)
+#define   PORTC_HOTPLUG_LIVE_STATUS_GM45       (1 << 28)
+#define   PORTB_HOTPLUG_LIVE_STATUS_GM45       (1 << 27)
+/* G4X/VLV/CHV DP/HDMI bits again match Bspec */
+#define   PORTD_HOTPLUG_LIVE_STATUS_G4X                (1 << 27)
 #define   PORTC_HOTPLUG_LIVE_STATUS_G4X                (1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS_G4X                (1 << 27)
-/* VLV DP/HDMI bits again match Bspec */
-#define   PORTD_HOTPLUG_LIVE_STATUS_VLV                (1 << 27)
-#define   PORTC_HOTPLUG_LIVE_STATUS_VLV                (1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS_VLV                (1 << 29)
+#define   PORTB_HOTPLUG_LIVE_STATUS_G4X                (1 << 29)
 #define   PORTD_HOTPLUG_INT_STATUS             (3 << 21)
 #define   PORTD_HOTPLUG_INT_LONG_PULSE         (2 << 21)
 #define   PORTD_HOTPLUG_INT_SHORT_PULSE                (1 << 21)
index ce82f9c7df2460b049b279957a8db78965b4f49c..d14bdc5375871f6917419aad54bf76f3c8b9e988 100644 (file)
@@ -1351,3 +1351,42 @@ intel_parse_bios(struct drm_device *dev)
 
        return 0;
 }
+
+/**
+ * intel_bios_is_port_present - is the specified digital port present
+ * @dev_priv:  i915 device instance
+ * @port:      port to check
+ *
+ * Return true if the device in %port is present.
+ */
+bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port)
+{
+       static const struct {
+               u16 dp, hdmi;
+       } port_mapping[] = {
+               [PORT_B] = { DVO_PORT_DPB, DVO_PORT_HDMIB, },
+               [PORT_C] = { DVO_PORT_DPC, DVO_PORT_HDMIC, },
+               [PORT_D] = { DVO_PORT_DPD, DVO_PORT_HDMID, },
+               [PORT_E] = { DVO_PORT_DPE, DVO_PORT_HDMIE, },
+       };
+       int i;
+
+       /* FIXME maybe deal with port A as well? */
+       if (WARN_ON(port == PORT_A) || port >= ARRAY_SIZE(port_mapping))
+               return false;
+
+       if (!dev_priv->vbt.child_dev_num)
+               return false;
+
+       for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+               const union child_device_config *p_child =
+                       &dev_priv->vbt.child_dev[i];
+               if ((p_child->common.dvo_port == port_mapping[port].dp ||
+                    p_child->common.dvo_port == port_mapping[port].hdmi) &&
+                   (p_child->common.device_type & (DEVICE_TYPE_TMDS_DVI_SIGNALING |
+                                                   DEVICE_TYPE_DISPLAYPORT_OUTPUT)))
+                       return true;
+       }
+
+       return false;
+}
index 240392ce305d2e68849b409712af801080518a4b..6f2502e16ecc6257314caadce86d640761adf76e 100644 (file)
@@ -2950,13 +2950,13 @@ u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
        }
 }
 
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
-                                    struct drm_i915_gem_object *obj,
-                                    unsigned int plane)
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+                          struct drm_i915_gem_object *obj,
+                          unsigned int plane)
 {
        const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
        struct i915_vma *vma;
-       unsigned char *offset;
+       u64 offset;
 
        if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
                view = &i915_ggtt_view_rotated;
@@ -2966,14 +2966,16 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
                view->type))
                return -1;
 
-       offset = (unsigned char *)vma->node.start;
+       offset = vma->node.start;
 
        if (plane == 1) {
                offset += vma->ggtt_view.rotation_info.uv_start_page *
                          PAGE_SIZE;
        }
 
-       return (unsigned long)offset;
+       WARN_ON(upper_32_bits(offset));
+
+       return lower_32_bits(offset);
 }
 
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -3099,7 +3101,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
        u32 tile_height, plane_offset, plane_size;
        unsigned int rotation;
        int x_offset, y_offset;
-       unsigned long surf_addr;
+       u32 surf_addr;
        struct intel_crtc_state *crtc_state = intel_crtc->config;
        struct intel_plane_state *plane_state;
        int src_x = 0, src_y = 0, src_w = 0, src_h = 0;
@@ -11952,21 +11954,11 @@ connected_sink_compute_bpp(struct intel_connector *connector,
                pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
        }
 
-       /* Clamp bpp to default limit on screens without EDID 1.4 */
-       if (connector->base.display_info.bpc == 0) {
-               int type = connector->base.connector_type;
-               int clamp_bpp = 24;
-
-               /* Fall back to 18 bpp when DP sink capability is unknown. */
-               if (type == DRM_MODE_CONNECTOR_DisplayPort ||
-                   type == DRM_MODE_CONNECTOR_eDP)
-                       clamp_bpp = 18;
-
-               if (bpp > clamp_bpp) {
-                       DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of %d\n",
-                                     bpp, clamp_bpp);
-                       pipe_config->pipe_bpp = clamp_bpp;
-               }
+       /* Clamp bpp to 8 on screens without EDID 1.4 */
+       if (connector->base.display_info.bpc == 0 && bpp > 24) {
+               DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
+                             bpp);
+               pipe_config->pipe_bpp = 24;
        }
 }
 
@@ -14170,6 +14162,8 @@ static void intel_setup_outputs(struct drm_device *dev)
                if (I915_READ(PCH_DP_D) & DP_DETECTED)
                        intel_dp_init(dev, PCH_DP_D, PORT_D);
        } else if (IS_VALLEYVIEW(dev)) {
+               bool has_edp, has_port;
+
                /*
                 * The DP_DETECTED bit is the latched state of the DDC
                 * SDA pin at boot. However since eDP doesn't require DDC
@@ -14178,27 +14172,37 @@ static void intel_setup_outputs(struct drm_device *dev)
                 * Thus we can't rely on the DP_DETECTED bit alone to detect
                 * eDP ports. Consult the VBT as well as DP_DETECTED to
                 * detect eDP ports.
+                *
+                * Sadly the straps seem to be missing sometimes even for HDMI
+                * ports (eg. on Voyo V3 - CHT x7-Z8700), so check both strap
+                * and VBT for the presence of the port. Additionally we can't
+                * trust the port type the VBT declares as we've seen at least
+                * HDMI ports that the VBT claim are DP or eDP.
                 */
-               if (I915_READ(VLV_HDMIB) & SDVO_DETECTED &&
-                   !intel_dp_is_edp(dev, PORT_B))
+               has_edp = intel_dp_is_edp(dev, PORT_B);
+               has_port = intel_bios_is_port_present(dev_priv, PORT_B);
+               if (I915_READ(VLV_DP_B) & DP_DETECTED || has_port)
+                       has_edp &= intel_dp_init(dev, VLV_DP_B, PORT_B);
+               if ((I915_READ(VLV_HDMIB) & SDVO_DETECTED || has_port) && !has_edp)
                        intel_hdmi_init(dev, VLV_HDMIB, PORT_B);
-               if (I915_READ(VLV_DP_B) & DP_DETECTED ||
-                   intel_dp_is_edp(dev, PORT_B))
-                       intel_dp_init(dev, VLV_DP_B, PORT_B);
 
-               if (I915_READ(VLV_HDMIC) & SDVO_DETECTED &&
-                   !intel_dp_is_edp(dev, PORT_C))
+               has_edp = intel_dp_is_edp(dev, PORT_C);
+               has_port = intel_bios_is_port_present(dev_priv, PORT_C);
+               if (I915_READ(VLV_DP_C) & DP_DETECTED || has_port)
+                       has_edp &= intel_dp_init(dev, VLV_DP_C, PORT_C);
+               if ((I915_READ(VLV_HDMIC) & SDVO_DETECTED || has_port) && !has_edp)
                        intel_hdmi_init(dev, VLV_HDMIC, PORT_C);
-               if (I915_READ(VLV_DP_C) & DP_DETECTED ||
-                   intel_dp_is_edp(dev, PORT_C))
-                       intel_dp_init(dev, VLV_DP_C, PORT_C);
 
                if (IS_CHERRYVIEW(dev)) {
-                       /* eDP not supported on port D, so don't check VBT */
-                       if (I915_READ(CHV_HDMID) & SDVO_DETECTED)
-                               intel_hdmi_init(dev, CHV_HDMID, PORT_D);
-                       if (I915_READ(CHV_DP_D) & DP_DETECTED)
+                       /*
+                        * eDP not supported on port D,
+                        * so no need to worry about it
+                        */
+                       has_port = intel_bios_is_port_present(dev_priv, PORT_D);
+                       if (I915_READ(CHV_DP_D) & DP_DETECTED || has_port)
                                intel_dp_init(dev, CHV_DP_D, PORT_D);
+                       if (I915_READ(CHV_HDMID) & SDVO_DETECTED || has_port)
+                               intel_hdmi_init(dev, CHV_HDMID, PORT_D);
                }
 
                intel_dsi_init(dev);
index 0ff09fe97a462733423b868152fd78281e2ed9e8..65f46e1987981faacf280a716385c5b6c07c9275 100644 (file)
@@ -4592,20 +4592,20 @@ static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
        return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
-static bool vlv_digital_port_connected(struct drm_i915_private *dev_priv,
-                                      struct intel_digital_port *port)
+static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv,
+                                       struct intel_digital_port *port)
 {
        u32 bit;
 
        switch (port->port) {
        case PORT_B:
-               bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+               bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
                break;
        case PORT_C:
-               bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+               bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
                break;
        case PORT_D:
-               bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+               bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
                break;
        default:
                MISSING_CASE(port->port);
@@ -4648,7 +4648,7 @@ static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
  *
  * Return %true if @port is connected, %false otherwise.
  */
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
+static bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
                                         struct intel_digital_port *port)
 {
        if (HAS_PCH_IBX(dev_priv))
@@ -4657,8 +4657,8 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
                return cpt_digital_port_connected(dev_priv, port);
        else if (IS_BROXTON(dev_priv))
                return bxt_digital_port_connected(dev_priv, port);
-       else if (IS_VALLEYVIEW(dev_priv))
-               return vlv_digital_port_connected(dev_priv, port);
+       else if (IS_GM45(dev_priv))
+               return gm45_digital_port_connected(dev_priv, port);
        else
                return g4x_digital_port_connected(dev_priv, port);
 }
@@ -6113,8 +6113,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        return true;
 }
 
-void
-intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
+bool intel_dp_init(struct drm_device *dev,
+                  int output_reg,
+                  enum port port)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_digital_port *intel_dig_port;
@@ -6124,7 +6125,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 
        intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
        if (!intel_dig_port)
-               return;
+               return false;
 
        intel_connector = intel_connector_alloc();
        if (!intel_connector)
@@ -6179,15 +6180,14 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        if (!intel_dp_init_connector(intel_dig_port, intel_connector))
                goto err_init_connector;
 
-       return;
+       return true;
 
 err_init_connector:
        drm_encoder_cleanup(encoder);
        kfree(intel_connector);
 err_connector_alloc:
        kfree(intel_dig_port);
-
-       return;
+       return false;
 }
 
 void intel_dp_mst_suspend(struct drm_device *dev)
index c5f11e0c5d5ba99474843ac4ed7861127e1181ea..722aa159cd28a3154e6bccb6e69b8c478b5bc21b 100644 (file)
@@ -1177,9 +1177,9 @@ void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
 int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
 
-unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
-                                    struct drm_i915_gem_object *obj,
-                                    unsigned int plane);
+u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
+                          struct drm_i915_gem_object *obj,
+                          unsigned int plane);
 
 u32 skl_plane_ctl_format(uint32_t pixel_format);
 u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
@@ -1195,7 +1195,7 @@ void intel_csr_ucode_fini(struct drm_device *dev);
 void assert_csr_loaded(struct drm_i915_private *dev_priv);
 
 /* intel_dp.c */
-void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
+bool intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                             struct intel_connector *intel_connector);
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
@@ -1231,8 +1231,6 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp);
 void intel_edp_drrs_invalidate(struct drm_device *dev,
                unsigned frontbuffer_bits);
 void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
-bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
-                                        struct intel_digital_port *port);
 void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
 
 /* intel_dp_mst.c */
index 5763037586ee099f132577b8a4baea80af4b1351..7b7eefec60cfb57b382304f696f335cc3b07a166 100644 (file)
@@ -1331,19 +1331,18 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
 }
 
 static bool
-intel_hdmi_set_edid(struct drm_connector *connector, bool force)
+intel_hdmi_set_edid(struct drm_connector *connector)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
        struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-       struct edid *edid = NULL;
+       struct edid *edid;
        bool connected = false;
 
        intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-       if (force)
-               edid = drm_get_edid(connector,
-                                   intel_gmbus_get_adapter(dev_priv,
-                                   intel_hdmi->ddc_bus));
+       edid = drm_get_edid(connector,
+                           intel_gmbus_get_adapter(dev_priv,
+                           intel_hdmi->ddc_bus));
 
        intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
 
@@ -1371,37 +1370,16 @@ static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
        enum drm_connector_status status;
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
        struct drm_i915_private *dev_priv = to_i915(connector->dev);
-       bool live_status = false;
-       unsigned int try;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, connector->name);
 
        intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-       for (try = 0; !live_status && try < 9; try++) {
-               if (try)
-                       msleep(10);
-               live_status = intel_digital_port_connected(dev_priv,
-                               hdmi_to_dig_port(intel_hdmi));
-       }
-
-       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);
 
-       if (intel_hdmi_set_edid(connector, live_status)) {
+       if (intel_hdmi_set_edid(connector)) {
                struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 
                hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
@@ -1427,7 +1405,7 @@ intel_hdmi_force(struct drm_connector *connector)
        if (connector->status != connector_status_connected)
                return;
 
-       intel_hdmi_set_edid(connector, true);
+       intel_hdmi_set_edid(connector);
        hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
 }
 
@@ -2030,6 +2008,9 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
        enum port port = intel_dig_port->port;
        uint8_t alternate_ddc_pin;
 
+       DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
+                     port_name(port));
+
        drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
                           DRM_MODE_CONNECTOR_HDMIA);
        drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
index 6dc13c02c28e60c2322442d835a983c5f903e38c..e362a30776fa63b41875822c2d9e6cfd94f752b7 100644 (file)
@@ -682,7 +682,7 @@ static void intel_didl_outputs(struct drm_device *dev)
        }
 
        if (!acpi_video_bus) {
-               DRM_ERROR("No ACPI video bus found\n");
+               DRM_DEBUG_KMS("No ACPI video bus found\n");
                return;
        }
 
index 62284e45d5312ea95cf02efce2da1605dd7857cd..3f802163f7d47b0c59d300c204b48d1aa6233e08 100644 (file)
@@ -1789,16 +1789,20 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
                                   const struct intel_plane_state *pstate,
                                   uint32_t mem_value)
 {
-       int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+       /*
+        * We treat the cursor plane as always-on for the purposes of watermark
+        * calculation.  Until we have two-stage watermark programming merged,
+        * this is necessary to avoid flickering.
+        */
+       int cpp = 4;
+       int width = pstate->visible ? pstate->base.crtc_w : 64;
 
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active)
                return 0;
 
        return ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                              cstate->base.adjusted_mode.crtc_htotal,
-                             drm_rect_width(&pstate->dst),
-                             bpp,
-                             mem_value);
+                             width, cpp, mem_value);
 }
 
 /* Only for WM_LP. */
@@ -2092,33 +2096,35 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
                wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
                                GEN9_MEM_LATENCY_LEVEL_MASK;
 
+               /*
+                * If a level n (n > 1) has a 0us latency, all levels m (m >= n)
+                * need to be disabled. We make sure to sanitize the values out
+                * of the punit to satisfy this requirement.
+                */
+               for (level = 1; level <= max_level; level++) {
+                       if (wm[level] == 0) {
+                               for (i = level + 1; i <= max_level; i++)
+                                       wm[i] = 0;
+                               break;
+                       }
+               }
+
                /*
                 * WaWmMemoryReadLatency:skl
                 *
                 * punit doesn't take into account the read latency so we need
-                * to add 2us to the various latency levels we retrieve from
-                * the punit.
-                *   - W0 is a bit special in that it's the only level that
-                *   can't be disabled if we want to have display working, so
-                *   we always add 2us there.
-                *   - For levels >=1, punit returns 0us latency when they are
-                *   disabled, so we respect that and don't add 2us then
-                *
-                * Additionally, if a level n (n > 1) has a 0us latency, all
-                * levels m (m >= n) need to be disabled. We make sure to
-                * sanitize the values out of the punit to satisfy this
-                * requirement.
+                * to add 2us to the various latency levels we retrieve from the
+                * punit when level 0 response data us 0us.
                 */
-               wm[0] += 2;
-               for (level = 1; level <= max_level; level++)
-                       if (wm[level] != 0)
+               if (wm[0] == 0) {
+                       wm[0] += 2;
+                       for (level = 1; level <= max_level; level++) {
+                               if (wm[level] == 0)
+                                       break;
                                wm[level] += 2;
-                       else {
-                               for (i = level + 1; i <= max_level; i++)
-                                       wm[i] = 0;
-
-                               break;
                        }
+               }
+
        } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                uint64_t sskpd = I915_READ64(MCH_SSKPD);
 
@@ -4522,7 +4528,8 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
                else
                        gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
                dev_priv->rps.last_adj = 0;
-               I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+               I915_WRITE(GEN6_PMINTRMSK,
+                          gen6_sanitize_rps_pm_mask(dev_priv, ~0));
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 
index 9e9795dbf5bbbcf92cf6b012bdb7e6b472bda27a..19d7ef20a1e0cacf927b420e5be3ebdaca8362dd 100644 (file)
@@ -195,7 +195,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
        const struct drm_intel_sprite_colorkey *key =
                &to_intel_plane_state(drm_plane->state)->ckey;
-       unsigned long surf_addr;
+       u32 surf_addr;
        u32 tile_height, plane_offset, plane_size;
        unsigned int rotation;
        int x_offset, y_offset;
index 6d7cd3fe21e70b665aebf4eb76ffa28b8e1e266f..1847f83b1e33a2a206b5361facace9df9ebcc236 100644 (file)
@@ -55,6 +55,14 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
        return submit;
 }
 
+static inline unsigned long __must_check
+copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
+{
+       if (access_ok(VERIFY_READ, from, n))
+               return __copy_from_user_inatomic(to, from, n);
+       return -EFAULT;
+}
+
 static int submit_lookup_objects(struct msm_gem_submit *submit,
                struct drm_msm_gem_submit *args, struct drm_file *file)
 {
@@ -62,6 +70,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
        int ret = 0;
 
        spin_lock(&file->table_lock);
+       pagefault_disable();
 
        for (i = 0; i < args->nr_bos; i++) {
                struct drm_msm_gem_submit_bo submit_bo;
@@ -70,10 +79,15 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                void __user *userptr =
                        to_user_ptr(args->bos + (i * sizeof(submit_bo)));
 
-               ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
-               if (ret) {
-                       ret = -EFAULT;
-                       goto out_unlock;
+               ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo));
+               if (unlikely(ret)) {
+                       pagefault_enable();
+                       spin_unlock(&file->table_lock);
+                       ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
+                       if (ret)
+                               goto out;
+                       spin_lock(&file->table_lock);
+                       pagefault_disable();
                }
 
                if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
@@ -113,9 +127,12 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
        }
 
 out_unlock:
-       submit->nr_bos = i;
+       pagefault_enable();
        spin_unlock(&file->table_lock);
 
+out:
+       submit->nr_bos = i;
+
        return ret;
 }
 
index 1d3ee5179ab8521c59471994abb530da1c9f92a1..d236fc7c425bbc5d922c3f7d67b35d211c91fae2 100644 (file)
@@ -308,7 +308,16 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        bool boot = false;
        int ret;
 
-       /* remove conflicting drivers (vesafb, efifb etc) */
+       /* We need to check that the chipset is supported before booting
+        * fbdev off the hardware, as there's no way to put it back.
+        */
+       ret = nvkm_device_pci_new(pdev, NULL, "error", true, false, 0, &device);
+       if (ret)
+               return ret;
+
+       nvkm_device_del(&device);
+
+       /* Remove conflicting drivers (vesafb, efifb etc). */
        aper = alloc_apertures(3);
        if (!aper)
                return -ENOMEM;
index 8f715feadf56bede1b28b618354d8787bb196797..f905683274689773773124be1a57ab5d13d08d83 100644 (file)
@@ -107,11 +107,11 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
                         ((image->dx + image->width) & 0xffff));
        OUT_RING(chan, bg);
        OUT_RING(chan, fg);
-       OUT_RING(chan, (image->height << 16) | image->width);
+       OUT_RING(chan, (image->height << 16) | ALIGN(image->width, 8));
        OUT_RING(chan, (image->height << 16) | image->width);
        OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
 
-       dsize = ALIGN(image->width * image->height, 32) >> 5;
+       dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
        while (dsize) {
                int iter_len = dsize > 128 ? 128 : dsize;
 
index a4e259a00430a9c7e5da7044b90434cef41c703c..c8e096533f60e72c4c1a32c138aa3cca0edf80ec 100644 (file)
@@ -125,7 +125,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
        OUT_RING(chan, 0);
        OUT_RING(chan, image->dy);
 
-       dwords = ALIGN(image->width * image->height, 32) >> 5;
+       dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
        while (dwords) {
                int push = dwords > 2047 ? 2047 : dwords;
 
index f28315e865a5fbe6a759f778c86d4b1489d4941a..22d32578dafda7757cd9b3d8121fcf89eb2be26f 100644 (file)
@@ -125,7 +125,7 @@ nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
        OUT_RING  (chan, 0);
        OUT_RING  (chan, image->dy);
 
-       dwords = ALIGN(image->width * image->height, 32) >> 5;
+       dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
        while (dwords) {
                int push = dwords > 2047 ? 2047 : dwords;
 
index bfcc6408a77203a88de81b7d1938f558de1039ab..b7f4b826febedfc1f2fb4b7dbe6309c5f01007c4 100644 (file)
@@ -36,7 +36,10 @@ nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *base, int cookie)
 {
        struct nv04_fifo_chan *chan = nv04_fifo_chan(base);
        struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem;
+
+       mutex_lock(&chan->fifo->base.engine.subdev.mutex);
        nvkm_ramht_remove(imem->ramht, cookie);
+       mutex_unlock(&chan->fifo->base.engine.subdev.mutex);
 }
 
 static int
index 69de8c6259febb8dab996b66eee38b6a9e21a868..f1e15a4d4f64fe95a2fe38a1fa2566ba376e2698 100644 (file)
@@ -76,8 +76,8 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
                nvkm_wo32(chan->inst, i, 0x00040004);
        for (i = 0x1f18; i <= 0x3088 ; i += 16) {
                nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
-               nvkm_wo32(chan->inst, i + 1, 0x0436086c);
-               nvkm_wo32(chan->inst, i + 2, 0x000c001b);
+               nvkm_wo32(chan->inst, i + 4, 0x0436086c);
+               nvkm_wo32(chan->inst, i + 8, 0x000c001b);
        }
        for (i = 0x30b8; i < 0x30c8; i += 4)
                nvkm_wo32(chan->inst, i, 0x0000ffff);
index 2207dac23981a10f4b01dde77ea47f1df84f9723..300f5ed5de0b0fe618e1707aa0d78b12b62b370f 100644 (file)
@@ -75,8 +75,8 @@ nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
                nvkm_wo32(chan->inst, i, 0x00040004);
        for (i = 0x15ac; i <= 0x271c ; i += 16) {
                nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
-               nvkm_wo32(chan->inst, i + 1, 0x0436086c);
-               nvkm_wo32(chan->inst, i + 2, 0x000c001b);
+               nvkm_wo32(chan->inst, i + 4, 0x0436086c);
+               nvkm_wo32(chan->inst, i + 8, 0x000c001b);
        }
        for (i = 0x274c; i < 0x275c; i += 4)
                nvkm_wo32(chan->inst, i, 0x0000ffff);
index 4bef72a9d106817fdf2e2091d971e60711c0d855..3fda594700e023f71d3cc5b885ef80232e4873d9 100644 (file)
@@ -59,9 +59,11 @@ static void
 nv40_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom)
 {
        struct nvkm_device *device = pm->engine.subdev.device;
-       if (pm->sequence != pm->sequence) {
+       struct nv40_pm *nv40pm = container_of(pm, struct nv40_pm, base);
+
+       if (nv40pm->sequence != pm->sequence) {
                nvkm_wr32(device, 0x400084, 0x00000020);
-               pm->sequence = pm->sequence;
+               nv40pm->sequence = pm->sequence;
        }
 }
 
index 56e1d633875e2772b6a3f767e3af44e013f3519d..6e6c76080d6a1bc78108388e496c1b4373f223ba 100644 (file)
@@ -136,6 +136,8 @@ static int qxl_palette_create_1bit(struct qxl_bo *palette_bo,
                                 * correctly globaly, since that would require
                                 * tracking all of our palettes. */
        ret = qxl_bo_kmap(palette_bo, (void **)&pal);
+       if (ret)
+               return ret;
        pal->num_ents = 2;
        pal->unique = unique++;
        if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) {
index bd73b4069069b900b01e4858bc38bb42dfc3ac10..44ee72e04df9e953bafe64cdfdadf2f01c1f9bce 100644 (file)
@@ -302,77 +302,31 @@ static int convert_bpc_to_bpp(int bpc)
                return bpc * 3;
 }
 
-/* get the max pix clock supported by the link rate and lane num */
-static int dp_get_max_dp_pix_clock(int link_rate,
-                                  int lane_num,
-                                  int bpp)
-{
-       return (link_rate * lane_num * 8) / bpp;
-}
-
 /***** radeon specific DP functions *****/
 
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                               const u8 dpcd[DP_DPCD_SIZE])
-{
-       int max_link_rate;
-
-       if (radeon_connector_is_dp12_capable(connector))
-               max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
-       else
-               max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
-
-       return max_link_rate;
-}
-
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
-                                       const u8 dpcd[DP_DPCD_SIZE],
-                                       int pix_clock)
-{
-       int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
-       int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
-       int max_lane_num = drm_dp_max_lane_count(dpcd);
-       int lane_num;
-       int max_dp_pix_clock;
-
-       for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
-               max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
-               if (pix_clock <= max_dp_pix_clock)
-                       break;
-       }
-
-       return lane_num;
-}
-
-static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
-                                      const u8 dpcd[DP_DPCD_SIZE],
-                                      int pix_clock)
+int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+                                const u8 dpcd[DP_DPCD_SIZE],
+                                unsigned pix_clock,
+                                unsigned *dp_lanes, unsigned *dp_rate)
 {
        int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
-       int lane_num, max_pix_clock;
-
-       if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
-           ENCODER_OBJECT_ID_NUTMEG)
-               return 270000;
-
-       lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
-       max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
-       if (pix_clock <= max_pix_clock)
-               return 162000;
-       max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
-       if (pix_clock <= max_pix_clock)
-               return 270000;
-       if (radeon_connector_is_dp12_capable(connector)) {
-               max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
-               if (pix_clock <= max_pix_clock)
-                       return 540000;
+       static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+       unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+       unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+       unsigned lane_num, i, max_pix_clock;
+
+       for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+               for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
+                       max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+                       if (max_pix_clock >= pix_clock) {
+                               *dp_lanes = lane_num;
+                               *dp_rate = link_rates[i];
+                               return 0;
+                       }
+               }
        }
 
-       return radeon_dp_get_max_link_rate(connector, dpcd);
+       return -EINVAL;
 }
 
 static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
@@ -491,6 +445,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct radeon_connector_atom_dig *dig_connector;
+       int ret;
 
        if (!radeon_connector->con_priv)
                return;
@@ -498,10 +453,14 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
 
        if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
            (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-               dig_connector->dp_clock =
-                       radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
-               dig_connector->dp_lane_count =
-                       radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+               ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+                                                  mode->clock,
+                                                  &dig_connector->dp_lane_count,
+                                                  &dig_connector->dp_clock);
+               if (ret) {
+                       dig_connector->dp_clock = 0;
+                       dig_connector->dp_lane_count = 0;
+               }
        }
 }
 
@@ -510,7 +469,8 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct radeon_connector_atom_dig *dig_connector;
-       int dp_clock;
+       unsigned dp_clock, dp_lanes;
+       int ret;
 
        if ((mode->clock > 340000) &&
            (!radeon_connector_is_dp12_capable(connector)))
@@ -520,8 +480,12 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
                return MODE_CLOCK_HIGH;
        dig_connector = radeon_connector->con_priv;
 
-       dp_clock =
-               radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+       ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+                                          mode->clock,
+                                          &dp_lanes,
+                                          &dp_clock);
+       if (ret)
+               return MODE_CLOCK_HIGH;
 
        if ((dp_clock == 540000) &&
            (!radeon_connector_is_dp12_capable(connector)))
index 9de6503b10d8507898ac0488b7e51cf399ae067a..7c7242b256e0ab60d79b25bbb36a8ef27d580eae 100644 (file)
@@ -120,6 +120,7 @@ atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level)
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
                        if (dig->backlight_level == 0)
                                atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
                        else {
index fa2154493cf1537dee269149b1924468a6035325..470af4aa4a6aa252671f0f46e90fcb816745d68e 100644 (file)
@@ -156,19 +156,20 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)
        struct drm_device *dev = rdev->ddev;
        struct drm_crtc *crtc;
        struct radeon_crtc *radeon_crtc;
-       u32 line_time_us, vblank_lines;
+       u32 vblank_in_pixels;
        u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
 
        if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                        radeon_crtc = to_radeon_crtc(crtc);
                        if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
-                               line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) /
-                                       radeon_crtc->hw_mode.clock;
-                               vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end -
-                                       radeon_crtc->hw_mode.crtc_vdisplay +
-                                       (radeon_crtc->v_border * 2);
-                               vblank_time_us = vblank_lines * line_time_us;
+                               vblank_in_pixels =
+                                       radeon_crtc->hw_mode.crtc_htotal *
+                                       (radeon_crtc->hw_mode.crtc_vblank_end -
+                                        radeon_crtc->hw_mode.crtc_vdisplay +
+                                        (radeon_crtc->v_border * 2));
+
+                               vblank_time_us = vblank_in_pixels * 1000 / radeon_crtc->hw_mode.clock;
                                break;
                        }
                }
index de9a2ffcf5f762539d6d4c92464ed5eff19e1c42..0c5b3eeff82d06a4b06a8514ce65e011cd261bf1 100644 (file)
@@ -1155,7 +1155,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                    le16_to_cpu(firmware_info->info.usReferenceClock);
                p1pll->reference_div = 0;
 
-               if (crev < 2)
+               if ((frev < 2) && (crev < 2))
                        p1pll->pll_out_min =
                                le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
                else
@@ -1164,7 +1164,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                p1pll->pll_out_max =
                    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
 
-               if (crev >= 4) {
+               if (((frev < 2) && (crev >= 4)) || (frev >= 2)) {
                        p1pll->lcd_pll_out_min =
                                le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100;
                        if (p1pll->lcd_pll_out_min == 0)
index c4b4f298a2831a2ca3723bebe3ef8834bc6a6f3c..69ce955711368468e831bac62890de158efd9061 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 
 #include "radeon_acpi.h"
 
@@ -255,6 +256,10 @@ static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state)
                if (!info)
                        return -EIO;
                kfree(info);
+
+               /* 200ms delay is required after off */
+               if (state == 0)
+                       msleep(200);
        }
        return 0;
 }
index 9cfc1c3e19657c10432029b95431902e47db2879..30f00748ed37e7c406beed32ab3ac539ab86d120 100644 (file)
@@ -2058,7 +2058,6 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                           RADEON_OUTPUT_CSC_BYPASS);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
                        connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
                        break;
@@ -2308,8 +2307,10 @@ radeon_add_atom_connector(struct drm_device *dev,
        }
 
        if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
-               if (i2c_bus->valid)
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+               if (i2c_bus->valid) {
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+                                           DRM_CONNECTOR_POLL_DISCONNECT;
+               }
        } else
                connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -2385,7 +2386,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
                                              1);
                /* no HPD on analog connectors */
                radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
                connector->interlace_allowed = true;
                connector->doublescan_allowed = true;
                break;
@@ -2470,10 +2470,13 @@ radeon_add_legacy_connector(struct drm_device *dev,
        }
 
        if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
-               if (i2c_bus->valid)
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+               if (i2c_bus->valid) {
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+                                           DRM_CONNECTOR_POLL_DISCONNECT;
+               }
        } else
                connector->polled = DRM_CONNECTOR_POLL_HPD;
+
        connector->display_info.subpixel_order = subpixel_order;
        drm_connector_register(connector);
 }
index e2dd5d19c32ca2ab0bd77375dfad45ae0311e41d..4aa2cbe4c85fae3212aae4012bf957e16d2d6f83 100644 (file)
@@ -660,8 +660,9 @@ bool radeon_card_posted(struct radeon_device *rdev)
 {
        uint32_t reg;
 
-       /* for pass through, always force asic_init */
-       if (radeon_device_is_virtual())
+       /* for pass through, always force asic_init for CI */
+       if (rdev->family >= CHIP_BONAIRE &&
+           radeon_device_is_virtual())
                return false;
 
        /* required for EFI mode on macbook2,1 which uses an r5xx asic */
index 94323f51ffcfb37e1292c225e793c925179dd563..7a47a062de5d493ca564981d14c94252a3b26dfd 100644 (file)
@@ -525,11 +525,9 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
        drm_mode_set_crtcinfo(adjusted_mode, 0);
        {
          struct radeon_connector_atom_dig *dig_connector;
-
          dig_connector = mst_enc->connector->con_priv;
          dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
-         dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
-                                                               dig_connector->dpcd);
+         dig_connector->dp_clock = drm_dp_max_link_rate(dig_connector->dpcd);
          DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
                        dig_connector->dp_lane_count, dig_connector->dp_clock);
        }
index bba112628b478476b0685dc8416ef4badc170d46..7a0666ac4e235c3b6ff0795f592ec185f193a031 100644 (file)
@@ -757,8 +757,10 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                                    struct drm_connector *connector);
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                               const u8 *dpcd);
+extern int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+                                       const u8 *dpcd,
+                                       unsigned pix_clock,
+                                       unsigned *dp_lanes, unsigned *dp_rate);
 extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
                                         u8 power_state);
 extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
index f342aad79cc6d2debc95269ac2552750647d28d2..35310336dd0a25475b88e485ed63f502c8759df8 100644 (file)
@@ -263,8 +263,8 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
 
        rdev = radeon_get_rdev(bo->bdev);
        ridx = radeon_copy_ring_index(rdev);
-       old_start = old_mem->start << PAGE_SHIFT;
-       new_start = new_mem->start << PAGE_SHIFT;
+       old_start = (u64)old_mem->start << PAGE_SHIFT;
+       new_start = (u64)new_mem->start << PAGE_SHIFT;
 
        switch (old_mem->mem_type) {
        case TTM_PL_VRAM:
index caa73de584a53dd8ca9f26cdb6ca97d4f17c6b41..472e0771832eef0ab248f664ccf16d3730fcc0e4 100644 (file)
@@ -3015,6 +3015,12 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
        if (rdev->pdev->device == 0x6811 &&
            rdev->pdev->revision == 0x81)
                max_mclk = 120000;
+       /* limit sclk/mclk on Jet parts for stability */
+       if (rdev->pdev->device == 0x6665 &&
+           rdev->pdev->revision == 0xc3) {
+               max_sclk = 75000;
+               max_mclk = 80000;
+       }
 
        if (rps->vce_active) {
                rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
@@ -4106,7 +4112,7 @@ static int si_populate_smc_voltage_tables(struct radeon_device *rdev,
                                                              &rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
                                si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
 
-                               table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
+                               table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING] =
                                        cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
 
                                si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
index 3c779838d9ab16ad13a0588b1f69ac323509d933..966e3a556011d641be34f822c6d7283d0cace9f3 100644 (file)
@@ -194,6 +194,7 @@ typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE;
 #define SISLANDS_SMC_VOLTAGEMASK_VDDC  0
 #define SISLANDS_SMC_VOLTAGEMASK_MVDD  1
 #define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define SISLANDS_SMC_VOLTAGEMASK_VDDC_PHASE_SHEDDING 3
 #define SISLANDS_SMC_VOLTAGEMASK_MAX   4
 
 struct SISLANDS_SMC_VOLTAGEMASKTABLE
index 4948c15298369cf4dc907b9aa07b2496441656dc..ecf15cf0c3fd49e0dbb83a16411901dd0e586281 100644 (file)
@@ -3830,14 +3830,14 @@ static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv,
        int ret;
 
        *header = NULL;
-       if (!dev_priv->cman || kernel_commands)
-               return kernel_commands;
-
        if (command_size > SVGA_CB_MAX_SIZE) {
                DRM_ERROR("Command buffer is too large.\n");
                return ERR_PTR(-EINVAL);
        }
 
+       if (!dev_priv->cman || kernel_commands)
+               return kernel_commands;
+
        /* If possible, add a little space for fencing. */
        cmdbuf_size = command_size + 512;
        cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE);
index 7ce13da61203b4ce33d48ec13c76baae9b11492d..e43de846accc00b70d13b2a372ddf1c2ba840511 100644 (file)
@@ -1251,6 +1251,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
                /* Ignore report if ErrorRollOver */
                if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
                    value[n] >= min && value[n] <= max &&
+                   value[n] - min < field->maxusage &&
                    field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
                        goto exit;
        }
@@ -1263,11 +1264,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
                }
 
                if (field->value[n] >= min && field->value[n] <= max
+                       && field->value[n] - min < field->maxusage
                        && field->usage[field->value[n] - min].hid
                        && search(value, field->value[n], count))
                                hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
 
                if (value[n] >= min && value[n] <= max
+                       && value[n] - min < field->maxusage
                        && field->usage[value[n] - min].hid
                        && search(field->value, value[n], count))
                                hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
index 774cd221056659f5bacd480b8b07744c1a5a138f..21febbb0d84e6e59f9615cd9046d09b0690675f7 100644 (file)
@@ -1418,8 +1418,10 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
        }
 
        ret = hid_hw_output_report(hdev, buf, 1);
-       if (ret < 0)
-               hid_err(hdev, "can't set operational mode: step 3\n");
+       if (ret < 0) {
+               hid_info(hdev, "can't set operational mode: step 3, ignoring\n");
+               ret = 0;
+       }
 
 out:
        kfree(buf);
index e094c572b86e61ff5b4108a29ef78340114d018e..1a2032c2c1fb5674d33a1cdbfe3a1fe90255802f 100644 (file)
@@ -51,10 +51,26 @@ struct uhid_device {
        u32 report_id;
        u32 report_type;
        struct uhid_event report_buf;
+       struct work_struct worker;
 };
 
 static struct miscdevice uhid_misc;
 
+static void uhid_device_add_worker(struct work_struct *work)
+{
+       struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
+       int ret;
+
+       ret = hid_add_device(uhid->hid);
+       if (ret) {
+               hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
+
+               hid_destroy_device(uhid->hid);
+               uhid->hid = NULL;
+               uhid->running = false;
+       }
+}
+
 static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
 {
        __u8 newhead;
@@ -498,18 +514,14 @@ static int uhid_dev_create2(struct uhid_device *uhid,
        uhid->hid = hid;
        uhid->running = true;
 
-       ret = hid_add_device(hid);
-       if (ret) {
-               hid_err(hid, "Cannot register HID device\n");
-               goto err_hid;
-       }
+       /* Adding of a HID device is done through a worker, to allow HID drivers
+        * which use feature requests during .probe to work, without they would
+        * be blocked on devlock, which is held by uhid_char_write.
+        */
+       schedule_work(&uhid->worker);
 
        return 0;
 
-err_hid:
-       hid_destroy_device(hid);
-       uhid->hid = NULL;
-       uhid->running = false;
 err_free:
        kfree(uhid->rd_data);
        uhid->rd_data = NULL;
@@ -550,6 +562,8 @@ static int uhid_dev_destroy(struct uhid_device *uhid)
        uhid->running = false;
        wake_up_interruptible(&uhid->report_wait);
 
+       cancel_work_sync(&uhid->worker);
+
        hid_destroy_device(uhid->hid);
        kfree(uhid->rd_data);
 
@@ -612,6 +626,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
        init_waitqueue_head(&uhid->waitq);
        init_waitqueue_head(&uhid->report_wait);
        uhid->running = false;
+       INIT_WORK(&uhid->worker, uhid_device_add_worker);
 
        file->private_data = uhid;
        nonseekable_open(inode, file);
index 9098f13f2f44aaf16673addebd4c54d09417e36d..1ef37c7275725f07d76b448b251f12001b1f88d0 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/module.h>
 #include <linux/hyperv.h>
 #include <linux/uio.h>
+#include <linux/interrupt.h>
 
 #include "hyperv_vmbus.h"
 
@@ -496,8 +497,21 @@ static void reset_channel_cb(void *arg)
 static int vmbus_close_internal(struct vmbus_channel *channel)
 {
        struct vmbus_channel_close_channel *msg;
+       struct tasklet_struct *tasklet;
        int ret;
 
+       /*
+        * process_chn_event(), running in the tasklet, can race
+        * with vmbus_close_internal() in the case of SMP guest, e.g., when
+        * the former is accessing channel->inbound.ring_buffer, the latter
+        * could be freeing the ring_buffer pages.
+        *
+        * To resolve the race, we can serialize them by disabling the
+        * tasklet when the latter is running here.
+        */
+       tasklet = hv_context.event_dpc[channel->target_cpu];
+       tasklet_disable(tasklet);
+
        channel->state = CHANNEL_OPEN_STATE;
        channel->sc_creation_callback = NULL;
        /* Stop callback and cancel the timer asap */
@@ -525,7 +539,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
                 * If we failed to post the close msg,
                 * it is perhaps better to leak memory.
                 */
-               return ret;
+               goto out;
        }
 
        /* Tear down the gpadl for the channel's ring buffer */
@@ -538,7 +552,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
                         * If we failed to teardown gpadl,
                         * it is perhaps better to leak memory.
                         */
-                       return ret;
+                       goto out;
                }
        }
 
@@ -549,12 +563,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
        free_pages((unsigned long)channel->ringbuffer_pages,
                get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
 
-       /*
-        * If the channel has been rescinded; process device removal.
-        */
-       if (channel->rescind)
-               hv_process_channel_removal(channel,
-                                          channel->offermsg.child_relid);
+out:
+       tasklet_enable(tasklet);
+
        return ret;
 }
 
index 652afd11a9efdceb545add8bad4980b41f698340..37238dffd947611b771f1ba394b9bf7fb95671d4 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/hyperv.h>
 
 #include "hyperv_vmbus.h"
@@ -191,6 +192,8 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
        if (channel == NULL)
                return;
 
+       BUG_ON(!channel->rescind);
+
        if (channel->target_cpu != get_cpu()) {
                put_cpu();
                smp_call_function_single(channel->target_cpu,
@@ -230,9 +233,7 @@ void vmbus_free_channels(void)
 
        list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
                listentry) {
-               /* if we don't set rescind to true, vmbus_close_internal()
-                * won't invoke hv_process_channel_removal().
-                */
+               /* hv_process_channel_removal() needs this */
                channel->rescind = true;
 
                vmbus_device_unregister(channel->device_obj);
@@ -459,6 +460,17 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
                    cpumask_of_node(primary->numa_node));
 
        cur_cpu = -1;
+
+       /*
+        * Normally Hyper-V host doesn't create more subchannels than there
+        * are VCPUs on the node but it is possible when not all present VCPUs
+        * on the node are initialized by guest. Clear the alloced_cpus_in_node
+        * to start over.
+        */
+       if (cpumask_equal(&primary->alloced_cpus_in_node,
+                         cpumask_of_node(primary->numa_node)))
+               cpumask_clear(&primary->alloced_cpus_in_node);
+
        while (true) {
                cur_cpu = cpumask_next(cur_cpu, &available_mask);
                if (cur_cpu >= nr_cpu_ids) {
@@ -488,6 +500,40 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
        channel->target_vp = hv_context.vp_index[cur_cpu];
 }
 
+static void vmbus_wait_for_unload(void)
+{
+       int cpu = smp_processor_id();
+       void *page_addr = hv_context.synic_message_page[cpu];
+       struct hv_message *msg = (struct hv_message *)page_addr +
+                                 VMBUS_MESSAGE_SINT;
+       struct vmbus_channel_message_header *hdr;
+       bool unloaded = false;
+
+       while (1) {
+               if (msg->header.message_type == HVMSG_NONE) {
+                       mdelay(10);
+                       continue;
+               }
+
+               hdr = (struct vmbus_channel_message_header *)msg->u.payload;
+               if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE)
+                       unloaded = true;
+
+               msg->header.message_type = HVMSG_NONE;
+               /*
+                * header.message_type needs to be written before we do
+                * wrmsrl() below.
+                */
+               mb();
+
+               if (msg->header.message_flags.msg_pending)
+                       wrmsrl(HV_X64_MSR_EOM, 0);
+
+               if (unloaded)
+                       break;
+       }
+}
+
 /*
  * vmbus_unload_response - Handler for the unload response.
  */
@@ -513,7 +559,14 @@ void vmbus_initiate_unload(void)
        hdr.msgtype = CHANNELMSG_UNLOAD;
        vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header));
 
-       wait_for_completion(&vmbus_connection.unload_event);
+       /*
+        * vmbus_initiate_unload() is also called on crash and the crash can be
+        * happening in an interrupt context, where scheduling is impossible.
+        */
+       if (!in_interrupt())
+               wait_for_completion(&vmbus_connection.unload_event);
+       else
+               vmbus_wait_for_unload();
 }
 
 /*
index 6341be8739ae6e3a4931912a6fcd3139a0314c4c..63194a9a7189e5eb84b12cc699bcb3284c41f137 100644 (file)
@@ -293,8 +293,14 @@ void hv_cleanup(void)
         * Cleanup the TSC page based CS.
         */
        if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
-               clocksource_change_rating(&hyperv_cs_tsc, 10);
-               clocksource_unregister(&hyperv_cs_tsc);
+               /*
+                * Crash can happen in an interrupt context and unregistering
+                * a clocksource is impossible and redundant in this case.
+                */
+               if (!oops_in_progress) {
+                       clocksource_change_rating(&hyperv_cs_tsc, 10);
+                       clocksource_unregister(&hyperv_cs_tsc);
+               }
 
                hypercall_msr.as_uint64 = 0;
                wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
index db4b887b889d268c3e427764e732ce88dc6a008e..c37a71e13de093ada851cf91c9e9851bb964f68a 100644 (file)
@@ -51,7 +51,6 @@ static struct {
        struct hv_fcopy_hdr  *fcopy_msg; /* current message */
        struct vmbus_channel *recv_channel; /* chn we got the request */
        u64 recv_req_id; /* request ID. */
-       void *fcopy_context; /* for the channel callback */
 } fcopy_transaction;
 
 static void fcopy_respond_to_host(int error);
@@ -67,6 +66,13 @@ static struct hvutil_transport *hvt;
  */
 static int dm_reg_value;
 
+static void fcopy_poll_wrapper(void *channel)
+{
+       /* Transaction is finished, reset the state here to avoid races. */
+       fcopy_transaction.state = HVUTIL_READY;
+       hv_fcopy_onchannelcallback(channel);
+}
+
 static void fcopy_timeout_func(struct work_struct *dummy)
 {
        /*
@@ -74,13 +80,7 @@ static void fcopy_timeout_func(struct work_struct *dummy)
         * process the pending transaction.
         */
        fcopy_respond_to_host(HV_E_FAIL);
-
-       /* Transaction is finished, reset the state. */
-       if (fcopy_transaction.state > HVUTIL_READY)
-               fcopy_transaction.state = HVUTIL_READY;
-
-       hv_poll_channel(fcopy_transaction.fcopy_context,
-                       hv_fcopy_onchannelcallback);
+       hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
 }
 
 static int fcopy_handle_handshake(u32 version)
@@ -108,9 +108,7 @@ static int fcopy_handle_handshake(u32 version)
                return -EINVAL;
        }
        pr_debug("FCP: userspace daemon ver. %d registered\n", version);
-       fcopy_transaction.state = HVUTIL_READY;
-       hv_poll_channel(fcopy_transaction.fcopy_context,
-                       hv_fcopy_onchannelcallback);
+       hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
        return 0;
 }
 
@@ -227,15 +225,8 @@ void hv_fcopy_onchannelcallback(void *context)
        int util_fw_version;
        int fcopy_srv_version;
 
-       if (fcopy_transaction.state > HVUTIL_READY) {
-               /*
-                * We will defer processing this callback once
-                * the current transaction is complete.
-                */
-               fcopy_transaction.fcopy_context = context;
+       if (fcopy_transaction.state > HVUTIL_READY)
                return;
-       }
-       fcopy_transaction.fcopy_context = NULL;
 
        vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
                         &requestid);
@@ -275,7 +266,8 @@ void hv_fcopy_onchannelcallback(void *context)
                 * Send the information to the user-level daemon.
                 */
                schedule_work(&fcopy_send_work);
-               schedule_delayed_work(&fcopy_timeout_work, 5*HZ);
+               schedule_delayed_work(&fcopy_timeout_work,
+                                     HV_UTIL_TIMEOUT * HZ);
                return;
        }
        icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
@@ -304,9 +296,8 @@ static int fcopy_on_msg(void *msg, int len)
        if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
                fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
                fcopy_respond_to_host(*val);
-               fcopy_transaction.state = HVUTIL_READY;
-               hv_poll_channel(fcopy_transaction.fcopy_context,
-                               hv_fcopy_onchannelcallback);
+               hv_poll_channel(fcopy_transaction.recv_channel,
+                               fcopy_poll_wrapper);
        }
 
        return 0;
index 74c38a9f34a609369fc84b9e0c5ce4a4c7de5931..2a3420c4ca5988c056ab1a294319a66bf022e132 100644 (file)
@@ -66,7 +66,6 @@ static struct {
        struct hv_kvp_msg  *kvp_msg; /* current message */
        struct vmbus_channel *recv_channel; /* chn we got the request */
        u64 recv_req_id; /* request ID. */
-       void *kvp_context; /* for the channel callback */
 } kvp_transaction;
 
 /*
@@ -94,6 +93,13 @@ static struct hvutil_transport *hvt;
  */
 #define HV_DRV_VERSION           "3.1"
 
+static void kvp_poll_wrapper(void *channel)
+{
+       /* Transaction is finished, reset the state here to avoid races. */
+       kvp_transaction.state = HVUTIL_READY;
+       hv_kvp_onchannelcallback(channel);
+}
+
 static void
 kvp_register(int reg_value)
 {
@@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy)
         */
        kvp_respond_to_host(NULL, HV_E_FAIL);
 
-       /* Transaction is finished, reset the state. */
-       if (kvp_transaction.state > HVUTIL_READY)
-               kvp_transaction.state = HVUTIL_READY;
-
-       hv_poll_channel(kvp_transaction.kvp_context,
-                       hv_kvp_onchannelcallback);
+       hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
 }
 
 static int kvp_handle_handshake(struct hv_kvp_msg *msg)
@@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len)
         */
        if (cancel_delayed_work_sync(&kvp_timeout_work)) {
                kvp_respond_to_host(message, error);
-               kvp_transaction.state = HVUTIL_READY;
-               hv_poll_channel(kvp_transaction.kvp_context,
-                               hv_kvp_onchannelcallback);
+               hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
        }
 
        return 0;
@@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context)
        int util_fw_version;
        int kvp_srv_version;
 
-       if (kvp_transaction.state > HVUTIL_READY) {
-               /*
-                * We will defer processing this callback once
-                * the current transaction is complete.
-                */
-               kvp_transaction.kvp_context = context;
+       if (kvp_transaction.state > HVUTIL_READY)
                return;
-       }
-       kvp_transaction.kvp_context = NULL;
 
        vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
                         &requestid);
@@ -668,7 +660,8 @@ void hv_kvp_onchannelcallback(void *context)
                         * user-mode not responding.
                         */
                        schedule_work(&kvp_sendkey_work);
-                       schedule_delayed_work(&kvp_timeout_work, 5*HZ);
+                       schedule_delayed_work(&kvp_timeout_work,
+                                             HV_UTIL_TIMEOUT * HZ);
 
                        return;
 
index 815405f2e777daba30f0db91216ca04a56b81a6a..81882d4848bdf1f29f1d26e86bd27f49b3ddb206 100644 (file)
@@ -53,7 +53,6 @@ static struct {
        struct vmbus_channel *recv_channel; /* chn we got the request */
        u64 recv_req_id; /* request ID. */
        struct hv_vss_msg  *msg; /* current message */
-       void *vss_context; /* for the channel callback */
 } vss_transaction;
 
 
@@ -74,6 +73,13 @@ static void vss_timeout_func(struct work_struct *dummy);
 static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
 static DECLARE_WORK(vss_send_op_work, vss_send_op);
 
+static void vss_poll_wrapper(void *channel)
+{
+       /* Transaction is finished, reset the state here to avoid races. */
+       vss_transaction.state = HVUTIL_READY;
+       hv_vss_onchannelcallback(channel);
+}
+
 /*
  * Callback when data is received from user mode.
  */
@@ -86,12 +92,7 @@ static void vss_timeout_func(struct work_struct *dummy)
        pr_warn("VSS: timeout waiting for daemon to reply\n");
        vss_respond_to_host(HV_E_FAIL);
 
-       /* Transaction is finished, reset the state. */
-       if (vss_transaction.state > HVUTIL_READY)
-               vss_transaction.state = HVUTIL_READY;
-
-       hv_poll_channel(vss_transaction.vss_context,
-                       hv_vss_onchannelcallback);
+       hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
 }
 
 static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
@@ -138,9 +139,8 @@ static int vss_on_msg(void *msg, int len)
                if (cancel_delayed_work_sync(&vss_timeout_work)) {
                        vss_respond_to_host(vss_msg->error);
                        /* Transaction is finished, reset the state. */
-                       vss_transaction.state = HVUTIL_READY;
-                       hv_poll_channel(vss_transaction.vss_context,
-                                       hv_vss_onchannelcallback);
+                       hv_poll_channel(vss_transaction.recv_channel,
+                                       vss_poll_wrapper);
                }
        } else {
                /* This is a spurious call! */
@@ -238,15 +238,8 @@ void hv_vss_onchannelcallback(void *context)
        struct icmsg_hdr *icmsghdrp;
        struct icmsg_negotiate *negop = NULL;
 
-       if (vss_transaction.state > HVUTIL_READY) {
-               /*
-                * We will defer processing this callback once
-                * the current transaction is complete.
-                */
-               vss_transaction.vss_context = context;
+       if (vss_transaction.state > HVUTIL_READY)
                return;
-       }
-       vss_transaction.vss_context = NULL;
 
        vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
                         &requestid);
@@ -338,6 +331,11 @@ static void vss_on_reset(void)
 int
 hv_vss_init(struct hv_util_service *srv)
 {
+       if (vmbus_proto_version < VERSION_WIN8_1) {
+               pr_warn("Integration service 'Backup (volume snapshot)'"
+                       " not supported on this host version.\n");
+               return -ENOTSUPP;
+       }
        recv_buffer = srv->recv_buffer;
 
        /*
index 6a9d80a5332d31f264c0ff36ac4464264bfcb40d..1505ee6e6605e0b646cdeeae531dedb9fc8dbd11 100644 (file)
@@ -204,9 +204,12 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
                goto out_unlock;
        }
        hvt->outmsg = kzalloc(len, GFP_KERNEL);
-       memcpy(hvt->outmsg, msg, len);
-       hvt->outmsg_len = len;
-       wake_up_interruptible(&hvt->outmsg_q);
+       if (hvt->outmsg) {
+               memcpy(hvt->outmsg, msg, len);
+               hvt->outmsg_len = len;
+               wake_up_interruptible(&hvt->outmsg_q);
+       } else
+               ret = -ENOMEM;
 out_unlock:
        mutex_unlock(&hvt->outmsg_lock);
        return ret;
index 3782636562a1b0c2b7d16273c14db14e8549e768..12156db2e88e20dfa45e2afd4c4bee835f8e3ab9 100644 (file)
 #include <linux/atomic.h>
 #include <linux/hyperv.h>
 
+/*
+ * Timeout for services such as KVP and fcopy.
+ */
+#define HV_UTIL_TIMEOUT 30
+
 /*
  * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent
  * is set by CPUID(HVCPUID_VERSION_FEATURES).
@@ -759,11 +764,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel,
        if (!channel)
                return;
 
-       if (channel->target_cpu != smp_processor_id())
-               smp_call_function_single(channel->target_cpu,
-                                        cb, channel, true);
-       else
-               cb(channel);
+       smp_call_function_single(channel->target_cpu, cb, channel, true);
 }
 
 enum hvutil_device_state {
index f19b6f7a467a6a8c14988da9a3817e2cea02c433..509ed9731630153f8fb48f18c515a56b51e2ca5a 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/ptrace.h>
 #include <linux/screen_info.h>
 #include <linux/kdebug.h>
+#include <linux/random.h>
 #include "hyperv_vmbus.h"
 
 static struct acpi_device  *hv_acpi_dev;
@@ -104,6 +105,7 @@ static struct notifier_block hyperv_panic_block = {
 };
 
 struct resource *hyperv_mmio;
+DEFINE_SEMAPHORE(hyperv_mmio_lock);
 
 static int vmbus_exists(void)
 {
@@ -602,23 +604,11 @@ static int vmbus_remove(struct device *child_device)
 {
        struct hv_driver *drv;
        struct hv_device *dev = device_to_hv_device(child_device);
-       u32 relid = dev->channel->offermsg.child_relid;
 
        if (child_device->driver) {
                drv = drv_to_hv_drv(child_device->driver);
                if (drv->remove)
                        drv->remove(dev);
-               else {
-                       hv_process_channel_removal(dev->channel, relid);
-                       pr_err("remove not set for driver %s\n",
-                               dev_name(child_device));
-               }
-       } else {
-               /*
-                * We don't have a driver for this device; deal with the
-                * rescind message by removing the channel.
-                */
-               hv_process_channel_removal(dev->channel, relid);
        }
 
        return 0;
@@ -653,7 +643,10 @@ static void vmbus_shutdown(struct device *child_device)
 static void vmbus_device_release(struct device *device)
 {
        struct hv_device *hv_dev = device_to_hv_device(device);
+       struct vmbus_channel *channel = hv_dev->channel;
 
+       hv_process_channel_removal(channel,
+                                  channel->offermsg.child_relid);
        kfree(hv_dev);
 
 }
@@ -826,6 +819,8 @@ static void vmbus_isr(void)
                else
                        tasklet_schedule(&msg_dpc);
        }
+
+       add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
 }
 
 
@@ -867,7 +862,7 @@ static int vmbus_bus_init(int irq)
        on_each_cpu(hv_synic_init, NULL, 1);
        ret = vmbus_connect();
        if (ret)
-               goto err_alloc;
+               goto err_connect;
 
        if (vmbus_proto_version > VERSION_WIN7)
                cpu_hotplug_disable();
@@ -885,6 +880,8 @@ static int vmbus_bus_init(int irq)
 
        return 0;
 
+err_connect:
+       on_each_cpu(hv_synic_cleanup, NULL, 1);
 err_alloc:
        hv_synic_free();
        hv_remove_vmbus_irq();
@@ -1144,7 +1141,10 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
        resource_size_t range_min, range_max, start, local_min, local_max;
        const char *dev_n = dev_name(&device_obj->device);
        u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1);
-       int i;
+       int i, retval;
+
+       retval = -ENXIO;
+       down(&hyperv_mmio_lock);
 
        for (iter = hyperv_mmio; iter; iter = iter->sibling) {
                if ((iter->start >= max) || (iter->end <= min))
@@ -1181,13 +1181,17 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
                        for (; start + size - 1 <= local_max; start += align) {
                                *new = request_mem_region_exclusive(start, size,
                                                                    dev_n);
-                               if (*new)
-                                       return 0;
+                               if (*new) {
+                                       retval = 0;
+                                       goto exit;
+                               }
                        }
                }
        }
 
-       return -ENXIO;
+exit:
+       up(&hyperv_mmio_lock);
+       return retval;
 }
 EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
 
index 827c037031287637c602f4f3d6ca9c1790686f16..a7f886961830cf9c5ca7ecfaf9d8839ce1accbaf 100644 (file)
@@ -30,6 +30,7 @@
 
 #define ADT7411_REG_CFG1                       0x18
 #define ADT7411_CFG1_START_MONITOR             (1 << 0)
+#define ADT7411_CFG1_RESERVED_BIT3             (1 << 3)
 
 #define ADT7411_REG_CFG2                       0x19
 #define ADT7411_CFG2_DISABLE_AVG               (1 << 5)
@@ -296,8 +297,10 @@ static int adt7411_probe(struct i2c_client *client,
        mutex_init(&data->device_lock);
        mutex_init(&data->update_lock);
 
+       /* According to the datasheet, we must only write 1 to bit 3 */
        ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
-                                ADT7411_CFG1_START_MONITOR, 1);
+                                ADT7411_CFG1_RESERVED_BIT3
+                                | ADT7411_CFG1_START_MONITOR, 1);
        if (ret < 0)
                return ret;
 
index 17ae2eb26ce21604edf9a1d9df4e24abe01980d6..d5c06f2764f4c89d06607fa74980716c3c1d39a3 100644 (file)
@@ -109,24 +109,24 @@ static int iio_hwmon_probe(struct platform_device *pdev)
 
                switch (type) {
                case IIO_VOLTAGE:
-                       a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-                                                         "in%d_input",
-                                                         in_i++);
+                       a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                              "in%d_input",
+                                                              in_i++);
                        break;
                case IIO_TEMP:
-                       a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-                                                         "temp%d_input",
-                                                         temp_i++);
+                       a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                              "temp%d_input",
+                                                              temp_i++);
                        break;
                case IIO_CURRENT:
-                       a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-                                                         "curr%d_input",
-                                                         curr_i++);
+                       a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                              "curr%d_input",
+                                                              curr_i++);
                        break;
                case IIO_HUMIDITYRELATIVE:
-                       a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
-                                                         "humidity%d_input",
-                                                         humidity_i++);
+                       a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                              "humidity%d_input",
+                                                              humidity_i++);
                        break;
                default:
                        ret = -EINVAL;
index 165d3001c3015466e605b092358820bbe4327e64..c6ec5c62b7a9e8d13261bfcdcac65487fb59344c 100644 (file)
@@ -419,6 +419,38 @@ static struct intel_th_subdevice {
        },
 };
 
+#ifdef CONFIG_MODULES
+static void __intel_th_request_hub_module(struct work_struct *work)
+{
+       struct intel_th *th = container_of(work, struct intel_th,
+                                          request_module_work);
+
+       request_module("intel_th_%s", th->hub->name);
+}
+
+static int intel_th_request_hub_module(struct intel_th *th)
+{
+       INIT_WORK(&th->request_module_work, __intel_th_request_hub_module);
+       schedule_work(&th->request_module_work);
+
+       return 0;
+}
+
+static void intel_th_request_hub_module_flush(struct intel_th *th)
+{
+       flush_work(&th->request_module_work);
+}
+#else
+static inline int intel_th_request_hub_module(struct intel_th *th)
+{
+       return -EINVAL;
+}
+
+static inline void intel_th_request_hub_module_flush(struct intel_th *th)
+{
+}
+#endif /* CONFIG_MODULES */
+
 static int intel_th_populate(struct intel_th *th, struct resource *devres,
                             unsigned int ndevres, int irq)
 {
@@ -488,7 +520,7 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres,
                /* need switch driver to be loaded to enumerate the rest */
                if (subdev->type == INTEL_TH_SWITCH && !req) {
                        th->hub = thdev;
-                       err = request_module("intel_th_%s", subdev->name);
+                       err = intel_th_request_hub_module(th);
                        if (!err)
                                req++;
                }
@@ -603,6 +635,7 @@ void intel_th_free(struct intel_th *th)
 {
        int i;
 
+       intel_th_request_hub_module_flush(th);
        for (i = 0; i < TH_SUBDEVICE_MAX; i++)
                if (th->thdev[i] != th->hub)
                        intel_th_device_remove(th->thdev[i]);
index 57fd72b20fae3135aa599475ce91e113abc4147d..d03a6cd1c65d5205334f7e21e4a89a3a1e19b9ce 100644 (file)
@@ -197,6 +197,9 @@ struct intel_th {
 
        int                     id;
        int                     major;
+#ifdef CONFIG_MODULES
+       struct work_struct      request_module_work;
+#endif /* CONFIG_MODULES */
 #ifdef CONFIG_INTEL_TH_DEBUG
        struct dentry           *dbg;
 #endif
index 641e87936064b72c4a2fca2f93eadd83c9d6cdd6..d57a2f75dccf26f62b964514f3b3e7bc75c61c0b 100644 (file)
@@ -67,6 +67,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa126),
                .driver_data = (kernel_ulong_t)0,
        },
+       {
+               /* Kaby Lake PCH-H */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
+               .driver_data = (kernel_ulong_t)0,
+       },
        { 0 },
 };
 
index a0d95ff682ae120186a689dd0dcdd74f3d65b0f3..2d5ff86398d0911cd0c3a261fb689cf2c9e04609 100644 (file)
@@ -215,7 +215,7 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
        msg->outsize = request_len;
        msg->insize = response_len;
 
-       result = cros_ec_cmd_xfer(bus->ec, msg);
+       result = cros_ec_cmd_xfer_status(bus->ec, msg);
        if (result < 0) {
                dev_err(dev, "Error transferring EC i2c message %d\n", result);
                goto exit;
index 8eff627388777d42b5bbe30199bba9c657387fd8..e253598d764c0d1429e18982a3f8f4a2d32b77a4 100644 (file)
@@ -433,7 +433,7 @@ static int efm32_i2c_probe(struct platform_device *pdev)
        ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
-               return ret;
+               goto err_disable_clk;
        }
 
        ret = i2c_add_adapter(&ddata->adapter);
index 76e699f9ed9732cb910fd6092837d1ddf13c37c5..eef3aa6007f1051faa4c7dd5a6abf63880ef4a3e 100644 (file)
@@ -773,13 +773,6 @@ static int pch_i2c_probe(struct pci_dev *pdev,
        /* Set the number of I2C channel instance */
        adap_info->ch_num = id->driver_data;
 
-       ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
-                 KBUILD_MODNAME, adap_info);
-       if (ret) {
-               pch_pci_err(pdev, "request_irq FAILED\n");
-               goto err_request_irq;
-       }
-
        for (i = 0; i < adap_info->ch_num; i++) {
                pch_adap = &adap_info->pch_data[i].pch_adapter;
                adap_info->pch_i2c_suspended = false;
@@ -796,6 +789,17 @@ static int pch_i2c_probe(struct pci_dev *pdev,
                adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
 
                pch_adap->dev.parent = &pdev->dev;
+       }
+
+       ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+                 KBUILD_MODNAME, adap_info);
+       if (ret) {
+               pch_pci_err(pdev, "request_irq FAILED\n");
+               goto err_request_irq;
+       }
+
+       for (i = 0; i < adap_info->ch_num; i++) {
+               pch_adap = &adap_info->pch_data[i].pch_adapter;
 
                pch_i2c_init(&adap_info->pch_data[i]);
 
index 27fa0cb09538cebfd0f9388112cfe30abb773edd..85f39cc3e2765f71a4e7700aebec130f3d69befd 100644 (file)
@@ -244,6 +244,13 @@ struct i801_priv {
        struct platform_device *mux_pdev;
 #endif
        struct platform_device *tco_pdev;
+
+       /*
+        * If set to true the host controller registers are reserved for
+        * ACPI AML use. Protected by acpi_lock.
+        */
+       bool acpi_reserved;
+       struct mutex acpi_lock;
 };
 
 #define FEATURE_SMBUS_PEC      (1 << 0)
@@ -714,9 +721,15 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
 {
        int hwpec;
        int block = 0;
-       int ret, xact = 0;
+       int ret = 0, xact = 0;
        struct i801_priv *priv = i2c_get_adapdata(adap);
 
+       mutex_lock(&priv->acpi_lock);
+       if (priv->acpi_reserved) {
+               mutex_unlock(&priv->acpi_lock);
+               return -EBUSY;
+       }
+
        hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
                && size != I2C_SMBUS_QUICK
                && size != I2C_SMBUS_I2C_BLOCK_DATA;
@@ -773,7 +786,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
        default:
                dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
                        size);
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               goto out;
        }
 
        if (hwpec)      /* enable/disable hardware PEC */
@@ -796,11 +810,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
                       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
 
        if (block)
-               return ret;
+               goto out;
        if (ret)
-               return ret;
+               goto out;
        if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
-               return 0;
+               goto out;
 
        switch (xact & 0x7f) {
        case I801_BYTE: /* Result put in SMBHSTDAT0 */
@@ -812,7 +826,10 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
                             (inb_p(SMBHSTDAT1(priv)) << 8);
                break;
        }
-       return 0;
+
+out:
+       mutex_unlock(&priv->acpi_lock);
+       return ret;
 }
 
 
@@ -1249,6 +1266,72 @@ static void i801_add_tco(struct i801_priv *priv)
        priv->tco_pdev = pdev;
 }
 
+#ifdef CONFIG_ACPI
+static acpi_status
+i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
+                    u64 *value, void *handler_context, void *region_context)
+{
+       struct i801_priv *priv = handler_context;
+       struct pci_dev *pdev = priv->pci_dev;
+       acpi_status status;
+
+       /*
+        * Once BIOS AML code touches the OpRegion we warn and inhibit any
+        * further access from the driver itself. This device is now owned
+        * by the system firmware.
+        */
+       mutex_lock(&priv->acpi_lock);
+
+       if (!priv->acpi_reserved) {
+               priv->acpi_reserved = true;
+
+               dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
+               dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
+       }
+
+       if ((function & ACPI_IO_MASK) == ACPI_READ)
+               status = acpi_os_read_port(address, (u32 *)value, bits);
+       else
+               status = acpi_os_write_port(address, (u32)*value, bits);
+
+       mutex_unlock(&priv->acpi_lock);
+
+       return status;
+}
+
+static int i801_acpi_probe(struct i801_priv *priv)
+{
+       struct acpi_device *adev;
+       acpi_status status;
+
+       adev = ACPI_COMPANION(&priv->pci_dev->dev);
+       if (adev) {
+               status = acpi_install_address_space_handler(adev->handle,
+                               ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler,
+                               NULL, priv);
+               if (ACPI_SUCCESS(status))
+                       return 0;
+       }
+
+       return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]);
+}
+
+static void i801_acpi_remove(struct i801_priv *priv)
+{
+       struct acpi_device *adev;
+
+       adev = ACPI_COMPANION(&priv->pci_dev->dev);
+       if (!adev)
+               return;
+
+       acpi_remove_address_space_handler(adev->handle,
+               ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
+}
+#else
+static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
+static inline void i801_acpi_remove(struct i801_priv *priv) { }
+#endif
+
 static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        unsigned char temp;
@@ -1266,6 +1349,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
        priv->adapter.dev.parent = &dev->dev;
        ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
        priv->adapter.retries = 3;
+       mutex_init(&priv->acpi_lock);
 
        priv->pci_dev = dev;
        switch (dev->device) {
@@ -1328,10 +1412,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
                return -ENODEV;
        }
 
-       err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
-       if (err) {
+       if (i801_acpi_probe(priv))
                return -ENODEV;
-       }
 
        err = pcim_iomap_regions(dev, 1 << SMBBAR,
                                 dev_driver_string(&dev->dev));
@@ -1340,6 +1422,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
                        "Failed to request SMBus region 0x%lx-0x%Lx\n",
                        priv->smba,
                        (unsigned long long)pci_resource_end(dev, SMBBAR));
+               i801_acpi_remove(priv);
                return err;
        }
 
@@ -1404,6 +1487,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
        err = i2c_add_adapter(&priv->adapter);
        if (err) {
                dev_err(&dev->dev, "Failed to add SMBus adapter\n");
+               i801_acpi_remove(priv);
                return err;
        }
 
@@ -1422,6 +1506,7 @@ static void i801_remove(struct pci_dev *dev)
 
        i801_del_mux(priv);
        i2c_del_adapter(&priv->adapter);
+       i801_acpi_remove(priv);
        pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 
        platform_device_unregister(priv->tco_pdev);
index fdcbdab808e9fcbea9eb301ab7a2fb261abb3226..33b11563cde79b04f6068b426f6aac83883d3333 100644 (file)
@@ -727,7 +727,8 @@ static int qup_i2c_pm_resume_runtime(struct device *device)
 #ifdef CONFIG_PM_SLEEP
 static int qup_i2c_suspend(struct device *device)
 {
-       qup_i2c_pm_suspend_runtime(device);
+       if (!pm_runtime_suspended(device))
+               return qup_i2c_pm_suspend_runtime(device);
        return 0;
 }
 
index 5fbd5bd0878f1f460a58556ba74f3b4354319389..49fc2c7e560a68bbd6f65387b781e1d5fd524f21 100644 (file)
@@ -150,7 +150,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
                mux->data.idle_in_use = true;
 
        /* map address from "reg" if exists */
-       if (of_address_to_resource(np, 0, &res)) {
+       if (of_address_to_resource(np, 0, &res) == 0) {
                mux->data.reg_size = resource_size(&res);
                mux->data.reg = devm_ioremap_resource(&pdev->dev, &res);
                if (IS_ERR(mux->data.reg))
index 146eed70bdf46e0caf005531d18bb5c46db175aa..ba947df5a8c7d09af2c36a23d5b6a1d5f4df8bb3 100644 (file)
@@ -716,6 +716,26 @@ static struct cpuidle_state avn_cstates[] = {
        {
                .enter = NULL }
 };
+static struct cpuidle_state knl_cstates[] = {
+       {
+               .name = "C1-KNL",
+               .desc = "MWAIT 0x00",
+               .flags = MWAIT2flg(0x00),
+               .exit_latency = 1,
+               .target_residency = 2,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze },
+       {
+               .name = "C6-KNL",
+               .desc = "MWAIT 0x10",
+               .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 120,
+               .target_residency = 500,
+               .enter = &intel_idle,
+               .enter_freeze = intel_idle_freeze },
+       {
+               .enter = NULL }
+};
 
 /**
  * intel_idle
@@ -890,6 +910,10 @@ static const struct idle_cpu idle_cpu_avn = {
        .disable_promotion_to_c1e = true,
 };
 
+static const struct idle_cpu idle_cpu_knl = {
+       .state_table = knl_cstates,
+};
+
 #define ICPU(model, cpu) \
        { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
 
@@ -921,6 +945,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {
        ICPU(0x56, idle_cpu_bdw),
        ICPU(0x4e, idle_cpu_skl),
        ICPU(0x5e, idle_cpu_skl),
+       ICPU(0x57, idle_cpu_knl),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
index 291c61a41c9a8cae12198c207a2f12afd5d5532c..fa24d519661596de415e01490b36a36eff63fc28 100644 (file)
@@ -68,6 +68,9 @@
 #define BMC150_ACCEL_REG_PMU_BW                0x10
 #define BMC150_ACCEL_DEF_BW                    125
 
+#define BMC150_ACCEL_REG_RESET                 0x14
+#define BMC150_ACCEL_RESET_VAL                 0xB6
+
 #define BMC150_ACCEL_REG_INT_MAP_0             0x19
 #define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE       BIT(2)
 
@@ -1487,6 +1490,14 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
        int ret, i;
        unsigned int val;
 
+       /*
+        * Reset chip to get it in a known good state. A delay of 1.8ms after
+        * reset is required according to the data sheets of supported chips.
+        */
+       regmap_write(data->regmap, BMC150_ACCEL_REG_RESET,
+                    BMC150_ACCEL_RESET_VAL);
+       usleep_range(1800, 2500);
+
        ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
        if (ret < 0) {
                dev_err(data->dev,
index 3a9f106787d28b2f85248402b68628fd02604460..9d72d4bcf5e9b316034219bb1b880fc55a72c076 100644 (file)
@@ -160,11 +160,13 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
                if (ret < 0)
                        goto error_ret;
                *val = ret;
+               ret = IIO_VAL_INT;
                break;
        case IIO_CHAN_INFO_SCALE:
                ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
                if (ret < 0)
                        goto error_ret;
+               *val = 0;
                *val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
                ret = IIO_VAL_INT_PLUS_MICRO;
                break;
index 1e7aded53117c28e6900f32eee33f9a728515f3d..bda6bbe4479cbec62aff1dd4202bdff80b5ec072 100644 (file)
@@ -306,6 +306,7 @@ config QCOM_SPMI_VADC
 config ROCKCHIP_SARADC
        tristate "Rockchip SARADC driver"
        depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
+       depends on RESET_CONTROLLER
        help
          Say yes here to build support for the SARADC found in SoCs from
          Rockchip.
index 01d71588d752ae0aa73da6abf4019f35d041939a..ba82de25a79727dfd8832424a9283b6410645ec6 100644 (file)
@@ -533,6 +533,7 @@ static struct attribute_group ad799x_event_attrs_group = {
 static const struct iio_info ad7991_info = {
        .read_raw = &ad799x_read_raw,
        .driver_module = THIS_MODULE,
+       .update_scan_mode = ad799x_update_scan_mode,
 };
 
 static const struct iio_info ad7993_4_7_8_noirq_info = {
index 7b40925dd4ff297e56fa0a3541980e9964d14092..93986f0590efa64f7e3b58fc468e96de4ac48cdb 100644 (file)
@@ -381,8 +381,8 @@ static irqreturn_t at91_adc_rl_interrupt(int irq, void *private)
                st->ts_bufferedmeasure = false;
                input_report_key(st->ts_input, BTN_TOUCH, 0);
                input_sync(st->ts_input);
-       } else if (status & AT91_ADC_EOC(3)) {
-               /* Conversion finished */
+       } else if (status & AT91_ADC_EOC(3) && st->ts_input) {
+               /* Conversion finished and we've a touchscreen */
                if (st->ts_bufferedmeasure) {
                        /*
                         * Last measurement is always discarded, since it can
index f9ad6c2d68219234e250dcbdeb6d5909fb06bbe1..85d701291654074e1fa07978331eb01d89abd04a 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/of_device.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
 #include <linux/regulator/consumer.h>
 #include <linux/iio/iio.h>
 
@@ -53,6 +55,7 @@ struct rockchip_saradc {
        struct clk              *clk;
        struct completion       completion;
        struct regulator        *vref;
+       struct reset_control    *reset;
        const struct rockchip_saradc_data *data;
        u16                     last_val;
 };
@@ -190,6 +193,16 @@ static const struct of_device_id rockchip_saradc_match[] = {
 };
 MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
 
+/**
+ * Reset SARADC Controller.
+ */
+static void rockchip_saradc_reset_controller(struct reset_control *reset)
+{
+       reset_control_assert(reset);
+       usleep_range(10, 20);
+       reset_control_deassert(reset);
+}
+
 static int rockchip_saradc_probe(struct platform_device *pdev)
 {
        struct rockchip_saradc *info = NULL;
@@ -218,6 +231,20 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        if (IS_ERR(info->regs))
                return PTR_ERR(info->regs);
 
+       /*
+        * The reset should be an optional property, as it should work
+        * with old devicetrees as well
+        */
+       info->reset = devm_reset_control_get(&pdev->dev, "saradc-apb");
+       if (IS_ERR(info->reset)) {
+               ret = PTR_ERR(info->reset);
+               if (ret != -ENOENT)
+                       return ret;
+
+               dev_dbg(&pdev->dev, "no reset control found\n");
+               info->reset = NULL;
+       }
+
        init_completion(&info->completion);
 
        irq = platform_get_irq(pdev, 0);
@@ -252,6 +279,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
                return PTR_ERR(info->vref);
        }
 
+       if (info->reset)
+               rockchip_saradc_reset_controller(info->reset);
+
        /*
         * Use a default value for the converter clock.
         * This may become user-configurable in the future.
index c1e05532d437f263a9aa3d7f7c96147b13bfe682..0470fc843d4efebba6ca4a6f269691ea34b9914f 100644 (file)
@@ -32,6 +32,7 @@
 
 struct tiadc_device {
        struct ti_tscadc_dev *mfd_tscadc;
+       struct mutex fifo1_lock; /* to protect fifo access */
        int channels;
        u8 channel_line[8];
        u8 channel_step[8];
@@ -360,6 +361,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
                int *val, int *val2, long mask)
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
+       int ret = IIO_VAL_INT;
        int i, map_val;
        unsigned int fifo1count, read, stepid;
        bool found = false;
@@ -373,13 +375,14 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
        if (!step_en)
                return -EINVAL;
 
+       mutex_lock(&adc_dev->fifo1_lock);
        fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
        while (fifo1count--)
                tiadc_readl(adc_dev, REG_FIFO1);
 
        am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en);
 
-       timeout = jiffies + usecs_to_jiffies
+       timeout = jiffies + msecs_to_jiffies
                                (IDLE_TIMEOUT * adc_dev->channels);
        /* Wait for Fifo threshold interrupt */
        while (1) {
@@ -389,7 +392,8 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
 
                if (time_after(jiffies, timeout)) {
                        am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       goto err_unlock;
                }
        }
        map_val = adc_dev->channel_step[chan->scan_index];
@@ -415,8 +419,11 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
        am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
 
        if (found == false)
-               return -EBUSY;
-       return IIO_VAL_INT;
+               ret =  -EBUSY;
+
+err_unlock:
+       mutex_unlock(&adc_dev->fifo1_lock);
+       return ret;
 }
 
 static const struct iio_info tiadc_info = {
@@ -485,6 +492,7 @@ static int tiadc_probe(struct platform_device *pdev)
 
        tiadc_step_config(indio_dev);
        tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD);
+       mutex_init(&adc_dev->fifo1_lock);
 
        err = tiadc_channel_init(indio_dev, adc_dev->channels);
        if (err < 0)
index e81f434760f4c778c604c7d2e102bfa79adef9b2..dc33c1dd5191a57aaa8c3c66cdaa75a31866463c 100644 (file)
@@ -56,8 +56,8 @@ static struct {
        {HID_USAGE_SENSOR_ALS, 0, 1, 0},
        {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0},
 
-       {HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0},
-       {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0},
+       {HID_USAGE_SENSOR_PRESSURE, 0, 100, 0},
+       {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000},
 };
 
 static int pow_10(unsigned power)
index 0f6f63b2026379ffd968a764e3309f8fb792eda5..32bb036069eb032313fa95895c83b3396cd752f3 100644 (file)
@@ -107,9 +107,10 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
 {
        struct iio_dev *indio_dev = filp->private_data;
        struct iio_buffer *rb = indio_dev->buffer;
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
        size_t datum_size;
        size_t to_wait;
-       int ret;
+       int ret = 0;
 
        if (!indio_dev->info)
                return -ENODEV;
@@ -131,19 +132,29 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
        else
                to_wait = min_t(size_t, n / datum_size, rb->watermark);
 
+       add_wait_queue(&rb->pollq, &wait);
        do {
-               ret = wait_event_interruptible(rb->pollq,
-                     iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size));
-               if (ret)
-                       return ret;
+               if (!indio_dev->info) {
+                       ret = -ENODEV;
+                       break;
+               }
 
-               if (!indio_dev->info)
-                       return -ENODEV;
+               if (!iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size)) {
+                       if (signal_pending(current)) {
+                               ret = -ERESTARTSYS;
+                               break;
+                       }
+
+                       wait_woken(&wait, TASK_INTERRUPTIBLE,
+                                  MAX_SCHEDULE_TIMEOUT);
+                       continue;
+               }
 
                ret = rb->access->read_first_n(rb, n, buf);
                if (ret == 0 && (filp->f_flags & O_NONBLOCK))
                        ret = -EAGAIN;
-        } while (ret == 0);
+       } while (ret == 0);
+       remove_wait_queue(&rb->pollq, &wait);
 
        return ret;
 }
index 159ede61f79318d4ee8e581a8a61df2028680aba..131b434af994ddf5a09c3e828b33baba58ef66cd 100644 (file)
@@ -433,23 +433,21 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
                scale_db = true;
        case IIO_VAL_INT_PLUS_MICRO:
                if (vals[1] < 0)
-                       return sprintf(buf, "-%ld.%06u%s\n", abs(vals[0]),
-                                       -vals[1],
-                               scale_db ? " dB" : "");
+                       return sprintf(buf, "-%d.%06u%s\n", abs(vals[0]),
+                                      -vals[1], scale_db ? " dB" : "");
                else
                        return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1],
                                scale_db ? " dB" : "");
        case IIO_VAL_INT_PLUS_NANO:
                if (vals[1] < 0)
-                       return sprintf(buf, "-%ld.%09u\n", abs(vals[0]),
-                                       -vals[1]);
+                       return sprintf(buf, "-%d.%09u\n", abs(vals[0]),
+                                      -vals[1]);
                else
                        return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
        case IIO_VAL_FRACTIONAL:
                tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
-               vals[1] = do_div(tmp, 1000000000LL);
-               vals[0] = tmp;
-               return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
+               vals[0] = (int)div_s64_rem(tmp, 1000000000, &vals[1]);
+               return sprintf(buf, "%d.%09u\n", vals[0], abs(vals[1]));
        case IIO_VAL_FRACTIONAL_LOG2:
                tmp = (s64)vals[0] * 1000000000LL >> vals[1];
                vals[1] = do_div(tmp, 1000000000LL);
index e2f926cdcad2acdbdd8aec50f0f479f52d2a6584..a0aedda7dfd769202c3782e2b6c1a854b3abba13 100644 (file)
@@ -392,7 +392,7 @@ static int as3935_probe(struct spi_device *spi)
                return ret;
        }
 
-       ret = iio_triggered_buffer_setup(indio_dev, NULL,
+       ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
                &as3935_trigger_handler, NULL);
 
        if (ret) {
index 5fb089e913530c54a9852d4ae6fabcda24a00451..fb43a242847b254b6656887e78101f5c0a31b2c2 100644 (file)
@@ -634,6 +634,7 @@ static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
        if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
                           RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
                pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
+               dev_kfree_skb(skb);
                return -ENOMEM;
        }
        nlh->nlmsg_type = NLMSG_DONE;
index bb6685fb08c61483546505f99037b88af6202ad0..6aa648cb538139409e658d487102e3510f8489d5 100644 (file)
@@ -106,7 +106,6 @@ struct mcast_group {
        atomic_t                refcount;
        enum mcast_group_state  state;
        struct ib_sa_query      *query;
-       int                     query_id;
        u16                     pkey_index;
        u8                      leave_state;
        int                     retries;
@@ -339,11 +338,7 @@ static int send_join(struct mcast_group *group, struct mcast_member *member)
                                       member->multicast.comp_mask,
                                       3000, GFP_KERNEL, join_handler, group,
                                       &group->query);
-       if (ret >= 0) {
-               group->query_id = ret;
-               ret = 0;
-       }
-       return ret;
+       return (ret > 0) ? 0 : ret;
 }
 
 static int send_leave(struct mcast_group *group, u8 leave_state)
@@ -363,11 +358,7 @@ static int send_leave(struct mcast_group *group, u8 leave_state)
                                       IB_SA_MCMEMBER_REC_JOIN_STATE,
                                       3000, GFP_KERNEL, leave_handler,
                                       group, &group->query);
-       if (ret >= 0) {
-               group->query_id = ret;
-               ret = 0;
-       }
-       return ret;
+       return (ret > 0) ? 0 : ret;
 }
 
 static void join_group(struct mcast_group *group, struct mcast_member *member,
index a95a32ba596edc03728cf7790a6752c951cde951..d3b7ecd106f7df45aa352298eb274a04a3e35f55 100644 (file)
@@ -534,7 +534,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
        data = ibnl_put_msg(skb, &nlh, query->seq, 0, RDMA_NL_LS,
                            RDMA_NL_LS_OP_RESOLVE, NLM_F_REQUEST);
        if (!data) {
-               kfree_skb(skb);
+               nlmsg_free(skb);
                return -EMSGSIZE;
        }
 
index 94bbd8c155fcca1daf5f2e9ee0fc65552821ff3f..a2d19d136099d22f655d50eb5ed4b7dadf7e1c14 100644 (file)
@@ -116,6 +116,7 @@ struct ib_uverbs_event_file {
 struct ib_uverbs_file {
        struct kref                             ref;
        struct mutex                            mutex;
+       struct mutex                            cleanup_mutex; /* protect cleanup */
        struct ib_uverbs_device                *device;
        struct ib_ucontext                     *ucontext;
        struct ib_event_handler                 event_handler;
index 24f3ca2c4ad761bf639eb2933c30387c25377c21..d625c82d6c82db0e7af16bf312df1bd8dd123c62 100644 (file)
@@ -922,6 +922,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
        file->async_file = NULL;
        kref_init(&file->ref);
        mutex_init(&file->mutex);
+       mutex_init(&file->cleanup_mutex);
 
        filp->private_data = file;
        kobject_get(&dev->kobj);
@@ -947,18 +948,20 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
 {
        struct ib_uverbs_file *file = filp->private_data;
        struct ib_uverbs_device *dev = file->device;
-       struct ib_ucontext *ucontext = NULL;
+
+       mutex_lock(&file->cleanup_mutex);
+       if (file->ucontext) {
+               ib_uverbs_cleanup_ucontext(file, file->ucontext);
+               file->ucontext = NULL;
+       }
+       mutex_unlock(&file->cleanup_mutex);
 
        mutex_lock(&file->device->lists_mutex);
-       ucontext = file->ucontext;
-       file->ucontext = NULL;
        if (!file->is_closed) {
                list_del(&file->list);
                file->is_closed = 1;
        }
        mutex_unlock(&file->device->lists_mutex);
-       if (ucontext)
-               ib_uverbs_cleanup_ucontext(file, ucontext);
 
        if (file->async_file)
                kref_put(&file->async_file->ref, ib_uverbs_release_event_file);
@@ -1172,22 +1175,30 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev,
        mutex_lock(&uverbs_dev->lists_mutex);
        while (!list_empty(&uverbs_dev->uverbs_file_list)) {
                struct ib_ucontext *ucontext;
-
                file = list_first_entry(&uverbs_dev->uverbs_file_list,
                                        struct ib_uverbs_file, list);
                file->is_closed = 1;
-               ucontext = file->ucontext;
                list_del(&file->list);
-               file->ucontext = NULL;
                kref_get(&file->ref);
                mutex_unlock(&uverbs_dev->lists_mutex);
-               /* We must release the mutex before going ahead and calling
-                * disassociate_ucontext. disassociate_ucontext might end up
-                * indirectly calling uverbs_close, for example due to freeing
-                * the resources (e.g mmput).
-                */
+
                ib_uverbs_event_handler(&file->event_handler, &event);
+
+               mutex_lock(&file->cleanup_mutex);
+               ucontext = file->ucontext;
+               file->ucontext = NULL;
+               mutex_unlock(&file->cleanup_mutex);
+
+               /* At this point ib_uverbs_close cannot be running
+                * ib_uverbs_cleanup_ucontext
+                */
                if (ucontext) {
+                       /* We must release the mutex before going ahead and
+                        * calling disassociate_ucontext. disassociate_ucontext
+                        * might end up indirectly calling uverbs_close,
+                        * for example due to freeing the resources
+                        * (e.g mmput).
+                        */
                        ib_dev->disassociate_ucontext(ucontext);
                        ib_uverbs_cleanup_ucontext(file, ucontext);
                }
index 870e56b6b25f5c7837f5a4a358597d748aaf1ef5..d862b9b7910e489dc5a4a4f4b00d9b44eec4f764 100644 (file)
@@ -526,7 +526,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
                tun_tx_ix = (++tun_qp->tx_ix_head) & (MLX4_NUM_TUNNEL_BUFS - 1);
        spin_unlock(&tun_qp->tx_lock);
        if (ret)
-               goto out;
+               goto end;
 
        tun_mad = (struct mlx4_rcv_tunnel_mad *) (tun_qp->tx_ring[tun_tx_ix].buf.addr);
        if (tun_qp->tx_ring[tun_tx_ix].ah)
@@ -595,9 +595,15 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
        wr.wr.send_flags = IB_SEND_SIGNALED;
 
        ret = ib_post_send(src_qp, &wr.wr, &bad_wr);
-out:
-       if (ret)
-               ib_destroy_ah(ah);
+       if (!ret)
+               return 0;
+ out:
+       spin_lock(&tun_qp->tx_lock);
+       tun_qp->tx_ix_tail++;
+       spin_unlock(&tun_qp->tx_lock);
+       tun_qp->tx_ring[tun_tx_ix].ah = NULL;
+end:
+       ib_destroy_ah(ah);
        return ret;
 }
 
@@ -1074,6 +1080,27 @@ void handle_port_mgmt_change_event(struct work_struct *work)
 
                /* Generate GUID changed event */
                if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) {
+                       if (mlx4_is_master(dev->dev)) {
+                               union ib_gid gid;
+                               int err = 0;
+
+                               if (!eqe->event.port_mgmt_change.params.port_info.gid_prefix)
+                                       err = __mlx4_ib_query_gid(&dev->ib_dev, port, 0, &gid, 1);
+                               else
+                                       gid.global.subnet_prefix =
+                                               eqe->event.port_mgmt_change.params.port_info.gid_prefix;
+                               if (err) {
+                                       pr_warn("Could not change QP1 subnet prefix for port %d: query_gid error (%d)\n",
+                                               port, err);
+                               } else {
+                                       pr_debug("Changing QP1 subnet prefix for port %d. old=0x%llx. new=0x%llx\n",
+                                                port,
+                                                (u64)atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix),
+                                                be64_to_cpu(gid.global.subnet_prefix));
+                                       atomic64_set(&dev->sriov.demux[port - 1].subnet_prefix,
+                                                    be64_to_cpu(gid.global.subnet_prefix));
+                               }
+                       }
                        mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE);
                        /*if master, notify all slaves*/
                        if (mlx4_is_master(dev->dev))
@@ -1278,9 +1305,15 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
 
 
        ret = ib_post_send(send_qp, &wr.wr, &bad_wr);
+       if (!ret)
+               return 0;
+
+       spin_lock(&sqp->tx_lock);
+       sqp->tx_ix_tail++;
+       spin_unlock(&sqp->tx_lock);
+       sqp->tx_ring[wire_tx_ix].ah = NULL;
 out:
-       if (ret)
-               ib_destroy_ah(ah);
+       ib_destroy_ah(ah);
        return ret;
 }
 
@@ -2142,6 +2175,8 @@ int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev)
                if (err)
                        goto demux_err;
                dev->sriov.demux[i].guid_cache[0] = gid.global.interface_id;
+               atomic64_set(&dev->sriov.demux[i].subnet_prefix,
+                            be64_to_cpu(gid.global.subnet_prefix));
                err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1,
                                      &dev->sriov.sqps[i]);
                if (err)
index 99451d887266d2bffee04e2a71347f69b4883305..36ec8aa048aacafdd17f89e1cb66a360d344ad0b 100644 (file)
@@ -489,7 +489,7 @@ static u8 get_leave_state(struct mcast_group *group)
                if (!group->members[i])
                        leave_state |= (1 << i);
 
-       return leave_state & (group->rec.scope_join_state & 7);
+       return leave_state & (group->rec.scope_join_state & 0xf);
 }
 
 static int join_group(struct mcast_group *group, int slave, u8 join_mask)
@@ -564,8 +564,8 @@ static void mlx4_ib_mcg_timeout_handler(struct work_struct *work)
                } else
                        mcg_warn_group(group, "DRIVER BUG\n");
        } else if (group->state == MCAST_LEAVE_SENT) {
-               if (group->rec.scope_join_state & 7)
-                       group->rec.scope_join_state &= 0xf8;
+               if (group->rec.scope_join_state & 0xf)
+                       group->rec.scope_join_state &= 0xf0;
                group->state = MCAST_IDLE;
                mutex_unlock(&group->lock);
                if (release_group(group, 1))
@@ -605,7 +605,7 @@ static int handle_leave_req(struct mcast_group *group, u8 leave_mask,
 static int handle_join_req(struct mcast_group *group, u8 join_mask,
                           struct mcast_req *req)
 {
-       u8 group_join_state = group->rec.scope_join_state & 7;
+       u8 group_join_state = group->rec.scope_join_state & 0xf;
        int ref = 0;
        u16 status;
        struct ib_sa_mcmember_data *sa_data = (struct ib_sa_mcmember_data *)req->sa_mad.data;
@@ -690,8 +690,8 @@ static void mlx4_ib_mcg_work_handler(struct work_struct *work)
                        u8 cur_join_state;
 
                        resp_join_state = ((struct ib_sa_mcmember_data *)
-                                               group->response_sa_mad.data)->scope_join_state & 7;
-                       cur_join_state = group->rec.scope_join_state & 7;
+                                               group->response_sa_mad.data)->scope_join_state & 0xf;
+                       cur_join_state = group->rec.scope_join_state & 0xf;
 
                        if (method == IB_MGMT_METHOD_GET_RESP) {
                                /* successfull join */
@@ -710,7 +710,7 @@ process_requests:
                req = list_first_entry(&group->pending_list, struct mcast_req,
                                       group_list);
                sa_data = (struct ib_sa_mcmember_data *)req->sa_mad.data;
-               req_join_state = sa_data->scope_join_state & 0x7;
+               req_join_state = sa_data->scope_join_state & 0xf;
 
                /* For a leave request, we will immediately answer the VF, and
                 * update our internal counters. The actual leave will be sent
index 1caa11edac03347a246467436daa72dd18d5c505..78f29e91653a39e9871a783ac71037a4c7989dcf 100644 (file)
@@ -441,7 +441,7 @@ struct mlx4_ib_demux_ctx {
        struct workqueue_struct *wq;
        struct workqueue_struct *ud_wq;
        spinlock_t ud_lock;
-       __be64 subnet_prefix;
+       atomic64_t subnet_prefix;
        __be64 guid_cache[128];
        struct mlx4_ib_dev *dev;
        /* the following lock protects both mcg_table and mcg_mgid0_list */
index 13eaaf45288f80d4bb6658d5a18985a978e8c98d..f350f2d61c15b8efe9303a681d1f90d70b44ccf4 100644 (file)
@@ -357,7 +357,7 @@ static int send_wqe_overhead(enum mlx4_ib_qp_type type, u32 flags)
                        sizeof (struct mlx4_wqe_raddr_seg);
        case MLX4_IB_QPT_RC:
                return sizeof (struct mlx4_wqe_ctrl_seg) +
-                       sizeof (struct mlx4_wqe_atomic_seg) +
+                       sizeof (struct mlx4_wqe_masked_atomic_seg) +
                        sizeof (struct mlx4_wqe_raddr_seg);
        case MLX4_IB_QPT_SMI:
        case MLX4_IB_QPT_GSI:
@@ -1162,8 +1162,10 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
        {
                err = create_qp_common(to_mdev(pd->device), pd, init_attr,
                                       udata, 0, &qp, gfp);
-               if (err)
+               if (err) {
+                       kfree(qp);
                        return ERR_PTR(err);
+               }
 
                qp->ibqp.qp_num = qp->mqp.qpn;
                qp->xrcdn = xrcdn;
@@ -2329,24 +2331,27 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_ud_wr *wr,
                sqp->ud_header.grh.flow_label    =
                        ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
                sqp->ud_header.grh.hop_limit     = ah->av.ib.hop_limit;
-               if (is_eth)
+               if (is_eth) {
                        memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16);
-               else {
-               if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
-                       /* When multi-function is enabled, the ib_core gid
-                        * indexes don't necessarily match the hw ones, so
-                        * we must use our own cache */
-                       sqp->ud_header.grh.source_gid.global.subnet_prefix =
-                               to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-                                                      subnet_prefix;
-                       sqp->ud_header.grh.source_gid.global.interface_id =
-                               to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-                                              guid_cache[ah->av.ib.gid_index];
-               } else
-                       ib_get_cached_gid(ib_dev,
-                                         be32_to_cpu(ah->av.ib.port_pd) >> 24,
-                                         ah->av.ib.gid_index,
-                                         &sqp->ud_header.grh.source_gid, NULL);
+               } else {
+                       if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
+                               /* When multi-function is enabled, the ib_core gid
+                                * indexes don't necessarily match the hw ones, so
+                                * we must use our own cache
+                                */
+                               sqp->ud_header.grh.source_gid.global.subnet_prefix =
+                                       cpu_to_be64(atomic64_read(&(to_mdev(ib_dev)->sriov.
+                                                                   demux[sqp->qp.port - 1].
+                                                                   subnet_prefix)));
+                               sqp->ud_header.grh.source_gid.global.interface_id =
+                                       to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
+                                                      guid_cache[ah->av.ib.gid_index];
+                       } else {
+                               ib_get_cached_gid(ib_dev,
+                                                 be32_to_cpu(ah->av.ib.port_pd) >> 24,
+                                                 ah->av.ib.gid_index,
+                                                 &sqp->ud_header.grh.source_gid, NULL);
+                       }
                }
                memcpy(sqp->ud_header.grh.destination_gid.raw,
                       ah->av.ib.dgid, 16);
index 92ddae101ecc7dc6032705e56a2c75d46fd0bf71..8184267c79012e027ef12614aab72d373c2b51b3 100644 (file)
@@ -763,7 +763,8 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev,
        if (attr->flags)
                return ERR_PTR(-EINVAL);
 
-       if (entries < 0)
+       if (entries < 0 ||
+           (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))))
                return ERR_PTR(-EINVAL);
 
        entries = roundup_pow_of_two(entries + 1);
@@ -1094,11 +1095,16 @@ int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
                return -ENOSYS;
        }
 
-       if (entries < 1)
+       if (entries < 1 ||
+           entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))) {
+               mlx5_ib_warn(dev, "wrong entries number %d, max %d\n",
+                            entries,
+                            1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz));
                return -EINVAL;
+       }
 
        entries = roundup_pow_of_two(entries + 1);
-       if (entries >  (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1)
+       if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1)
                return -EINVAL;
 
        if (entries == ibcq->cqe + 1)
index fd17443aeacde3259cab9b50f6b918f518990179..bfc940ff9c8a531368bae44fde0ed68f000ae787 100644 (file)
@@ -962,14 +962,11 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context,
                break;
 
        case MLX5_DEV_EVENT_PORT_DOWN:
+       case MLX5_DEV_EVENT_PORT_INITIALIZED:
                ibev.event = IB_EVENT_PORT_ERR;
                port = (u8)param;
                break;
 
-       case MLX5_DEV_EVENT_PORT_INITIALIZED:
-               /* not used by ULPs */
-               return;
-
        case MLX5_DEV_EVENT_LID_CHANGE:
                ibev.event = IB_EVENT_LID_CHANGE;
                port = (u8)param;
index 307bdbca8938e1d87493d7048b93126bd9261e26..cfcfbb6b84d7c459d454e32f1d49537b00a561e7 100644 (file)
@@ -226,6 +226,8 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
                qp->rq.max_gs = 0;
                qp->rq.wqe_cnt = 0;
                qp->rq.wqe_shift = 0;
+               cap->max_recv_wr = 0;
+               cap->max_recv_sge = 0;
        } else {
                if (ucmd) {
                        qp->rq.wqe_cnt = ucmd->rq_wqe_count;
@@ -2525,10 +2527,11 @@ static u8 get_fence(u8 fence, struct ib_send_wr *wr)
                        return MLX5_FENCE_MODE_SMALL_AND_FENCE;
                else
                        return fence;
-
-       } else {
-               return 0;
+       } else if (unlikely(wr->send_flags & IB_SEND_FENCE)) {
+               return MLX5_FENCE_MODE_FENCE;
        }
+
+       return 0;
 }
 
 static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
@@ -3092,17 +3095,19 @@ int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr
        qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
 
        if (!ibqp->uobject) {
-               qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
+               qp_attr->cap.max_send_wr  = qp->sq.max_post;
                qp_attr->cap.max_send_sge = qp->sq.max_gs;
+               qp_init_attr->qp_context = ibqp->qp_context;
        } else {
                qp_attr->cap.max_send_wr  = 0;
                qp_attr->cap.max_send_sge = 0;
        }
 
-       /* We don't support inline sends for kernel QPs (yet), and we
-        * don't know what userspace's value should be.
-        */
-       qp_attr->cap.max_inline_data = 0;
+       qp_init_attr->qp_type = ibqp->qp_type;
+       qp_init_attr->recv_cq = ibqp->recv_cq;
+       qp_init_attr->send_cq = ibqp->send_cq;
+       qp_init_attr->srq = ibqp->srq;
+       qp_attr->cap.max_inline_data = qp->max_inline_data;
 
        qp_init_attr->cap            = qp_attr->cap;
 
index 3ede103097547d4355646d322b5570ebb421d2ec..69a151ae8261432ba95ad4135db57df8a336251e 100644 (file)
@@ -472,6 +472,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
                struct ipoib_ah *address, u32 qpn);
 void ipoib_reap_ah(struct work_struct *work);
 
+struct ipoib_path *__path_find(struct net_device *dev, void *gid);
 void ipoib_mark_paths_invalid(struct net_device *dev);
 void ipoib_flush_paths(struct net_device *dev);
 struct ipoib_dev_priv *ipoib_intf_alloc(const char *format);
index 3ae9726efb9837512a62214705bf5e8e9561a02c..8ca75af0e6d18d052b9d5e4be7cd644608da1f1b 100644 (file)
@@ -1299,6 +1299,8 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
        }
 }
 
+#define QPN_AND_OPTIONS_OFFSET 4
+
 static void ipoib_cm_tx_start(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
@@ -1307,6 +1309,7 @@ static void ipoib_cm_tx_start(struct work_struct *work)
        struct ipoib_neigh *neigh;
        struct ipoib_cm_tx *p;
        unsigned long flags;
+       struct ipoib_path *path;
        int ret;
 
        struct ib_sa_path_rec pathrec;
@@ -1319,7 +1322,19 @@ static void ipoib_cm_tx_start(struct work_struct *work)
                p = list_entry(priv->cm.start_list.next, typeof(*p), list);
                list_del_init(&p->list);
                neigh = p->neigh;
+
                qpn = IPOIB_QPN(neigh->daddr);
+               /*
+                * As long as the search is with these 2 locks,
+                * path existence indicates its validity.
+                */
+               path = __path_find(dev, neigh->daddr + QPN_AND_OPTIONS_OFFSET);
+               if (!path) {
+                       pr_info("%s ignore not valid path %pI6\n",
+                               __func__,
+                               neigh->daddr + QPN_AND_OPTIONS_OFFSET);
+                       goto free_neigh;
+               }
                memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
 
                spin_unlock_irqrestore(&priv->lock, flags);
@@ -1331,6 +1346,7 @@ static void ipoib_cm_tx_start(struct work_struct *work)
                spin_lock_irqsave(&priv->lock, flags);
 
                if (ret) {
+free_neigh:
                        neigh = p->neigh;
                        if (neigh) {
                                neigh->cm = NULL;
index 5ea0c14070d1f2d8af36a05c15206c63f406b97d..85de078fb0cecbe63a457227ffbbe8c19bee042a 100644 (file)
@@ -245,8 +245,6 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        skb_reset_mac_header(skb);
        skb_pull(skb, IPOIB_ENCAP_LEN);
 
-       skb->truesize = SKB_TRUESIZE(skb->len);
-
        ++dev->stats.rx_packets;
        dev->stats.rx_bytes += skb->len;
 
@@ -1030,8 +1028,17 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        }
 
        if (level == IPOIB_FLUSH_LIGHT) {
+               int oper_up;
                ipoib_mark_paths_invalid(dev);
+               /* Set IPoIB operation as down to prevent races between:
+                * the flush flow which leaves MCG and on the fly joins
+                * which can happen during that time. mcast restart task
+                * should deal with join requests we missed.
+                */
+               oper_up = test_and_clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
                ipoib_mcast_dev_flush(dev);
+               if (oper_up)
+                       set_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
                ipoib_flush_ah(dev);
        }
 
index 7d3281866ffcd520d4bca543a9ad0544f2ec159f..5f7681b975d0defccb280a47ed1477c055707fde 100644 (file)
@@ -481,7 +481,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
        return -EINVAL;
 }
 
-static struct ipoib_path *__path_find(struct net_device *dev, void *gid)
+struct ipoib_path *__path_find(struct net_device *dev, void *gid)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct rb_node *n = priv->path_tree.rb_node;
@@ -1131,7 +1131,9 @@ struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr)
                                neigh = NULL;
                                goto out_unlock;
                        }
-                       neigh->alive = jiffies;
+
+                       if (likely(skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE))
+                               neigh->alive = jiffies;
                        goto out_unlock;
                }
        }
index fd4100d56d8c5509986be23e40d2af137cd840b1..aff42d5e2296b4e0c91732bdea25aab05c47d315 100644 (file)
@@ -317,6 +317,19 @@ static struct usb_device_id xpad_table[] = {
 
 MODULE_DEVICE_TABLE(usb, xpad_table);
 
+struct xpad_output_packet {
+       u8 data[XPAD_PKT_LEN];
+       u8 len;
+       bool pending;
+};
+
+#define XPAD_OUT_CMD_IDX       0
+#define XPAD_OUT_FF_IDX                1
+#define XPAD_OUT_LED_IDX       (1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF))
+#define XPAD_NUM_OUT_PACKETS   (1 + \
+                                IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \
+                                IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS))
+
 struct usb_xpad {
        struct input_dev *dev;          /* input device interface */
        struct usb_device *udev;        /* usb device */
@@ -329,9 +342,13 @@ struct usb_xpad {
        dma_addr_t idata_dma;
 
        struct urb *irq_out;            /* urb for interrupt out report */
+       bool irq_out_active;            /* we must not use an active URB */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
-       struct mutex odata_mutex;
+       spinlock_t odata_lock;
+
+       struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS];
+       int last_out_packet;
 
 #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct xpad_led *led;
@@ -678,18 +695,71 @@ exit:
                        __func__, retval);
 }
 
+/* Callers must hold xpad->odata_lock spinlock */
+static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad)
+{
+       struct xpad_output_packet *pkt, *packet = NULL;
+       int i;
+
+       for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) {
+               if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS)
+                       xpad->last_out_packet = 0;
+
+               pkt = &xpad->out_packets[xpad->last_out_packet];
+               if (pkt->pending) {
+                       dev_dbg(&xpad->intf->dev,
+                               "%s - found pending output packet %d\n",
+                               __func__, xpad->last_out_packet);
+                       packet = pkt;
+                       break;
+               }
+       }
+
+       if (packet) {
+               memcpy(xpad->odata, packet->data, packet->len);
+               xpad->irq_out->transfer_buffer_length = packet->len;
+               packet->pending = false;
+               return true;
+       }
+
+       return false;
+}
+
+/* Callers must hold xpad->odata_lock spinlock */
+static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad)
+{
+       int error;
+
+       if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) {
+               error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+               if (error) {
+                       dev_err(&xpad->intf->dev,
+                               "%s - usb_submit_urb failed with result %d\n",
+                               __func__, error);
+                       return -EIO;
+               }
+
+               xpad->irq_out_active = true;
+       }
+
+       return 0;
+}
+
 static void xpad_irq_out(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
        struct device *dev = &xpad->intf->dev;
-       int retval, status;
+       int status = urb->status;
+       int error;
+       unsigned long flags;
 
-       status = urb->status;
+       spin_lock_irqsave(&xpad->odata_lock, flags);
 
        switch (status) {
        case 0:
                /* success */
-               return;
+               xpad->irq_out_active = xpad_prepare_next_out_packet(xpad);
+               break;
 
        case -ECONNRESET:
        case -ENOENT:
@@ -697,19 +767,26 @@ static void xpad_irq_out(struct urb *urb)
                /* this urb is terminated, clean up */
                dev_dbg(dev, "%s - urb shutting down with status: %d\n",
                        __func__, status);
-               return;
+               xpad->irq_out_active = false;
+               break;
 
        default:
                dev_dbg(dev, "%s - nonzero urb status received: %d\n",
                        __func__, status);
-               goto exit;
+               break;
        }
 
-exit:
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-       if (retval)
-               dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
-                       __func__, retval);
+       if (xpad->irq_out_active) {
+               error = usb_submit_urb(urb, GFP_ATOMIC);
+               if (error) {
+                       dev_err(dev,
+                               "%s - usb_submit_urb failed with result %d\n",
+                               __func__, error);
+                       xpad->irq_out_active = false;
+               }
+       }
+
+       spin_unlock_irqrestore(&xpad->odata_lock, flags);
 }
 
 static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -728,7 +805,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
                goto fail1;
        }
 
-       mutex_init(&xpad->odata_mutex);
+       spin_lock_init(&xpad->odata_lock);
 
        xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
        if (!xpad->irq_out) {
@@ -770,27 +847,57 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
 
 static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
 {
+       struct xpad_output_packet *packet =
+                       &xpad->out_packets[XPAD_OUT_CMD_IDX];
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&xpad->odata_lock, flags);
+
+       packet->data[0] = 0x08;
+       packet->data[1] = 0x00;
+       packet->data[2] = 0x0F;
+       packet->data[3] = 0xC0;
+       packet->data[4] = 0x00;
+       packet->data[5] = 0x00;
+       packet->data[6] = 0x00;
+       packet->data[7] = 0x00;
+       packet->data[8] = 0x00;
+       packet->data[9] = 0x00;
+       packet->data[10] = 0x00;
+       packet->data[11] = 0x00;
+       packet->len = 12;
+       packet->pending = true;
+
+       /* Reset the sequence so we send out presence first */
+       xpad->last_out_packet = -1;
+       retval = xpad_try_sending_next_out_packet(xpad);
+
+       spin_unlock_irqrestore(&xpad->odata_lock, flags);
+
+       return retval;
+}
+
+static int xpad_start_xbox_one(struct usb_xpad *xpad)
+{
+       struct xpad_output_packet *packet =
+                       &xpad->out_packets[XPAD_OUT_CMD_IDX];
+       unsigned long flags;
        int retval;
 
-       mutex_lock(&xpad->odata_mutex);
+       spin_lock_irqsave(&xpad->odata_lock, flags);
 
-       xpad->odata[0] = 0x08;
-       xpad->odata[1] = 0x00;
-       xpad->odata[2] = 0x0F;
-       xpad->odata[3] = 0xC0;
-       xpad->odata[4] = 0x00;
-       xpad->odata[5] = 0x00;
-       xpad->odata[6] = 0x00;
-       xpad->odata[7] = 0x00;
-       xpad->odata[8] = 0x00;
-       xpad->odata[9] = 0x00;
-       xpad->odata[10] = 0x00;
-       xpad->odata[11] = 0x00;
-       xpad->irq_out->transfer_buffer_length = 12;
+       /* Xbox one controller needs to be initialized. */
+       packet->data[0] = 0x05;
+       packet->data[1] = 0x20;
+       packet->len = 2;
+       packet->pending = true;
 
-       retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       /* Reset the sequence so we send out start packet first */
+       xpad->last_out_packet = -1;
+       retval = xpad_try_sending_next_out_packet(xpad);
 
-       mutex_unlock(&xpad->odata_mutex);
+       spin_unlock_irqrestore(&xpad->odata_lock, flags);
 
        return retval;
 }
@@ -799,8 +906,11 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
 static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
+       struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX];
        __u16 strong;
        __u16 weak;
+       int retval;
+       unsigned long flags;
 
        if (effect->type != FF_RUMBLE)
                return 0;
@@ -808,69 +918,80 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
        strong = effect->u.rumble.strong_magnitude;
        weak = effect->u.rumble.weak_magnitude;
 
+       spin_lock_irqsave(&xpad->odata_lock, flags);
+
        switch (xpad->xtype) {
        case XTYPE_XBOX:
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x06;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = strong / 256;  /* left actuator */
-               xpad->odata[4] = 0x00;
-               xpad->odata[5] = weak / 256;    /* right actuator */
-               xpad->irq_out->transfer_buffer_length = 6;
+               packet->data[0] = 0x00;
+               packet->data[1] = 0x06;
+               packet->data[2] = 0x00;
+               packet->data[3] = strong / 256; /* left actuator */
+               packet->data[4] = 0x00;
+               packet->data[5] = weak / 256;   /* right actuator */
+               packet->len = 6;
+               packet->pending = true;
                break;
 
        case XTYPE_XBOX360:
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x08;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = strong / 256;  /* left actuator? */
-               xpad->odata[4] = weak / 256;    /* right actuator? */
-               xpad->odata[5] = 0x00;
-               xpad->odata[6] = 0x00;
-               xpad->odata[7] = 0x00;
-               xpad->irq_out->transfer_buffer_length = 8;
+               packet->data[0] = 0x00;
+               packet->data[1] = 0x08;
+               packet->data[2] = 0x00;
+               packet->data[3] = strong / 256;  /* left actuator? */
+               packet->data[4] = weak / 256;   /* right actuator? */
+               packet->data[5] = 0x00;
+               packet->data[6] = 0x00;
+               packet->data[7] = 0x00;
+               packet->len = 8;
+               packet->pending = true;
                break;
 
        case XTYPE_XBOX360W:
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x01;
-               xpad->odata[2] = 0x0F;
-               xpad->odata[3] = 0xC0;
-               xpad->odata[4] = 0x00;
-               xpad->odata[5] = strong / 256;
-               xpad->odata[6] = weak / 256;
-               xpad->odata[7] = 0x00;
-               xpad->odata[8] = 0x00;
-               xpad->odata[9] = 0x00;
-               xpad->odata[10] = 0x00;
-               xpad->odata[11] = 0x00;
-               xpad->irq_out->transfer_buffer_length = 12;
+               packet->data[0] = 0x00;
+               packet->data[1] = 0x01;
+               packet->data[2] = 0x0F;
+               packet->data[3] = 0xC0;
+               packet->data[4] = 0x00;
+               packet->data[5] = strong / 256;
+               packet->data[6] = weak / 256;
+               packet->data[7] = 0x00;
+               packet->data[8] = 0x00;
+               packet->data[9] = 0x00;
+               packet->data[10] = 0x00;
+               packet->data[11] = 0x00;
+               packet->len = 12;
+               packet->pending = true;
                break;
 
        case XTYPE_XBOXONE:
-               xpad->odata[0] = 0x09; /* activate rumble */
-               xpad->odata[1] = 0x08;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = 0x08; /* continuous effect */
-               xpad->odata[4] = 0x00; /* simple rumble mode */
-               xpad->odata[5] = 0x03; /* L and R actuator only */
-               xpad->odata[6] = 0x00; /* TODO: LT actuator */
-               xpad->odata[7] = 0x00; /* TODO: RT actuator */
-               xpad->odata[8] = strong / 256;  /* left actuator */
-               xpad->odata[9] = weak / 256;    /* right actuator */
-               xpad->odata[10] = 0x80; /* length of pulse */
-               xpad->odata[11] = 0x00; /* stop period of pulse */
-               xpad->irq_out->transfer_buffer_length = 12;
+               packet->data[0] = 0x09; /* activate rumble */
+               packet->data[1] = 0x08;
+               packet->data[2] = 0x00;
+               packet->data[3] = 0x08; /* continuous effect */
+               packet->data[4] = 0x00; /* simple rumble mode */
+               packet->data[5] = 0x03; /* L and R actuator only */
+               packet->data[6] = 0x00; /* TODO: LT actuator */
+               packet->data[7] = 0x00; /* TODO: RT actuator */
+               packet->data[8] = strong / 256; /* left actuator */
+               packet->data[9] = weak / 256;   /* right actuator */
+               packet->data[10] = 0x80;        /* length of pulse */
+               packet->data[11] = 0x00;        /* stop period of pulse */
+               packet->len = 12;
+               packet->pending = true;
                break;
 
        default:
                dev_dbg(&xpad->dev->dev,
                        "%s - rumble command sent to unsupported xpad type: %d\n",
                        __func__, xpad->xtype);
-               return -EINVAL;
+               retval = -EINVAL;
+               goto out;
        }
 
-       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+       retval = xpad_try_sending_next_out_packet(xpad);
+
+out:
+       spin_unlock_irqrestore(&xpad->odata_lock, flags);
+       return retval;
 }
 
 static int xpad_init_ff(struct usb_xpad *xpad)
@@ -921,36 +1042,44 @@ struct xpad_led {
  */
 static void xpad_send_led_command(struct usb_xpad *xpad, int command)
 {
+       struct xpad_output_packet *packet =
+                       &xpad->out_packets[XPAD_OUT_LED_IDX];
+       unsigned long flags;
+
        command %= 16;
 
-       mutex_lock(&xpad->odata_mutex);
+       spin_lock_irqsave(&xpad->odata_lock, flags);
 
        switch (xpad->xtype) {
        case XTYPE_XBOX360:
-               xpad->odata[0] = 0x01;
-               xpad->odata[1] = 0x03;
-               xpad->odata[2] = command;
-               xpad->irq_out->transfer_buffer_length = 3;
+               packet->data[0] = 0x01;
+               packet->data[1] = 0x03;
+               packet->data[2] = command;
+               packet->len = 3;
+               packet->pending = true;
                break;
+
        case XTYPE_XBOX360W:
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x00;
-               xpad->odata[2] = 0x08;
-               xpad->odata[3] = 0x40 + command;
-               xpad->odata[4] = 0x00;
-               xpad->odata[5] = 0x00;
-               xpad->odata[6] = 0x00;
-               xpad->odata[7] = 0x00;
-               xpad->odata[8] = 0x00;
-               xpad->odata[9] = 0x00;
-               xpad->odata[10] = 0x00;
-               xpad->odata[11] = 0x00;
-               xpad->irq_out->transfer_buffer_length = 12;
+               packet->data[0] = 0x00;
+               packet->data[1] = 0x00;
+               packet->data[2] = 0x08;
+               packet->data[3] = 0x40 + command;
+               packet->data[4] = 0x00;
+               packet->data[5] = 0x00;
+               packet->data[6] = 0x00;
+               packet->data[7] = 0x00;
+               packet->data[8] = 0x00;
+               packet->data[9] = 0x00;
+               packet->data[10] = 0x00;
+               packet->data[11] = 0x00;
+               packet->len = 12;
+               packet->pending = true;
                break;
        }
 
-       usb_submit_urb(xpad->irq_out, GFP_KERNEL);
-       mutex_unlock(&xpad->odata_mutex);
+       xpad_try_sending_next_out_packet(xpad);
+
+       spin_unlock_irqrestore(&xpad->odata_lock, flags);
 }
 
 /*
@@ -1048,13 +1177,8 @@ static int xpad_open(struct input_dev *dev)
        if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
                return -EIO;
 
-       if (xpad->xtype == XTYPE_XBOXONE) {
-               /* Xbox one controller needs to be initialized. */
-               xpad->odata[0] = 0x05;
-               xpad->odata[1] = 0x20;
-               xpad->irq_out->transfer_buffer_length = 2;
-               return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
-       }
+       if (xpad->xtype == XTYPE_XBOXONE)
+               return xpad_start_xbox_one(xpad);
 
        return 0;
 }
@@ -1200,22 +1324,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        int ep_irq_in_idx;
        int i, error;
 
+       if (intf->cur_altsetting->desc.bNumEndpoints != 2)
+               return -ENODEV;
+
        for (i = 0; xpad_device[i].idVendor; i++) {
                if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
                    (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
                        break;
        }
 
-       if (xpad_device[i].xtype == XTYPE_XBOXONE &&
-           intf->cur_altsetting->desc.bInterfaceNumber != 0) {
-               /*
-                * The Xbox One controller lists three interfaces all with the
-                * same interface class, subclass and protocol. Differentiate by
-                * interface number.
-                */
-               return -ENODEV;
-       }
-
        xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
        if (!xpad)
                return -ENOMEM;
@@ -1246,6 +1363,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
                        if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
                                xpad->xtype = XTYPE_XBOX360W;
+                       else if (intf->cur_altsetting->desc.bInterfaceProtocol == 208)
+                               xpad->xtype = XTYPE_XBOXONE;
                        else
                                xpad->xtype = XTYPE_XBOX360;
                } else {
@@ -1260,6 +1379,17 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        xpad->mapping |= MAP_STICKS_TO_NULL;
        }
 
+       if (xpad->xtype == XTYPE_XBOXONE &&
+           intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+               /*
+                * The Xbox One controller lists three interfaces all with the
+                * same interface class, subclass and protocol. Differentiate by
+                * interface number.
+                */
+               error = -ENODEV;
+               goto err_free_in_urb;
+       }
+
        error = xpad_init_output(intf, xpad);
        if (error)
                goto err_free_in_urb;
index acc5394afb0343a62a4502f24251898d216daf09..29485bc4221cc4bcc452065a1e51113b7acb3ac1 100644 (file)
@@ -376,7 +376,7 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
        /* Reset the KBC controller to clear all previous status.*/
        reset_control_assert(kbc->rst);
        udelay(100);
-       reset_control_assert(kbc->rst);
+       reset_control_deassert(kbc->rst);
        udelay(100);
 
        tegra_kbc_config_pins(kbc);
index 7fbf7247e65f5879faa006d19340d8711dc34883..7e5222aec7c1e5e5f47b229422e84842a1df43cf 100644 (file)
@@ -32,8 +32,7 @@ struct keyreset_state {
 
 static void do_restart(struct work_struct *unused)
 {
-       sys_sync();
-       kernel_restart(NULL);
+       orderly_reboot();
 }
 
 static void do_reset_fn(void *priv)
index 2f589857a0395d8c48f685f47bd1c9ceb8445213..d15b338130213c53489baa600d6dcea1500790d4 100644 (file)
@@ -4,7 +4,8 @@
  * Copyright (c) 2013 ELAN Microelectronics Corp.
  *
  * Author: æž—政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.6.0
+ * Author: KT Liao <kt.liao@emc.com.tw>
+ * Version: 1.6.2
  *
  * Based on cyapa driver:
  * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +41,7 @@
 #include "elan_i2c.h"
 
 #define DRIVER_NAME            "elan_i2c"
-#define ELAN_DRIVER_VERSION    "1.6.1"
+#define ELAN_DRIVER_VERSION    "1.6.2"
 #define ELAN_VENDOR_ID         0x04f3
 #define ETP_MAX_PRESSURE       255
 #define ETP_FWIDTH_REDUCE      90
@@ -199,9 +200,41 @@ static int elan_sleep(struct elan_tp_data *data)
        return error;
 }
 
+static int elan_query_product(struct elan_tp_data *data)
+{
+       int error;
+
+       error = data->ops->get_product_id(data->client, &data->product_id);
+       if (error)
+               return error;
+
+       error = data->ops->get_sm_version(data->client, &data->ic_type,
+                                         &data->sm_version);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int elan_check_ASUS_special_fw(struct elan_tp_data *data)
+{
+       if (data->ic_type != 0x0E)
+               return false;
+
+       switch (data->product_id) {
+       case 0x05 ... 0x07:
+       case 0x09:
+       case 0x13:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int __elan_initialize(struct elan_tp_data *data)
 {
        struct i2c_client *client = data->client;
+       bool woken_up = false;
        int error;
 
        error = data->ops->initialize(client);
@@ -210,6 +243,27 @@ static int __elan_initialize(struct elan_tp_data *data)
                return error;
        }
 
+       error = elan_query_product(data);
+       if (error)
+               return error;
+
+       /*
+        * Some ASUS devices were shipped with firmware that requires
+        * touchpads to be woken up first, before attempting to switch
+        * them into absolute reporting mode.
+        */
+       if (elan_check_ASUS_special_fw(data)) {
+               error = data->ops->sleep_control(client, false);
+               if (error) {
+                       dev_err(&client->dev,
+                               "failed to wake device up: %d\n", error);
+                       return error;
+               }
+
+               msleep(200);
+               woken_up = true;
+       }
+
        data->mode |= ETP_ENABLE_ABS;
        error = data->ops->set_mode(client, data->mode);
        if (error) {
@@ -218,11 +272,13 @@ static int __elan_initialize(struct elan_tp_data *data)
                return error;
        }
 
-       error = data->ops->sleep_control(client, false);
-       if (error) {
-               dev_err(&client->dev,
-                       "failed to wake device up: %d\n", error);
-               return error;
+       if (!woken_up) {
+               error = data->ops->sleep_control(client, false);
+               if (error) {
+                       dev_err(&client->dev,
+                               "failed to wake device up: %d\n", error);
+                       return error;
+               }
        }
 
        return 0;
@@ -248,10 +304,6 @@ static int elan_query_device_info(struct elan_tp_data *data)
 {
        int error;
 
-       error = data->ops->get_product_id(data->client, &data->product_id);
-       if (error)
-               return error;
-
        error = data->ops->get_version(data->client, false, &data->fw_version);
        if (error)
                return error;
@@ -261,11 +313,6 @@ static int elan_query_device_info(struct elan_tp_data *data)
        if (error)
                return error;
 
-       error = data->ops->get_sm_version(data->client, &data->ic_type,
-                                         &data->sm_version);
-       if (error)
-               return error;
-
        error = data->ops->get_version(data->client, true, &data->iap_version);
        if (error)
                return error;
index 78f93cf68840d24328ebd0630f86c4e372d051bf..43482ae1e0492ef38f160611b96828f47581a022 100644 (file)
@@ -1163,6 +1163,13 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"),
                },
        },
+       {
+               /* Fujitsu H760 also has a middle button */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
+               },
+       },
 #endif
        { }
 };
@@ -1507,10 +1514,10 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
                },
        },
        {
-               /* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
+               /* Fujitsu H760 does not work with crc_enabled == 0 */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
                },
        },
        {
@@ -1520,6 +1527,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"),
                },
        },
+       {
+               /* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
+               },
+       },
+       {
+               /* Fujitsu LIFEBOOK E556 does not work with crc_enabled == 0 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E556"),
+               },
+       },
        {
                /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
                .matches = {
@@ -1568,13 +1589,7 @@ static int elantech_set_properties(struct elantech_data *etd)
                case 5:
                        etd->hw_version = 3;
                        break;
-               case 6:
-               case 7:
-               case 8:
-               case 9:
-               case 10:
-               case 13:
-               case 14:
+               case 6 ... 14:
                        etd->hw_version = 4;
                        break;
                default:
index a3f0f5a47490e936e31b45594861d692503429b1..0f586780ceb4bee18a38428b889dba8d994ea4c7 100644 (file)
@@ -355,18 +355,11 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
                return -ENXIO;
        }
 
-       if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) {
-               psmouse_dbg(psmouse, "VMMouse port in use.\n");
-               return -EBUSY;
-       }
-
        /* Check if the device is present */
        response = ~VMMOUSE_PROTO_MAGIC;
        VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2);
-       if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU) {
-               release_region(VMMOUSE_PROTO_PORT, 4);
+       if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU)
                return -ENXIO;
-       }
 
        if (set_properties) {
                psmouse->vendor = VMMOUSE_VENDOR;
@@ -374,8 +367,6 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
                psmouse->model = version;
        }
 
-       release_region(VMMOUSE_PROTO_PORT, 4);
-
        return 0;
 }
 
@@ -394,7 +385,6 @@ static void vmmouse_disconnect(struct psmouse *psmouse)
        psmouse_reset(psmouse);
        input_unregister_device(priv->abs_dev);
        kfree(priv);
-       release_region(VMMOUSE_PROTO_PORT, 4);
 }
 
 /**
@@ -438,15 +428,10 @@ int vmmouse_init(struct psmouse *psmouse)
        struct input_dev *rel_dev = psmouse->dev, *abs_dev;
        int error;
 
-       if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) {
-               psmouse_dbg(psmouse, "VMMouse port in use.\n");
-               return -EBUSY;
-       }
-
        psmouse_reset(psmouse);
        error = vmmouse_enable(psmouse);
        if (error)
-               goto release_region;
+               return error;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        abs_dev = input_allocate_device();
@@ -502,8 +487,5 @@ init_fail:
        kfree(priv);
        psmouse->private = NULL;
 
-release_region:
-       release_region(VMMOUSE_PROTO_PORT, 4);
-
        return error;
 }
index a5eed2ade53de3a4e1d06776288ec17baba52530..34da81c006b6d80d3df98feffc7651d8eaa3f2c8 100644 (file)
@@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
                return -EBUSY;
 #endif
 
-       i8042_reset = 1;
+       i8042_reset = I8042_RESET_ALWAYS;
        return 0;
 }
 
index ee1ad27d6ed06ef70370f3096352b37acb1c1368..08a1c10a1448d12db092a1c3f7525e4f5f1b76a2 100644 (file)
@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
                return -EBUSY;
 #endif
 
-       i8042_reset = 1;
+       i8042_reset = I8042_RESET_ALWAYS;
 
        return 0;
 }
index f708c75d16f1d919f4e054c94437fb6e4e587866..1aabea43329edf56f2067c73eafca4d140d3ac4b 100644 (file)
@@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
 
 static inline int i8042_platform_init(void)
 {
-       i8042_reset = 1;
+       i8042_reset = I8042_RESET_ALWAYS;
        return 0;
 }
 
index afcd1c1a05b272b1d615b481f2de9c0a812a2889..6231d63860ee324031d36e6e1c42dd57407dc27f 100644 (file)
@@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
                }
        }
 
-       i8042_reset = 1;
+       i8042_reset = I8042_RESET_ALWAYS;
 
        return 0;
 }
index 73f5cc124a3606a5cb73406e207d8a27fd4c339e..455747552f858a8819ec18d03317980352e514ea 100644 (file)
@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
        if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
                return -EBUSY;
 
-       i8042_reset = 1;
+       i8042_reset = I8042_RESET_ALWAYS;
        return 0;
 }
 
index 68f5f4a0f1e72f10b35e45243218e6cfbf3d586e..f4bfb4b2d50a356336fdab08124f52085a82f24f 100644 (file)
@@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
        { }
 };
 
+/*
+ * On some Asus laptops, just running self tests cause problems.
+ */
+static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
+               },
+       },
+       { }
+};
 static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
        {
                /* MSI Wind U-100 */
@@ -1072,12 +1156,18 @@ static int __init i8042_platform_init(void)
                return retval;
 
 #if defined(__ia64__)
-        i8042_reset = true;
+        i8042_reset = I8042_RESET_ALWAYS;
 #endif
 
 #ifdef CONFIG_X86
-       if (dmi_check_system(i8042_dmi_reset_table))
-               i8042_reset = true;
+       /* Honor module parameter when value is not default */
+       if (i8042_reset == I8042_RESET_DEFAULT) {
+               if (dmi_check_system(i8042_dmi_reset_table))
+                       i8042_reset = I8042_RESET_ALWAYS;
+
+               if (dmi_check_system(i8042_dmi_noselftest_table))
+                       i8042_reset = I8042_RESET_NEVER;
+       }
 
        if (dmi_check_system(i8042_dmi_noloop_table))
                i8042_noloop = true;
index 454195709a824b3e5a346b3aa9e087672dccdcae..89abfdb539ac750ff50eca67f77b2fe6898ff6f0 100644 (file)
@@ -48,9 +48,39 @@ static bool i8042_unlock;
 module_param_named(unlock, i8042_unlock, bool, 0);
 MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
 
-static bool i8042_reset;
-module_param_named(reset, i8042_reset, bool, 0);
-MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
+enum i8042_controller_reset_mode {
+       I8042_RESET_NEVER,
+       I8042_RESET_ALWAYS,
+       I8042_RESET_ON_S2RAM,
+#define I8042_RESET_DEFAULT    I8042_RESET_ON_S2RAM
+};
+static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
+static int i8042_set_reset(const char *val, const struct kernel_param *kp)
+{
+       enum i8042_controller_reset_mode *arg = kp->arg;
+       int error;
+       bool reset;
+
+       if (val) {
+               error = kstrtobool(val, &reset);
+               if (error)
+                       return error;
+       } else {
+               reset = true;
+       }
+
+       *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
+       return 0;
+}
+
+static const struct kernel_param_ops param_ops_reset_param = {
+       .flags = KERNEL_PARAM_OPS_FL_NOARG,
+       .set = i8042_set_reset,
+};
+#define param_check_reset_param(name, p)       \
+       __param_check(name, p, enum i8042_controller_reset_mode)
+module_param_named(reset, i8042_reset, reset_param, 0);
+MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
 
 static bool i8042_direct;
 module_param_named(direct, i8042_direct, bool, 0);
@@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
  * Reset the controller and reset CRT to the original value set by BIOS.
  */
 
-static void i8042_controller_reset(bool force_reset)
+static void i8042_controller_reset(bool s2r_wants_reset)
 {
        i8042_flush();
 
@@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
  * Reset the controller if requested.
  */
 
-       if (i8042_reset || force_reset)
+       if (i8042_reset == I8042_RESET_ALWAYS ||
+           (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
                i8042_controller_selftest();
+       }
 
 /*
  * Restore the original control register setting.
@@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
  * before suspending.
  */
 
-static int i8042_controller_resume(bool force_reset)
+static int i8042_controller_resume(bool s2r_wants_reset)
 {
        int error;
 
@@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
        if (error)
                return error;
 
-       if (i8042_reset || force_reset) {
+       if (i8042_reset == I8042_RESET_ALWAYS ||
+           (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
                error = i8042_controller_selftest();
                if (error)
                        return error;
@@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
 
 static int i8042_pm_resume(struct device *dev)
 {
-       bool force_reset;
+       bool want_reset;
        int i;
 
        for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
         * off control to the platform firmware, otherwise we can simply restore
         * the mode.
         */
-       force_reset = pm_resume_via_firmware();
+       want_reset = pm_resume_via_firmware();
 
-       return i8042_controller_resume(force_reset);
+       return i8042_controller_resume(want_reset);
 }
 
 static int i8042_pm_thaw(struct device *dev)
@@ -1277,6 +1310,7 @@ static int __init i8042_create_kbd_port(void)
        serio->start            = i8042_start;
        serio->stop             = i8042_stop;
        serio->close            = i8042_port_close;
+       serio->ps2_cmd_mutex    = &i8042_mutex;
        serio->port_data        = port;
        serio->dev.parent       = &i8042_platform_device->dev;
        strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
@@ -1304,6 +1338,7 @@ static int __init i8042_create_aux_port(int idx)
        serio->write            = i8042_aux_write;
        serio->start            = i8042_start;
        serio->stop             = i8042_stop;
+       serio->ps2_cmd_mutex    = &i8042_mutex;
        serio->port_data        = port;
        serio->dev.parent       = &i8042_platform_device->dev;
        if (idx < 0) {
@@ -1373,21 +1408,6 @@ static void i8042_unregister_ports(void)
        }
 }
 
-/*
- * Checks whether port belongs to i8042 controller.
- */
-bool i8042_check_port_owner(const struct serio *port)
-{
-       int i;
-
-       for (i = 0; i < I8042_NUM_PORTS; i++)
-               if (i8042_ports[i].serio == port)
-                       return true;
-
-       return false;
-}
-EXPORT_SYMBOL(i8042_check_port_owner);
-
 static void i8042_free_irqs(void)
 {
        if (i8042_aux_irq_registered)
@@ -1495,7 +1515,7 @@ static int __init i8042_probe(struct platform_device *dev)
 
        i8042_platform_device = dev;
 
-       if (i8042_reset) {
+       if (i8042_reset == I8042_RESET_ALWAYS) {
                error = i8042_controller_selftest();
                if (error)
                        return error;
index 316f2c8971011dae527d506ee18d49ce96f316e0..83e9c663aa6727da129d2fe8b0256f73f4581d53 100644 (file)
@@ -56,19 +56,17 @@ EXPORT_SYMBOL(ps2_sendbyte);
 
 void ps2_begin_command(struct ps2dev *ps2dev)
 {
-       mutex_lock(&ps2dev->cmd_mutex);
+       struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
 
-       if (i8042_check_port_owner(ps2dev->serio))
-               i8042_lock_chip();
+       mutex_lock(m);
 }
 EXPORT_SYMBOL(ps2_begin_command);
 
 void ps2_end_command(struct ps2dev *ps2dev)
 {
-       if (i8042_check_port_owner(ps2dev->serio))
-               i8042_unlock_chip();
+       struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
 
-       mutex_unlock(&ps2dev->cmd_mutex);
+       mutex_unlock(m);
 }
 EXPORT_SYMBOL(ps2_end_command);
 
index d214f22ed305aab0773fe783c2e692c62fc342eb..45b466e3bbe84372b68ab6a56abfc177adef733f 100644 (file)
@@ -126,7 +126,7 @@ struct sur40_image_header {
 #define VIDEO_PACKET_SIZE  16384
 
 /* polling interval (ms) */
-#define POLL_INTERVAL 4
+#define POLL_INTERVAL 1
 
 /* maximum number of contacts FIXME: this is a guess? */
 #define MAX_CONTACTS 64
@@ -441,7 +441,7 @@ static void sur40_process_video(struct sur40_state *sur40)
 
        /* return error if streaming was stopped in the meantime */
        if (sur40->sequence == -1)
-               goto err_poll;
+               return;
 
        /* mark as finished */
        v4l2_get_timestamp(&new_buf->vb.timestamp);
@@ -730,6 +730,7 @@ static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count)
 static void sur40_stop_streaming(struct vb2_queue *vq)
 {
        struct sur40_state *sur40 = vb2_get_drv_priv(vq);
+       vb2_wait_for_all_buffers(vq);
        sur40->sequence = -1;
 
        /* Release all active buffers */
index 7295c198aa086be8630b3a77e202415649c6937b..6fe55d598facac3a05114e57e03b92b9d162eb87 100644 (file)
 #include <linux/regmap.h>
 #include "tsc200x-core.h"
 
+static const struct input_id tsc2004_input_id = {
+       .bustype = BUS_I2C,
+       .product = 2004,
+};
+
 static int tsc2004_cmd(struct device *dev, u8 cmd)
 {
        u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd;
@@ -42,7 +47,7 @@ static int tsc2004_probe(struct i2c_client *i2c,
                         const struct i2c_device_id *id)
 
 {
-       return tsc200x_probe(&i2c->dev, i2c->irq, BUS_I2C,
+       return tsc200x_probe(&i2c->dev, i2c->irq, &tsc2004_input_id,
                             devm_regmap_init_i2c(i2c, &tsc200x_regmap_config),
                             tsc2004_cmd);
 }
index b9f593dfd2ef8368223e5d7d7d9ca06856afcc8d..f2c5f0e47f77dd6ab177adec2bb102ed0da5dd08 100644 (file)
 #include <linux/regmap.h>
 #include "tsc200x-core.h"
 
+static const struct input_id tsc2005_input_id = {
+       .bustype = BUS_SPI,
+       .product = 2005,
+};
+
 static int tsc2005_cmd(struct device *dev, u8 cmd)
 {
        u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd;
@@ -62,7 +67,7 @@ static int tsc2005_probe(struct spi_device *spi)
        if (error)
                return error;
 
-       return tsc200x_probe(&spi->dev, spi->irq, BUS_SPI,
+       return tsc200x_probe(&spi->dev, spi->irq, &tsc2005_input_id,
                             devm_regmap_init_spi(spi, &tsc200x_regmap_config),
                             tsc2005_cmd);
 }
index 15240c1ee850abd4f5099db9a9e21a4b8ecf725b..dfa7f1c4f5453bd9d1544badc24548eab0851361 100644 (file)
@@ -450,7 +450,7 @@ static void tsc200x_close(struct input_dev *input)
        mutex_unlock(&ts->mutex);
 }
 
-int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
+int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
                  struct regmap *regmap,
                  int (*tsc200x_cmd)(struct device *dev, u8 cmd))
 {
@@ -547,9 +547,18 @@ int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
        snprintf(ts->phys, sizeof(ts->phys),
                 "%s/input-ts", dev_name(dev));
 
-       input_dev->name = "TSC200X touchscreen";
+       if (tsc_id->product == 2004) {
+               input_dev->name = "TSC200X touchscreen";
+       } else {
+               input_dev->name = devm_kasprintf(dev, GFP_KERNEL,
+                                                "TSC%04d touchscreen",
+                                                tsc_id->product);
+               if (!input_dev->name)
+                       return -ENOMEM;
+       }
+
        input_dev->phys = ts->phys;
-       input_dev->id.bustype = bustype;
+       input_dev->id = *tsc_id;
        input_dev->dev.parent = dev;
        input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
index 7a482d1026148c692988172773af1c3f2ad9e57e..49a63a3c684094a331a7465dda370f1a2f0fcb21 100644 (file)
@@ -70,7 +70,7 @@
 extern const struct regmap_config tsc200x_regmap_config;
 extern const struct dev_pm_ops tsc200x_pm_ops;
 
-int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
+int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
                  struct regmap *regmap,
                  int (*tsc200x_cmd)(struct device *dev, u8 cmd));
 int tsc200x_remove(struct device *dev);
index 2792ca397dd085eb1f8d30d0af2a12a233389a41..3ed0ce1e4dcb13251b6d2eb9ea74f08f265fa83b 100644 (file)
@@ -27,7 +27,7 @@ MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#define W8001_MAX_LENGTH       11
+#define W8001_MAX_LENGTH       13
 #define W8001_LEAD_MASK                0x80
 #define W8001_LEAD_BYTE                0x80
 #define W8001_TAB_MASK         0x40
index b9319b76a8a193e9da184290e0282a94d5d2ae14..0397985a260128c6054513a22133adafd460991c 100644 (file)
@@ -352,9 +352,11 @@ static void init_iommu_group(struct device *dev)
        if (!domain)
                goto out;
 
-       dma_domain = to_pdomain(domain)->priv;
+       if (to_pdomain(domain)->flags == PD_DMA_OPS_MASK) {
+               dma_domain = to_pdomain(domain)->priv;
+               init_unity_mappings_for_device(dev, dma_domain);
+       }
 
-       init_unity_mappings_for_device(dev, dma_domain);
 out:
        iommu_group_put(group);
 }
@@ -2322,8 +2324,15 @@ static void update_device_table(struct protection_domain *domain)
 {
        struct iommu_dev_data *dev_data;
 
-       list_for_each_entry(dev_data, &domain->dev_list, list)
+       list_for_each_entry(dev_data, &domain->dev_list, list) {
                set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled);
+
+               if (dev_data->devid == dev_data->alias)
+                       continue;
+
+               /* There is an alias, update device table entry for it */
+               set_dte_entry(dev_data->alias, domain, dev_data->ats.enabled);
+       }
 }
 
 static void update_domain(struct protection_domain *domain)
@@ -2970,9 +2979,7 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 static void amd_iommu_domain_free(struct iommu_domain *dom)
 {
        struct protection_domain *domain;
-
-       if (!dom)
-               return;
+       struct dma_ops_domain *dma_dom;
 
        domain = to_pdomain(dom);
 
@@ -2981,13 +2988,24 @@ static void amd_iommu_domain_free(struct iommu_domain *dom)
 
        BUG_ON(domain->dev_cnt != 0);
 
-       if (domain->mode != PAGE_MODE_NONE)
-               free_pagetable(domain);
+       if (!dom)
+               return;
+
+       switch (dom->type) {
+       case IOMMU_DOMAIN_DMA:
+               dma_dom = domain->priv;
+               dma_ops_domain_free(dma_dom);
+               break;
+       default:
+               if (domain->mode != PAGE_MODE_NONE)
+                       free_pagetable(domain);
 
-       if (domain->flags & PD_IOMMUV2_MASK)
-               free_gcr3_table(domain);
+               if (domain->flags & PD_IOMMUV2_MASK)
+                       free_gcr3_table(domain);
 
-       protection_domain_free(domain);
+               protection_domain_free(domain);
+               break;
+       }
 }
 
 static void amd_iommu_detach_device(struct iommu_domain *dom,
index 8487987458a1a7d10b78693b629b93c6824468e6..00df3832faab5223acdaaf1a7851c53621d73b6b 100644 (file)
@@ -870,7 +870,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
         * We may have concurrent producers, so we need to be careful
         * not to touch any of the shadow cmdq state.
         */
-       queue_read(cmd, Q_ENT(q, idx), q->ent_dwords);
+       queue_read(cmd, Q_ENT(q, cons), q->ent_dwords);
        dev_err(smmu->dev, "skipping command in error state:\n");
        for (i = 0; i < ARRAY_SIZE(cmd); ++i)
                dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]);
@@ -881,7 +881,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
                return;
        }
 
-       queue_write(cmd, Q_ENT(q, idx), q->ent_dwords);
+       queue_write(Q_ENT(q, cons), cmd, q->ent_dwords);
 }
 
 static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
@@ -1025,6 +1025,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
                case STRTAB_STE_0_CFG_S2_TRANS:
                        ste_live = true;
                        break;
+               case STRTAB_STE_0_CFG_ABORT:
+                       if (disable_bypass)
+                               break;
                default:
                        BUG(); /* STE corruption */
                }
index 58f2fe687a24ddd29ac6d786862eefc33098d795..347a3c17f73a6ff9ed5acde668c9fb5df1b3a5cb 100644 (file)
@@ -68,7 +68,8 @@ void iommu_put_dma_cookie(struct iommu_domain *domain)
        if (!iovad)
                return;
 
-       put_iova_domain(iovad);
+       if (iovad->granule)
+               put_iova_domain(iovad);
        kfree(iovad);
        domain->iova_cookie = NULL;
 }
index 3821c4786662a4841f9e83c33d6bd7f70cf6d53d..565bb2c140ed9e15e34cf11f7bac5d789b7b0bfb 100644 (file)
@@ -1858,10 +1858,11 @@ static int dmar_hp_remove_drhd(struct acpi_dmar_header *header, void *arg)
        /*
         * All PCI devices managed by this unit should have been destroyed.
         */
-       if (!dmaru->include_all && dmaru->devices && dmaru->devices_cnt)
+       if (!dmaru->include_all && dmaru->devices && dmaru->devices_cnt) {
                for_each_active_dev_scope(dmaru->devices,
                                          dmaru->devices_cnt, i, dev)
                        return -EBUSY;
+       }
 
        ret = dmar_ir_hotplug(dmaru, false);
        if (ret == 0)
index 97c41b8ab5d980667667bde15ad1d16105278b65..29a31eb9ace3ed2c1369fcd6f1284a440474ca32 100644 (file)
@@ -647,6 +647,7 @@ static struct platform_driver exynos_sysmmu_driver __refdata = {
                .name           = "exynos-sysmmu",
                .of_match_table = sysmmu_of_match,
                .pm             = &sysmmu_pm_ops,
+               .suppress_bind_attrs = true,
        }
 };
 
index 6763a4dfed94ee4430b059e7b0742f383086dade..b7f852d824a3126f5a35233b2c9c71fab9c60265 100644 (file)
@@ -2032,7 +2032,7 @@ out_unlock:
        spin_unlock(&iommu->lock);
        spin_unlock_irqrestore(&device_domain_lock, flags);
 
-       return 0;
+       return ret;
 }
 
 struct domain_context_mapping_data {
@@ -4182,10 +4182,11 @@ int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg)
        if (!atsru)
                return 0;
 
-       if (!atsru->include_all && atsru->devices && atsru->devices_cnt)
+       if (!atsru->include_all && atsru->devices && atsru->devices_cnt) {
                for_each_active_dev_scope(atsru->devices, atsru->devices_cnt,
                                          i, dev)
                        return -EBUSY;
+       }
 
        return 0;
 }
index 8a0c7f28819841a83e1afb0e3eccf71d4aa287a7..981c3959da59431a776fa45faab5fae6929c93e3 100644 (file)
@@ -176,6 +176,7 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
 {
        struct irq_domain_chip_generic *dgc = d->gc;
        struct irq_chip_generic *gc;
+       unsigned long flags;
        unsigned smr;
        int idx;
        int ret;
@@ -194,12 +195,12 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
 
        gc = dgc->gc[idx];
 
-       irq_gc_lock(gc);
+       irq_gc_lock_irqsave(gc, flags);
        smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
        ret = aic_common_set_priority(intspec[2], &smr);
        if (!ret)
                irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
-       irq_gc_unlock(gc);
+       irq_gc_unlock_irqrestore(gc, flags);
 
        return ret;
 }
index 62bb840c613f2a660966333f858426af5ab3d93e..7dee71bde3504cced7b64285bf517994deb76425 100644 (file)
@@ -258,6 +258,7 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
                                 unsigned int *out_type)
 {
        struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0);
+       unsigned long flags;
        unsigned smr;
        int ret;
 
@@ -269,13 +270,13 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
        if (ret)
                return ret;
 
-       irq_gc_lock(bgc);
+       irq_gc_lock_irqsave(bgc, flags);
        irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR);
        smr = irq_reg_readl(bgc, AT91_AIC5_SMR);
        ret = aic_common_set_priority(intspec[2], &smr);
        if (!ret)
                irq_reg_writel(bgc, intspec[2] | smr, AT91_AIC5_SMR);
-       irq_gc_unlock(bgc);
+       irq_gc_unlock_irqrestore(bgc, flags);
 
        return ret;
 }
index a159529f9d53d14f3d8989eedd9d0ff7f9f7b8b3..c5f1757ac61d6705efd61a4e37e23f49bddd782f 100644 (file)
@@ -41,6 +41,7 @@
 
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING          (1ULL << 0)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375      (1ULL << 1)
+#define ITS_FLAGS_WORKAROUND_CAVIUM_23144      (1ULL << 2)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
 
@@ -71,6 +72,7 @@ struct its_node {
        struct list_head        its_device_list;
        u64                     flags;
        u32                     ite_size;
+       int                     numa_node;
 };
 
 #define ITS_ITT_ALIGN          SZ_256
@@ -600,11 +602,23 @@ static void its_unmask_irq(struct irq_data *d)
 static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                            bool force)
 {
-       unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
+       unsigned int cpu;
+       const struct cpumask *cpu_mask = cpu_online_mask;
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        struct its_collection *target_col;
        u32 id = its_get_event_id(d);
 
+       /* lpi cannot be routed to a redistributor that is on a foreign node */
+       if (its_dev->its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
+               if (its_dev->its->numa_node >= 0) {
+                       cpu_mask = cpumask_of_node(its_dev->its->numa_node);
+                       if (!cpumask_intersects(mask_val, cpu_mask))
+                               return -EINVAL;
+               }
+       }
+
+       cpu = cpumask_any_and(mask_val, cpu_mask);
+
        if (cpu >= nr_cpu_ids)
                return -EINVAL;
 
@@ -1081,6 +1095,16 @@ static void its_cpu_init_collection(void)
        list_for_each_entry(its, &its_nodes, entry) {
                u64 target;
 
+               /* avoid cross node collections and its mapping */
+               if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
+                       struct device_node *cpu_node;
+
+                       cpu_node = of_get_cpu_node(cpu, NULL);
+                       if (its->numa_node != NUMA_NO_NODE &&
+                               its->numa_node != of_node_to_nid(cpu_node))
+                               continue;
+               }
+
                /*
                 * We now have to bind each collection to its target
                 * redistributor.
@@ -1308,9 +1332,14 @@ static void its_irq_domain_activate(struct irq_domain *domain,
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        u32 event = its_get_event_id(d);
+       const struct cpumask *cpu_mask = cpu_online_mask;
+
+       /* get the cpu_mask of local node */
+       if (its_dev->its->numa_node >= 0)
+               cpu_mask = cpumask_of_node(its_dev->its->numa_node);
 
        /* Bind the LPI to the first possible CPU */
-       its_dev->event_map.col_map[event] = cpumask_first(cpu_online_mask);
+       its_dev->event_map.col_map[event] = cpumask_first(cpu_mask);
 
        /* Map the GIC IRQ and event to the device */
        its_send_mapvi(its_dev, d->hwirq, event);
@@ -1400,6 +1429,13 @@ static void __maybe_unused its_enable_quirk_cavium_22375(void *data)
        its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375;
 }
 
+static void __maybe_unused its_enable_quirk_cavium_23144(void *data)
+{
+       struct its_node *its = data;
+
+       its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_23144;
+}
+
 static const struct gic_quirk its_quirks[] = {
 #ifdef CONFIG_CAVIUM_ERRATUM_22375
        {
@@ -1408,6 +1444,14 @@ static const struct gic_quirk its_quirks[] = {
                .mask   = 0xffff0fff,
                .init   = its_enable_quirk_cavium_22375,
        },
+#endif
+#ifdef CONFIG_CAVIUM_ERRATUM_23144
+       {
+               .desc   = "ITS: Cavium erratum 23144",
+               .iidr   = 0xa100034c,   /* ThunderX pass 1.x */
+               .mask   = 0xffff0fff,
+               .init   = its_enable_quirk_cavium_23144,
+       },
 #endif
        {
        }
@@ -1470,6 +1514,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
        its->base = its_base;
        its->phys_base = res.start;
        its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
+       its->numa_node = of_node_to_nid(node);
 
        its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
        if (!its->cmd_base) {
index 2d39257beffba4413d23532235b3929913efb7dd..dff17aef68a24026193f9cfa9e43cc158f184faa 100644 (file)
@@ -145,7 +145,7 @@ static void gic_enable_redist(bool enable)
                        return; /* No PM support in this redistributor */
        }
 
-       while (count--) {
+       while (--count) {
                val = readl_relaxed(rbase + GICR_WAKER);
                if (enable ^ (val & GICR_WAKER_ChildrenAsleep))
                        break;
@@ -547,7 +547,7 @@ static struct notifier_block gic_cpu_notifier = {
 static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
                                   unsigned long cluster_id)
 {
-       int cpu = *base_cpu;
+       int next_cpu, cpu = *base_cpu;
        unsigned long mpidr = cpu_logical_map(cpu);
        u16 tlist = 0;
 
@@ -561,9 +561,10 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
 
                tlist |= 1 << (mpidr & 0xf);
 
-               cpu = cpumask_next(cpu, mask);
-               if (cpu >= nr_cpu_ids)
+               next_cpu = cpumask_next(cpu, mask);
+               if (next_cpu >= nr_cpu_ids)
                        goto out;
+               cpu = next_cpu;
 
                mpidr = cpu_logical_map(cpu);
 
index a54b339951a3e695bfa68e96fb6eaf2e3e451c62..2a96ff6923f02c331190581da6c3be8b07797566 100644 (file)
@@ -89,6 +89,7 @@ static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
 
                list_move_tail(&blk->list, &lun->bb_list);
                lun->vlun.nr_bad_blocks++;
+               lun->vlun.nr_free_blocks--;
        }
 
        return 0;
@@ -345,7 +346,7 @@ static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
 static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
 {
        if (!dev->ops->submit_io)
-               return 0;
+               return -ENODEV;
 
        /* Convert address space */
        gennvm_generic_to_addr_mode(dev, rqd);
index 134e4faba48259434db7d55d446f40f3deb206b9..596347f345db83c34be61aa8fea96e21142071ac 100644 (file)
@@ -287,6 +287,10 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk)
        }
 
        page = mempool_alloc(rrpc->page_pool, GFP_NOIO);
+       if (!page) {
+               bio_put(bio);
+               return -ENOMEM;
+       }
 
        while ((slot = find_first_zero_bit(rblk->invalid_pages,
                                            nr_pgs_per_blk)) < nr_pgs_per_blk) {
@@ -427,7 +431,7 @@ static void rrpc_lun_gc(struct work_struct *work)
        if (nr_blocks_need < rrpc->nr_luns)
                nr_blocks_need = rrpc->nr_luns;
 
-       spin_lock(&lun->lock);
+       spin_lock(&rlun->lock);
        while (nr_blocks_need > lun->nr_free_blocks &&
                                        !list_empty(&rlun->prio_list)) {
                struct rrpc_block *rblock = block_prio_find_max(rlun);
@@ -436,16 +440,16 @@ static void rrpc_lun_gc(struct work_struct *work)
                if (!rblock->nr_invalid_pages)
                        break;
 
+               gcb = mempool_alloc(rrpc->gcb_pool, GFP_ATOMIC);
+               if (!gcb)
+                       break;
+
                list_del_init(&rblock->prio);
 
                BUG_ON(!block_is_full(rrpc, rblock));
 
                pr_debug("rrpc: selected block '%lu' for GC\n", block->id);
 
-               gcb = mempool_alloc(rrpc->gcb_pool, GFP_ATOMIC);
-               if (!gcb)
-                       break;
-
                gcb->rrpc = rrpc;
                gcb->rblk = rblock;
                INIT_WORK(&gcb->ws_gc, rrpc_block_gc);
@@ -454,7 +458,7 @@ static void rrpc_lun_gc(struct work_struct *work)
 
                nr_blocks_need--;
        }
-       spin_unlock(&lun->lock);
+       spin_unlock(&rlun->lock);
 
        /* TODO: Hint that request queue can be started again */
 }
@@ -650,11 +654,12 @@ static int rrpc_end_io(struct nvm_rq *rqd, int error)
        if (bio_data_dir(rqd->bio) == WRITE)
                rrpc_end_io_write(rrpc, rrqd, laddr, npages);
 
+       bio_put(rqd->bio);
+
        if (rrqd->flags & NVM_IOTYPE_GC)
                return 0;
 
        rrpc_unlock_rq(rrpc, rqd);
-       bio_put(rqd->bio);
 
        if (npages > 1)
                nvm_dev_dma_free(rrpc->dev, rqd->ppa_list, rqd->dma_ppa_list);
@@ -841,6 +846,13 @@ static int rrpc_submit_io(struct rrpc *rrpc, struct bio *bio,
        err = nvm_submit_io(rrpc->dev, rqd);
        if (err) {
                pr_err("rrpc: I/O submission failed: %d\n", err);
+               bio_put(bio);
+               if (!(flags & NVM_IOTYPE_GC)) {
+                       rrpc_unlock_rq(rrpc, rqd);
+                       if (rqd->nr_pages > 1)
+                               nvm_dev_dma_free(rrpc->dev,
+                       rqd->ppa_list, rqd->dma_ppa_list);
+               }
                return NVM_IO_ERR;
        }
 
index d8b0ab6f3753c7ffc1e4655c1da26056f5746430..6035794bc1f208809aa0175685a3a15f58fc2c7d 100644 (file)
@@ -500,4 +500,21 @@ config DM_LOG_WRITES
 
          If unsure, say N.
 
+config DM_ANDROID_VERITY
+       tristate "Android verity target support"
+       depends on DM_VERITY
+       depends on X509_CERTIFICATE_PARSER
+       depends on SYSTEM_TRUSTED_KEYRING
+       depends on PUBLIC_KEY_ALGO_RSA
+       depends on KEYS
+       depends on ASYMMETRIC_KEY_TYPE
+       depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+       depends on MD_LINEAR
+       ---help---
+         This device-mapper target is virtually a VERITY target. This
+         target is setup by reading the metadata contents piggybacked
+         to the actual data blocks in the block device. The signature
+         of the metadata contents are verified against the key included
+         in the system keyring. Upon success, the underlying verity
+         target is setup.
 endif # MD
index 62a65764e8e0f093cede342f0eb4b7d0aec2eb4e..32b5d0a90d603ee51121e257ef2e3ff1b9c85e13 100644 (file)
@@ -60,6 +60,7 @@ obj-$(CONFIG_DM_CACHE_SMQ)    += dm-cache-smq.o
 obj-$(CONFIG_DM_CACHE_CLEANER) += dm-cache-cleaner.o
 obj-$(CONFIG_DM_ERA)           += dm-era.o
 obj-$(CONFIG_DM_LOG_WRITES)    += dm-log-writes.o
+obj-$(CONFIG_DM_ANDROID_VERITY) += dm-android-verity.o
 
 ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs                    += dm-uevent.o
index a296425a7270df87e1fc9cdd403668dd5bb82deb..3d5c0ba131818c8b7238c7d57f1c1f8eb252c064 100644 (file)
@@ -1818,7 +1818,7 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
        free = roundup_pow_of_two(ca->sb.nbuckets) >> 10;
 
        if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) ||
-           !init_fifo(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
+           !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
            !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
            !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
            !init_fifo(&ca->free_inc,   free << 2, GFP_KERNEL) ||
diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c
new file mode 100644 (file)
index 0000000..bb6c128
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/device-mapper.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/key.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/of.h>
+#include <linux/reboot.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <crypto/hash.h>
+#include <crypto/public_key.h>
+#include <crypto/sha.h>
+#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
+
+#include "dm-verity.h"
+#include "dm-android-verity.h"
+
+static char verifiedbootstate[VERITY_COMMANDLINE_PARAM_LENGTH];
+static char veritymode[VERITY_COMMANDLINE_PARAM_LENGTH];
+static char veritykeyid[VERITY_DEFAULT_KEY_ID_LENGTH];
+static char buildvariant[BUILD_VARIANT];
+
+static bool target_added;
+static bool verity_enabled = true;
+struct dentry *debug_dir;
+static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv);
+
+static struct target_type android_verity_target = {
+       .name                   = "android-verity",
+       .version                = {1, 0, 0},
+       .module                 = THIS_MODULE,
+       .ctr                    = android_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 verified_boot_state_param(char *line)
+{
+       strlcpy(verifiedbootstate, line, sizeof(verifiedbootstate));
+       return 1;
+}
+
+__setup("androidboot.verifiedbootstate=", verified_boot_state_param);
+
+static int __init verity_mode_param(char *line)
+{
+       strlcpy(veritymode, line, sizeof(veritymode));
+       return 1;
+}
+
+__setup("androidboot.veritymode=", verity_mode_param);
+
+static int __init verity_keyid_param(char *line)
+{
+       strlcpy(veritykeyid, line, sizeof(veritykeyid));
+       return 1;
+}
+
+__setup("veritykeyid=", verity_keyid_param);
+
+static int __init verity_buildvariant(char *line)
+{
+       strlcpy(buildvariant, line, sizeof(buildvariant));
+       return 1;
+}
+
+__setup("buildvariant=", verity_buildvariant);
+
+static inline bool default_verity_key_id(void)
+{
+       return veritykeyid[0] != '\0';
+}
+
+static inline bool is_eng(void)
+{
+       static const char typeeng[]  = "eng";
+
+       return !strncmp(buildvariant, typeeng, sizeof(typeeng));
+}
+
+static inline bool is_userdebug(void)
+{
+       static const char typeuserdebug[]  = "userdebug";
+
+       return !strncmp(buildvariant, typeuserdebug, sizeof(typeuserdebug));
+}
+
+
+static int table_extract_mpi_array(struct public_key_signature *pks,
+                               const void *data, size_t len)
+{
+       MPI mpi = mpi_read_raw_data(data, len);
+
+       if (!mpi) {
+               DMERR("Error while allocating mpi array");
+               return -ENOMEM;
+       }
+
+       pks->mpi[0] = mpi;
+       pks->nr_mpi = 1;
+       return 0;
+}
+
+static struct public_key_signature *table_make_digest(
+                                               enum hash_algo hash,
+                                               const void *table,
+                                               unsigned long table_len)
+{
+       struct public_key_signature *pks = NULL;
+       struct crypto_shash *tfm;
+       struct shash_desc *desc;
+       size_t digest_size, desc_size;
+       int ret;
+
+       /* Allocate the hashing algorithm we're going to need and find out how
+        * big the hash operational data will be.
+        */
+       tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
+       if (IS_ERR(tfm))
+               return ERR_CAST(tfm);
+
+       desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+       digest_size = crypto_shash_digestsize(tfm);
+
+       /* We allocate the hash operational data storage on the end of out
+        * context data and the digest output buffer on the end of that.
+        */
+       ret = -ENOMEM;
+       pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
+       if (!pks)
+               goto error;
+
+       pks->pkey_hash_algo = hash;
+       pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
+       pks->digest_size = digest_size;
+
+       desc = (struct shash_desc *)(pks + 1);
+       desc->tfm = tfm;
+       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       ret = crypto_shash_init(desc);
+       if (ret < 0)
+               goto error;
+
+       ret = crypto_shash_finup(desc, table, table_len, pks->digest);
+       if (ret < 0)
+               goto error;
+
+       crypto_free_shash(tfm);
+       return pks;
+
+error:
+       kfree(pks);
+       crypto_free_shash(tfm);
+       return ERR_PTR(ret);
+}
+
+static int read_block_dev(struct bio_read *payload, struct block_device *bdev,
+               sector_t offset, int length)
+{
+       struct bio *bio;
+       int err = 0, i;
+
+       payload->number_of_pages = DIV_ROUND_UP(length, PAGE_SIZE);
+
+       bio = bio_alloc(GFP_KERNEL, payload->number_of_pages);
+       if (!bio) {
+               DMERR("Error while allocating bio");
+               return -ENOMEM;
+       }
+
+       bio->bi_bdev = bdev;
+       bio->bi_iter.bi_sector = offset;
+
+       payload->page_io = kzalloc(sizeof(struct page *) *
+               payload->number_of_pages, GFP_KERNEL);
+       if (!payload->page_io) {
+               DMERR("page_io array alloc failed");
+               err = -ENOMEM;
+               goto free_bio;
+       }
+
+       for (i = 0; i < payload->number_of_pages; i++) {
+               payload->page_io[i] = alloc_page(GFP_KERNEL);
+               if (!payload->page_io[i]) {
+                       DMERR("alloc_page failed");
+                       err = -ENOMEM;
+                       goto free_pages;
+               }
+               if (!bio_add_page(bio, payload->page_io[i], PAGE_SIZE, 0)) {
+                       DMERR("bio_add_page error");
+                       err = -EIO;
+                       goto free_pages;
+               }
+       }
+
+       if (!submit_bio_wait(READ, bio))
+               /* success */
+               goto free_bio;
+       DMERR("bio read failed");
+       err = -EIO;
+
+free_pages:
+       for (i = 0; i < payload->number_of_pages; i++)
+               if (payload->page_io[i])
+                       __free_page(payload->page_io[i]);
+       kfree(payload->page_io);
+free_bio:
+       bio_put(bio);
+       return err;
+}
+
+static inline u64 fec_div_round_up(u64 x, u64 y)
+{
+       u64 remainder;
+
+       return div64_u64_rem(x, y, &remainder) +
+               (remainder > 0 ? 1 : 0);
+}
+
+static inline void populate_fec_metadata(struct fec_header *header,
+                               struct fec_ecc_metadata *ecc)
+{
+       ecc->blocks = fec_div_round_up(le64_to_cpu(header->inp_size),
+                       FEC_BLOCK_SIZE);
+       ecc->roots = le32_to_cpu(header->roots);
+       ecc->start = le64_to_cpu(header->inp_size);
+}
+
+static inline int validate_fec_header(struct fec_header *header, u64 offset)
+{
+       /* move offset to make the sanity check work for backup header
+        * as well. */
+       offset -= offset % FEC_BLOCK_SIZE;
+       if (le32_to_cpu(header->magic) != FEC_MAGIC ||
+               le32_to_cpu(header->version) != FEC_VERSION ||
+               le32_to_cpu(header->size) != sizeof(struct fec_header) ||
+               le32_to_cpu(header->roots) == 0 ||
+               le32_to_cpu(header->roots) >= FEC_RSM)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int extract_fec_header(dev_t dev, struct fec_header *fec,
+                               struct fec_ecc_metadata *ecc)
+{
+       u64 device_size;
+       struct bio_read payload;
+       int i, err = 0;
+       struct block_device *bdev;
+
+       bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
+
+       if (IS_ERR_OR_NULL(bdev)) {
+               DMERR("bdev get error");
+               return PTR_ERR(bdev);
+       }
+
+       device_size = i_size_read(bdev->bd_inode);
+
+       /* fec metadata size is a power of 2 and PAGE_SIZE
+        * is a power of 2 as well.
+        */
+       BUG_ON(FEC_BLOCK_SIZE > PAGE_SIZE);
+       /* 512 byte sector alignment */
+       BUG_ON(((device_size - FEC_BLOCK_SIZE) % (1 << SECTOR_SHIFT)) != 0);
+
+       err = read_block_dev(&payload, bdev, (device_size -
+               FEC_BLOCK_SIZE) / (1 << SECTOR_SHIFT), FEC_BLOCK_SIZE);
+       if (err) {
+               DMERR("Error while reading verity metadata");
+               goto error;
+       }
+
+       BUG_ON(sizeof(struct fec_header) > PAGE_SIZE);
+       memcpy(fec, page_address(payload.page_io[0]),
+                       sizeof(*fec));
+
+       ecc->valid = true;
+       if (validate_fec_header(fec, device_size - FEC_BLOCK_SIZE)) {
+               /* Try the backup header */
+               memcpy(fec, page_address(payload.page_io[0]) + FEC_BLOCK_SIZE
+                       - sizeof(*fec) ,
+                       sizeof(*fec));
+               if (validate_fec_header(fec, device_size -
+                       sizeof(struct fec_header)))
+                       ecc->valid = false;
+       }
+
+       if (ecc->valid)
+               populate_fec_metadata(fec, ecc);
+
+       for (i = 0; i < payload.number_of_pages; i++)
+               __free_page(payload.page_io[i]);
+       kfree(payload.page_io);
+
+error:
+       blkdev_put(bdev, FMODE_READ);
+       return err;
+}
+static void find_metadata_offset(struct fec_header *fec,
+               struct block_device *bdev, u64 *metadata_offset)
+{
+       u64 device_size;
+
+       device_size = i_size_read(bdev->bd_inode);
+
+       if (le32_to_cpu(fec->magic) == FEC_MAGIC)
+               *metadata_offset = le64_to_cpu(fec->inp_size) -
+                                       VERITY_METADATA_SIZE;
+       else
+               *metadata_offset = device_size - VERITY_METADATA_SIZE;
+}
+
+static int find_size(dev_t dev, u64 *device_size)
+{
+       struct block_device *bdev;
+
+       bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
+       if (IS_ERR_OR_NULL(bdev)) {
+               DMERR("blkdev_get_by_dev failed");
+               return PTR_ERR(bdev);
+       }
+
+       *device_size = i_size_read(bdev->bd_inode);
+       *device_size >>= SECTOR_SHIFT;
+
+       DMINFO("blkdev size in sectors: %llu", *device_size);
+       blkdev_put(bdev, FMODE_READ);
+       return 0;
+}
+
+static int verify_header(struct android_metadata_header *header)
+{
+       int retval = -EINVAL;
+
+       if (is_userdebug() && le32_to_cpu(header->magic_number) ==
+                       VERITY_METADATA_MAGIC_DISABLE)
+               return VERITY_STATE_DISABLE;
+
+       if (!(le32_to_cpu(header->magic_number) ==
+                       VERITY_METADATA_MAGIC_NUMBER) ||
+                       (le32_to_cpu(header->magic_number) ==
+                       VERITY_METADATA_MAGIC_DISABLE)) {
+               DMERR("Incorrect magic number");
+               return retval;
+       }
+
+       if (le32_to_cpu(header->protocol_version) !=
+                       VERITY_METADATA_VERSION) {
+               DMERR("Unsupported version %u",
+                       le32_to_cpu(header->protocol_version));
+               return retval;
+       }
+
+       return 0;
+}
+
+static int extract_metadata(dev_t dev, struct fec_header *fec,
+                               struct android_metadata **metadata,
+                               bool *verity_enabled)
+{
+       struct block_device *bdev;
+       struct android_metadata_header *header;
+       int i;
+       u32 table_length, copy_length, offset;
+       u64 metadata_offset;
+       struct bio_read payload;
+       int err = 0;
+
+       bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
+
+       if (IS_ERR_OR_NULL(bdev)) {
+               DMERR("blkdev_get_by_dev failed");
+               return -ENODEV;
+       }
+
+       find_metadata_offset(fec, bdev, &metadata_offset);
+
+       /* Verity metadata size is a power of 2 and PAGE_SIZE
+        * is a power of 2 as well.
+        * PAGE_SIZE is also a multiple of 512 bytes.
+       */
+       if (VERITY_METADATA_SIZE > PAGE_SIZE)
+               BUG_ON(VERITY_METADATA_SIZE % PAGE_SIZE != 0);
+       /* 512 byte sector alignment */
+       BUG_ON(metadata_offset % (1 << SECTOR_SHIFT) != 0);
+
+       err = read_block_dev(&payload, bdev, metadata_offset /
+               (1 << SECTOR_SHIFT), VERITY_METADATA_SIZE);
+       if (err) {
+               DMERR("Error while reading verity metadata");
+               goto blkdev_release;
+       }
+
+       header = kzalloc(sizeof(*header), GFP_KERNEL);
+       if (!header) {
+               DMERR("kzalloc failed for header");
+               err = -ENOMEM;
+               goto free_payload;
+       }
+
+       memcpy(header, page_address(payload.page_io[0]),
+               sizeof(*header));
+
+       DMINFO("bio magic_number:%u protocol_version:%d table_length:%u",
+               le32_to_cpu(header->magic_number),
+               le32_to_cpu(header->protocol_version),
+               le32_to_cpu(header->table_length));
+
+       err = verify_header(header);
+
+       if (err == VERITY_STATE_DISABLE) {
+               DMERR("Mounting root with verity disabled");
+               *verity_enabled = false;
+               /* we would still have to read the metadata to figure out
+                * the data blocks size. Or may be could map the entire
+                * partition similar to mounting the device.
+                *
+                * Reset error as well as the verity_enabled flag is changed.
+                */
+               err = 0;
+       } else if (err)
+               goto free_header;
+
+       *metadata = kzalloc(sizeof(**metadata), GFP_KERNEL);
+       if (!*metadata) {
+               DMERR("kzalloc for metadata failed");
+               err = -ENOMEM;
+               goto free_header;
+       }
+
+       (*metadata)->header = header;
+       table_length = le32_to_cpu(header->table_length);
+
+       if (table_length == 0 ||
+               table_length > (VERITY_METADATA_SIZE -
+                       sizeof(struct android_metadata_header))) {
+               DMERR("table_length too long");
+               err = -EINVAL;
+               goto free_metadata;
+       }
+
+       (*metadata)->verity_table = kzalloc(table_length + 1, GFP_KERNEL);
+
+       if (!(*metadata)->verity_table) {
+               DMERR("kzalloc verity_table failed");
+               err = -ENOMEM;
+               goto free_metadata;
+       }
+
+       if (sizeof(struct android_metadata_header) +
+                       table_length <= PAGE_SIZE) {
+               memcpy((*metadata)->verity_table,
+                       page_address(payload.page_io[0])
+                       + sizeof(struct android_metadata_header),
+                       table_length);
+       } else {
+               copy_length = PAGE_SIZE -
+                       sizeof(struct android_metadata_header);
+               memcpy((*metadata)->verity_table,
+                       page_address(payload.page_io[0])
+                       + sizeof(struct android_metadata_header),
+                       copy_length);
+               table_length -= copy_length;
+               offset = copy_length;
+               i = 1;
+               while (table_length != 0) {
+                       if (table_length > PAGE_SIZE) {
+                               memcpy((*metadata)->verity_table + offset,
+                                       page_address(payload.page_io[i]),
+                                       PAGE_SIZE);
+                               offset += PAGE_SIZE;
+                               table_length -= PAGE_SIZE;
+                       } else {
+                               memcpy((*metadata)->verity_table + offset,
+                                       page_address(payload.page_io[i]),
+                                       table_length);
+                               table_length = 0;
+                       }
+                       i++;
+               }
+       }
+       (*metadata)->verity_table[table_length] = '\0';
+
+       DMINFO("verity_table: %s", (*metadata)->verity_table);
+       goto free_payload;
+
+free_metadata:
+       kfree(*metadata);
+free_header:
+       kfree(header);
+free_payload:
+       for (i = 0; i < payload.number_of_pages; i++)
+               if (payload.page_io[i])
+                       __free_page(payload.page_io[i]);
+       kfree(payload.page_io);
+blkdev_release:
+       blkdev_put(bdev, FMODE_READ);
+       return err;
+}
+
+/* helper functions to extract properties from dts */
+const char *find_dt_value(const char *name)
+{
+       struct device_node *firmware;
+       const char *value;
+
+       firmware = of_find_node_by_path("/firmware/android");
+       if (!firmware)
+               return NULL;
+       value = of_get_property(firmware, name, NULL);
+       of_node_put(firmware);
+
+       return value;
+}
+
+static int verity_mode(void)
+{
+       static const char enforcing[] = "enforcing";
+       static const char verified_mode_prop[] = "veritymode";
+       const char *value;
+
+       value = find_dt_value(verified_mode_prop);
+       if (!value)
+               value = veritymode;
+       if (!strncmp(value, enforcing, sizeof(enforcing) - 1))
+               return DM_VERITY_MODE_RESTART;
+
+       return DM_VERITY_MODE_EIO;
+}
+
+static int verify_verity_signature(char *key_id,
+               struct android_metadata *metadata)
+{
+       key_ref_t key_ref;
+       struct key *key;
+       struct public_key_signature *pks = NULL;
+       int retval = -EINVAL;
+
+       key_ref = keyring_search(make_key_ref(system_trusted_keyring, 1),
+               &key_type_asymmetric, key_id);
+
+       if (IS_ERR(key_ref)) {
+               DMERR("keyring: key not found");
+               return -ENOKEY;
+       }
+
+       key = key_ref_to_ptr(key_ref);
+
+       pks = table_make_digest(HASH_ALGO_SHA256,
+                       (const void *)metadata->verity_table,
+                       le32_to_cpu(metadata->header->table_length));
+
+       if (IS_ERR(pks)) {
+               DMERR("hashing failed");
+               goto error;
+       }
+
+       retval = table_extract_mpi_array(pks, &metadata->header->signature[0],
+                               RSANUMBYTES);
+       if (retval < 0) {
+               DMERR("Error extracting mpi %d", retval);
+               goto error;
+       }
+
+       retval = verify_signature(key, pks);
+       mpi_free(pks->rsa.s);
+error:
+       kfree(pks);
+       key_put(key);
+
+       return retval;
+}
+
+static void handle_error(void)
+{
+       int mode = verity_mode();
+       if (mode == DM_VERITY_MODE_RESTART) {
+               DMERR("triggering restart");
+               kernel_restart("dm-verity device corrupted");
+       } else {
+               DMERR("Mounting verity root failed");
+       }
+}
+
+static inline bool test_mult_overflow(sector_t a, u32 b)
+{
+       sector_t r = (sector_t)~0ULL;
+
+       sector_div(r, b);
+       return a > r;
+}
+
+static int add_as_linear_device(struct dm_target *ti, char *dev)
+{
+       /*Move to linear mapping defines*/
+       char *linear_table_args[DM_LINEAR_ARGS] = {dev,
+                                       DM_LINEAR_TARGET_OFFSET};
+       int err = 0;
+
+       android_verity_target.dtr = dm_linear_dtr,
+       android_verity_target.map = dm_linear_map,
+       android_verity_target.status = dm_linear_status,
+       android_verity_target.prepare_ioctl = dm_linear_prepare_ioctl,
+       android_verity_target.iterate_devices = dm_linear_iterate_devices,
+       android_verity_target.io_hints = NULL;
+
+       err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args);
+
+       if (!err) {
+               DMINFO("Added android-verity as a linear target");
+               target_added = true;
+       } else
+               DMERR("Failed to add android-verity as linear target");
+
+       return err;
+}
+
+/*
+ * Target parameters:
+ *     <key id>        Key id of the public key in the system keyring.
+ *                     Verity metadata's signature would be verified against
+ *                     this. If the key id contains spaces, replace them
+ *                     with '#'.
+ *     <block device>  The block device for which dm-verity is being setup.
+ */
+static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+       dev_t uninitialized_var(dev);
+       struct android_metadata *metadata = NULL;
+       int err = 0, i, mode;
+       char *key_id, *table_ptr, dummy, *target_device,
+       *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
+       /* One for specifying number of opt args and one for mode */
+       sector_t data_sectors;
+       u32 data_block_size;
+       unsigned int no_of_args = VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS;
+       struct fec_header uninitialized_var(fec);
+       struct fec_ecc_metadata uninitialized_var(ecc);
+       char buf[FEC_ARG_LENGTH], *buf_ptr;
+       unsigned long long tmpll;
+       u64  uninitialized_var(device_size);
+
+       if (argc == 1) {
+               /* Use the default keyid */
+               if (default_verity_key_id())
+                       key_id = veritykeyid;
+               else if (!is_eng()) {
+                       DMERR("veritykeyid= is not set");
+                       handle_error();
+                       return -EINVAL;
+               }
+       } else if (argc == 2)
+               key_id = argv[1];
+       else {
+               DMERR("Incorrect number of arguments");
+               handle_error();
+               return -EINVAL;
+       }
+
+       target_device = argv[0];
+
+       dev = name_to_dev_t(target_device);
+       if (!dev) {
+               DMERR("no dev found for %s", target_device);
+               handle_error();
+               return -EINVAL;
+       }
+
+       if (is_eng()) {
+               err = find_size(dev, &device_size);
+               if (err) {
+                       DMERR("error finding bdev size");
+                       handle_error();
+                       return err;
+               }
+
+               ti->len = device_size;
+               err = add_as_linear_device(ti, target_device);
+               if (err) {
+                       handle_error();
+                       return err;
+               }
+               verity_enabled = false;
+               return 0;
+       }
+
+       strreplace(key_id, '#', ' ');
+
+       DMINFO("key:%s dev:%s", key_id, target_device);
+
+       if (extract_fec_header(dev, &fec, &ecc)) {
+               DMERR("Error while extracting fec header");
+               handle_error();
+               return -EINVAL;
+       }
+
+       err = extract_metadata(dev, &fec, &metadata, &verity_enabled);
+
+       if (err) {
+               DMERR("Error while extracting metadata");
+               handle_error();
+               goto free_metadata;
+       }
+
+       if (verity_enabled) {
+               err = verify_verity_signature(key_id, metadata);
+
+               if (err) {
+                       DMERR("Signature verification failed");
+                       handle_error();
+                       goto free_metadata;
+               } else
+                       DMINFO("Signature verification success");
+       }
+
+       table_ptr = metadata->verity_table;
+
+       for (i = 0; i < VERITY_TABLE_ARGS; i++) {
+               verity_table_args[i] = strsep(&table_ptr, " ");
+               if (verity_table_args[i] == NULL)
+                       break;
+       }
+
+       if (i != VERITY_TABLE_ARGS) {
+               DMERR("Verity table not in the expected format");
+               err = -EINVAL;
+               handle_error();
+               goto free_metadata;
+       }
+
+       if (sscanf(verity_table_args[5], "%llu%c", &tmpll, &dummy)
+                                                       != 1) {
+               DMERR("Verity table not in the expected format");
+               handle_error();
+               err = -EINVAL;
+               goto free_metadata;
+       }
+
+       if (tmpll > ULONG_MAX) {
+               DMERR("<num_data_blocks> too large. Forgot to turn on CONFIG_LBDAF?");
+               handle_error();
+               err = -EINVAL;
+               goto free_metadata;
+       }
+
+       data_sectors = tmpll;
+
+       if (sscanf(verity_table_args[3], "%u%c", &data_block_size, &dummy)
+                                                               != 1) {
+               DMERR("Verity table not in the expected format");
+               handle_error();
+               err = -EINVAL;
+               goto free_metadata;
+       }
+
+       if (test_mult_overflow(data_sectors, data_block_size >>
+                                                       SECTOR_SHIFT)) {
+               DMERR("data_sectors too large");
+               handle_error();
+               err = -EOVERFLOW;
+               goto free_metadata;
+       }
+
+       data_sectors *= data_block_size >> SECTOR_SHIFT;
+       DMINFO("Data sectors %llu", (unsigned long long)data_sectors);
+
+       /* update target length */
+       ti->len = data_sectors;
+
+       /* Setup linear target and free */
+       if (!verity_enabled) {
+               err = add_as_linear_device(ti, target_device);
+               goto free_metadata;
+       }
+
+       /*substitute data_dev and hash_dev*/
+       verity_table_args[1] = target_device;
+       verity_table_args[2] = target_device;
+
+       mode = verity_mode();
+
+       if (ecc.valid && IS_BUILTIN(CONFIG_DM_VERITY_FEC)) {
+               if (mode) {
+                       err = snprintf(buf, FEC_ARG_LENGTH,
+                               "%u %s " VERITY_TABLE_OPT_FEC_FORMAT,
+                               1 + VERITY_TABLE_OPT_FEC_ARGS,
+                               mode == DM_VERITY_MODE_RESTART ?
+                                       VERITY_TABLE_OPT_RESTART :
+                                       VERITY_TABLE_OPT_LOGGING,
+                               target_device,
+                               ecc.start / FEC_BLOCK_SIZE, ecc.blocks,
+                               ecc.roots);
+               } else {
+                       err = snprintf(buf, FEC_ARG_LENGTH,
+                               "%u " VERITY_TABLE_OPT_FEC_FORMAT,
+                               VERITY_TABLE_OPT_FEC_ARGS, target_device,
+                               ecc.start / FEC_BLOCK_SIZE, ecc.blocks,
+                               ecc.roots);
+               }
+       } else if (mode) {
+               err = snprintf(buf, FEC_ARG_LENGTH,
+                       "2 " VERITY_TABLE_OPT_IGNZERO " %s",
+                       mode == DM_VERITY_MODE_RESTART ?
+                       VERITY_TABLE_OPT_RESTART : VERITY_TABLE_OPT_LOGGING);
+       } else {
+               err = snprintf(buf, FEC_ARG_LENGTH, "1 %s",
+                                "ignore_zero_blocks");
+       }
+
+       if (err < 0 || err >= FEC_ARG_LENGTH)
+               goto free_metadata;
+
+       buf_ptr = buf;
+
+       for (i = VERITY_TABLE_ARGS; i < (VERITY_TABLE_ARGS +
+               VERITY_TABLE_OPT_FEC_ARGS + 2); i++) {
+               verity_table_args[i] = strsep(&buf_ptr, " ");
+               if (verity_table_args[i] == NULL) {
+                       no_of_args = i;
+                       break;
+               }
+       }
+
+       err = verity_ctr(ti, no_of_args, verity_table_args);
+
+       if (err)
+               DMERR("android-verity failed to mount as verity target");
+       else {
+               target_added = true;
+               DMINFO("android-verity mounted as verity target");
+       }
+
+free_metadata:
+       if (metadata) {
+               kfree(metadata->header);
+               kfree(metadata->verity_table);
+       }
+       kfree(metadata);
+       return err;
+}
+
+static int __init dm_android_verity_init(void)
+{
+       int r;
+       struct dentry *file;
+
+       r = dm_register_target(&android_verity_target);
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       /* Tracks the status of the last added target */
+       debug_dir = debugfs_create_dir("android_verity", NULL);
+
+       if (IS_ERR_OR_NULL(debug_dir)) {
+               DMERR("Cannot create android_verity debugfs directory: %ld",
+                       PTR_ERR(debug_dir));
+               goto end;
+       }
+
+       file = debugfs_create_bool("target_added", S_IRUGO, debug_dir,
+                               &target_added);
+
+       if (IS_ERR_OR_NULL(file)) {
+               DMERR("Cannot create android_verity debugfs directory: %ld",
+                       PTR_ERR(debug_dir));
+               debugfs_remove_recursive(debug_dir);
+               goto end;
+       }
+
+       file = debugfs_create_bool("verity_enabled", S_IRUGO, debug_dir,
+                               &verity_enabled);
+
+       if (IS_ERR_OR_NULL(file)) {
+               DMERR("Cannot create android_verity debugfs directory: %ld",
+                       PTR_ERR(debug_dir));
+               debugfs_remove_recursive(debug_dir);
+       }
+
+end:
+       return r;
+}
+
+static void __exit dm_android_verity_exit(void)
+{
+       if (!IS_ERR_OR_NULL(debug_dir))
+               debugfs_remove_recursive(debug_dir);
+
+       dm_unregister_target(&android_verity_target);
+}
+
+module_init(dm_android_verity_init);
+module_exit(dm_android_verity_exit);
diff --git a/drivers/md/dm-android-verity.h b/drivers/md/dm-android-verity.h
new file mode 100644 (file)
index 0000000..0c7ff6a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef DM_ANDROID_VERITY_H
+#define DM_ANDROID_VERITY_H
+
+#include <crypto/sha.h>
+
+#define RSANUMBYTES 256
+#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
+#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56
+#define VERITY_METADATA_VERSION 0
+#define VERITY_STATE_DISABLE 1
+#define DATA_BLOCK_SIZE (4 * 1024)
+#define VERITY_METADATA_SIZE (8 * DATA_BLOCK_SIZE)
+#define VERITY_TABLE_ARGS 10
+#define VERITY_COMMANDLINE_PARAM_LENGTH 20
+#define BUILD_VARIANT 20
+
+/*
+ * <subject>:<sha1-id> is the format for the identifier.
+ * subject can either be the Common Name(CN) + Organization Name(O) or
+ * just the CN if the it is prefixed with O
+ * From https://tools.ietf.org/html/rfc5280#appendix-A
+ * ub-organization-name-length INTEGER ::= 64
+ * ub-common-name-length INTEGER ::= 64
+ *
+ * http://lxr.free-electrons.com/source/crypto/asymmetric_keys/x509_cert_parser.c?v=3.9#L278
+ * ctx->o_size + 2 + ctx->cn_size + 1
+ * + 41 characters for ":" and sha1 id
+ * 64 + 2 + 64 + 1 + 1 + 40 (172)
+ * setting VERITY_DEFAULT_KEY_ID_LENGTH to 200 characters.
+ */
+#define VERITY_DEFAULT_KEY_ID_LENGTH 200
+
+#define FEC_MAGIC 0xFECFECFE
+#define FEC_BLOCK_SIZE (4 * 1024)
+#define FEC_VERSION 0
+#define FEC_RSM 255
+#define FEC_ARG_LENGTH 300
+
+#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
+#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
+#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
+
+#define VERITY_TABLE_OPT_FEC_FORMAT \
+       "use_fec_from_device %s fec_start %llu fec_blocks %llu fec_roots %u ignore_zero_blocks"
+#define VERITY_TABLE_OPT_FEC_ARGS 9
+
+#define VERITY_DEBUG 0
+
+#define DM_MSG_PREFIX                   "android-verity"
+
+#define DM_LINEAR_ARGS 2
+#define DM_LINEAR_TARGET_OFFSET "0"
+
+/*
+ * There can be two formats.
+ * if fec is present
+ * <data_blocks> <verity_tree> <verity_metdata_32K><fec_data><fec_data_4K>
+ * if fec is not present
+ * <data_blocks> <verity_tree> <verity_metdata_32K>
+ */
+struct fec_header {
+       __le32 magic;
+       __le32 version;
+       __le32 size;
+       __le32 roots;
+       __le32 fec_size;
+       __le64 inp_size;
+       u8 hash[SHA256_DIGEST_SIZE];
+} __attribute__((packed));
+
+struct android_metadata_header {
+       __le32 magic_number;
+       __le32 protocol_version;
+       char signature[RSANUMBYTES];
+       __le32 table_length;
+};
+
+struct android_metadata {
+       struct android_metadata_header *header;
+       char *verity_table;
+};
+
+struct fec_ecc_metadata {
+       bool valid;
+       u32 roots;
+       u64 blocks;
+       u64 rounds;
+       u64 start;
+};
+
+struct bio_read {
+       struct page **page_io;
+       int number_of_pages;
+};
+
+extern struct target_type linear_target;
+
+extern void dm_linear_dtr(struct dm_target *ti);
+extern int dm_linear_map(struct dm_target *ti, struct bio *bio);
+extern void dm_linear_status(struct dm_target *ti, status_type_t type,
+                       unsigned status_flags, char *result, unsigned maxlen);
+extern int dm_linear_prepare_ioctl(struct dm_target *ti,
+                struct block_device **bdev, fmode_t *mode);
+extern int dm_linear_iterate_devices(struct dm_target *ti,
+                       iterate_devices_callout_fn fn, void *data);
+extern int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv);
+#endif /* DM_ANDROID_VERITY_H */
index e85bcae50f65f68c2035efcbb328006d1bf45bb7..e540b7942ebac2b387dd609ed0c7de1f22515040 100644 (file)
@@ -112,8 +112,7 @@ struct iv_tcw_private {
  * and encrypts / decrypts at the same time.
  */
 enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
-            DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD,
-            DM_CRYPT_EXIT_THREAD};
+            DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
 
 /*
  * The fields in here must be read only after initialization.
@@ -1204,18 +1203,20 @@ continue_locked:
                if (!RB_EMPTY_ROOT(&cc->write_tree))
                        goto pop_from_list;
 
-               if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) {
-                       spin_unlock_irq(&cc->write_thread_wait.lock);
-                       break;
-               }
-
-               __set_current_state(TASK_INTERRUPTIBLE);
+               set_current_state(TASK_INTERRUPTIBLE);
                __add_wait_queue(&cc->write_thread_wait, &wait);
 
                spin_unlock_irq(&cc->write_thread_wait.lock);
 
+               if (unlikely(kthread_should_stop())) {
+                       set_task_state(current, TASK_RUNNING);
+                       remove_wait_queue(&cc->write_thread_wait, &wait);
+                       break;
+               }
+
                schedule();
 
+               set_task_state(current, TASK_RUNNING);
                spin_lock_irq(&cc->write_thread_wait.lock);
                __remove_wait_queue(&cc->write_thread_wait, &wait);
                goto continue_locked;
@@ -1530,13 +1531,8 @@ static void crypt_dtr(struct dm_target *ti)
        if (!cc)
                return;
 
-       if (cc->write_thread) {
-               spin_lock_irq(&cc->write_thread_wait.lock);
-               set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags);
-               wake_up_locked(&cc->write_thread_wait);
-               spin_unlock_irq(&cc->write_thread_wait.lock);
+       if (cc->write_thread)
                kthread_stop(cc->write_thread);
-       }
 
        if (cc->io_queue)
                destroy_workqueue(cc->io_queue);
@@ -1928,6 +1924,13 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
        }
 
+       /*
+        * Check if bio is too large, split as needed.
+        */
+       if (unlikely(bio->bi_iter.bi_size > (BIO_MAX_PAGES << PAGE_SHIFT)) &&
+           bio_data_dir(bio) == WRITE)
+               dm_accept_partial_bio(bio, ((BIO_MAX_PAGES << PAGE_SHIFT) >> SECTOR_SHIFT));
+
        io = dm_per_bio_data(bio, cc->per_bio_data_size);
        crypt_io_init(io, cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector));
        io->ctx.req = (struct ablkcipher_request *)(io + 1);
index 09e2afcafd2ddc2575d552e14eb4f469505300f2..8e9e928dafba398bb6e1ac19445508594c1c2807 100644 (file)
@@ -289,10 +289,14 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
                pb->bio_submitted = true;
 
                /*
-                * Map reads as normal.
+                * Error reads if neither corrupt_bio_byte or drop_writes are set.
+                * Otherwise, flakey_end_io() will decide if the reads should be modified.
                 */
-               if (bio_data_dir(bio) == READ)
+               if (bio_data_dir(bio) == READ) {
+                       if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags))
+                               return -EIO;
                        goto map_bio;
+               }
 
                /*
                 * Drop writes?
@@ -328,14 +332,22 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
        struct flakey_c *fc = ti->private;
        struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
 
-       /*
-        * Corrupt successful READs while in down state.
-        * If flags were specified, only corrupt those that match.
-        */
-       if (fc->corrupt_bio_byte && !error && pb->bio_submitted &&
-           (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
-           all_corrupt_bio_flags_match(bio, fc))
-               corrupt_bio_data(bio, fc);
+       if (!error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
+               if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) &&
+                   all_corrupt_bio_flags_match(bio, fc)) {
+                       /*
+                        * Corrupt successful matching READs while in down state.
+                        */
+                       corrupt_bio_data(bio, fc);
+
+               } else if (!test_bit(DROP_WRITES, &fc->flags)) {
+                       /*
+                        * Error read during the down_interval if drop_writes
+                        * wasn't configured.
+                        */
+                       return -EIO;
+               }
+       }
 
        return error;
 }
index 80a43954325966a872cf8ebc95fb23c92c0b8819..bc5e9a5b1f302b45c96fb6e874f04022ed9031b2 100644 (file)
@@ -1923,6 +1923,45 @@ void dm_interface_exit(void)
        dm_hash_exit();
 }
 
+
+/**
+ * dm_ioctl_export - Permanently export a mapped device via the ioctl interface
+ * @md: Pointer to mapped_device
+ * @name: Buffer (size DM_NAME_LEN) for name
+ * @uuid: Buffer (size DM_UUID_LEN) for uuid or NULL if not desired
+ */
+int dm_ioctl_export(struct mapped_device *md, const char *name,
+                   const char *uuid)
+{
+       int r = 0;
+       struct hash_cell *hc;
+
+       if (!md) {
+               r = -ENXIO;
+               goto out;
+       }
+
+       /* The name and uuid can only be set once. */
+       mutex_lock(&dm_hash_cells_mutex);
+       hc = dm_get_mdptr(md);
+       mutex_unlock(&dm_hash_cells_mutex);
+       if (hc) {
+               DMERR("%s: already exported", dm_device_name(md));
+               r = -ENXIO;
+               goto out;
+       }
+
+       r = dm_hash_insert(name, uuid, md);
+       if (r) {
+               DMERR("%s: could not bind to '%s'", dm_device_name(md), name);
+               goto out;
+       }
+
+       /* Let udev know we've changed. */
+       dm_kobject_uevent(md, KOBJ_CHANGE, dm_get_event_nr(md));
+out:
+       return r;
+}
 /**
  * dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers
  * @md: Pointer to mapped_device
index 05c35aacb3aaeadb4cfddd73a14fed73a7c1bbe0..2ff5f32a4b99c1762d9c293902af89a56ac6bc5a 100644 (file)
@@ -25,7 +25,7 @@ struct linear_c {
 /*
  * Construct a linear mapping: <dev_path> <offset>
  */
-static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        struct linear_c *lc;
        unsigned long long tmp;
@@ -66,14 +66,16 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        kfree(lc);
        return ret;
 }
+EXPORT_SYMBOL_GPL(dm_linear_ctr);
 
-static void linear_dtr(struct dm_target *ti)
+void dm_linear_dtr(struct dm_target *ti)
 {
        struct linear_c *lc = (struct linear_c *) ti->private;
 
        dm_put_device(ti, lc->dev);
        kfree(lc);
 }
+EXPORT_SYMBOL_GPL(dm_linear_dtr);
 
 static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
 {
@@ -92,14 +94,15 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio)
                        linear_map_sector(ti, bio->bi_iter.bi_sector);
 }
 
-static int linear_map(struct dm_target *ti, struct bio *bio)
+int dm_linear_map(struct dm_target *ti, struct bio *bio)
 {
        linear_map_bio(ti, bio);
 
        return DM_MAPIO_REMAPPED;
 }
+EXPORT_SYMBOL_GPL(dm_linear_map);
 
-static void linear_status(struct dm_target *ti, status_type_t type,
+void dm_linear_status(struct dm_target *ti, status_type_t type,
                          unsigned status_flags, char *result, unsigned maxlen)
 {
        struct linear_c *lc = (struct linear_c *) ti->private;
@@ -115,8 +118,9 @@ static void linear_status(struct dm_target *ti, status_type_t type,
                break;
        }
 }
+EXPORT_SYMBOL_GPL(dm_linear_status);
 
-static int linear_prepare_ioctl(struct dm_target *ti,
+int dm_linear_prepare_ioctl(struct dm_target *ti,
                struct block_device **bdev, fmode_t *mode)
 {
        struct linear_c *lc = (struct linear_c *) ti->private;
@@ -132,25 +136,27 @@ static int linear_prepare_ioctl(struct dm_target *ti,
                return 1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(dm_linear_prepare_ioctl);
 
-static int linear_iterate_devices(struct dm_target *ti,
+int dm_linear_iterate_devices(struct dm_target *ti,
                                  iterate_devices_callout_fn fn, void *data)
 {
        struct linear_c *lc = ti->private;
 
        return fn(ti, lc->dev, lc->start, ti->len, data);
 }
+EXPORT_SYMBOL_GPL(dm_linear_iterate_devices);
 
 static struct target_type linear_target = {
        .name   = "linear",
        .version = {1, 2, 1},
        .module = THIS_MODULE,
-       .ctr    = linear_ctr,
-       .dtr    = linear_dtr,
-       .map    = linear_map,
-       .status = linear_status,
-       .prepare_ioctl linear_prepare_ioctl,
-       .iterate_devices = linear_iterate_devices,
+       .ctr    = dm_linear_ctr,
+       .dtr    = dm_linear_dtr,
+       .map    = dm_linear_map,
+       .status = dm_linear_status,
+       .prepare_ioctl  = dm_linear_prepare_ioctl,
+       .iterate_devices = dm_linear_iterate_devices,
 };
 
 int __init dm_linear_init(void)
index 624589d51c2cb67828567ad34b02d283e5965956..c8b513ee117c9cd9b7e5e0e18efbc2611a9cba7c 100644 (file)
@@ -258,12 +258,12 @@ static int log_one_block(struct log_writes_c *lc,
                goto out;
        sector++;
 
-       bio = bio_alloc(GFP_KERNEL, block->vec_cnt);
+       atomic_inc(&lc->io_blocks);
+       bio = bio_alloc(GFP_KERNEL, min(block->vec_cnt, BIO_MAX_PAGES));
        if (!bio) {
                DMERR("Couldn't alloc log bio");
                goto error;
        }
-       atomic_inc(&lc->io_blocks);
        bio->bi_iter.bi_size = 0;
        bio->bi_iter.bi_sector = sector;
        bio->bi_bdev = lc->logdev->bdev;
@@ -280,7 +280,7 @@ static int log_one_block(struct log_writes_c *lc,
                if (ret != block->vecs[i].bv_len) {
                        atomic_inc(&lc->io_blocks);
                        submit_bio(WRITE, bio);
-                       bio = bio_alloc(GFP_KERNEL, block->vec_cnt - i);
+                       bio = bio_alloc(GFP_KERNEL, min(block->vec_cnt - i, BIO_MAX_PAGES));
                        if (!bio) {
                                DMERR("Couldn't alloc log bio");
                                goto error;
@@ -456,9 +456,9 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad;
        }
 
-       ret = -EINVAL;
        lc->log_kthread = kthread_run(log_writes_kthread, lc, "log-write");
-       if (!lc->log_kthread) {
+       if (IS_ERR(lc->log_kthread)) {
+               ret = PTR_ERR(lc->log_kthread);
                ti->error = "Couldn't alloc kthread";
                dm_put_device(ti, lc->dev);
                dm_put_device(ti, lc->logdev);
index cfa29f574c2a9e1454788a5757471835b254d857..5b2ef966012b585874ca0bc796d1ff47309c8313 100644 (file)
@@ -1220,10 +1220,10 @@ static void activate_path(struct work_struct *work)
 {
        struct pgpath *pgpath =
                container_of(work, struct pgpath, activate_path.work);
+       struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev);
 
-       if (pgpath->is_active)
-               scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev),
-                                pg_init_done, pgpath);
+       if (pgpath->is_active && !blk_queue_dying(q))
+               scsi_dh_activate(q, pg_init_done, pgpath);
        else
                pg_init_done(pgpath, SCSI_DH_DEV_OFFLINED);
 }
index cb5d0daf53bb65ba0c47c330ce533590840adb46..b3d78bba3a79a450f8dc92b9b3bb37e2d989e107 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
 #include <linux/namei.h>
+#include <linux/mount.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/slab.h>
index 5c5d30cb6ec59bba067fa3f97808353004ea8aec..9d3d4b2972011f090696e9e9b9105a80b967e272 100644 (file)
@@ -551,7 +551,7 @@ static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
  * 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)
+int verity_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_verity *v = ti->private;
        struct dm_verity_io *io;
@@ -592,11 +592,12 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
 
        return DM_MAPIO_SUBMITTED;
 }
+EXPORT_SYMBOL_GPL(verity_map);
 
 /*
  * Status: V (valid) or C (corruption found)
  */
-static void verity_status(struct dm_target *ti, status_type_t type,
+void verity_status(struct dm_target *ti, status_type_t type,
                          unsigned status_flags, char *result, unsigned maxlen)
 {
        struct dm_verity *v = ti->private;
@@ -655,8 +656,9 @@ static void verity_status(struct dm_target *ti, status_type_t type,
                break;
        }
 }
+EXPORT_SYMBOL_GPL(verity_status);
 
-static int verity_prepare_ioctl(struct dm_target *ti,
+int verity_prepare_ioctl(struct dm_target *ti,
                struct block_device **bdev, fmode_t *mode)
 {
        struct dm_verity *v = ti->private;
@@ -668,16 +670,18 @@ static int verity_prepare_ioctl(struct dm_target *ti,
                return 1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(verity_prepare_ioctl);
 
-static int verity_iterate_devices(struct dm_target *ti,
+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);
 }
+EXPORT_SYMBOL_GPL(verity_iterate_devices);
 
-static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
+void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        struct dm_verity *v = ti->private;
 
@@ -689,8 +693,9 @@ static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
        blk_limits_io_min(limits, limits->logical_block_size);
 }
+EXPORT_SYMBOL_GPL(verity_io_hints);
 
-static void verity_dtr(struct dm_target *ti)
+void verity_dtr(struct dm_target *ti)
 {
        struct dm_verity *v = ti->private;
 
@@ -719,6 +724,7 @@ static void verity_dtr(struct dm_target *ti)
 
        kfree(v);
 }
+EXPORT_SYMBOL_GPL(verity_dtr);
 
 static int verity_alloc_zero_digest(struct dm_verity *v)
 {
@@ -817,7 +823,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
  *     <digest>
  *     <salt>          Hex string or "-" if no salt.
  */
-static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
        struct dm_verity *v;
        struct dm_arg_set as;
@@ -1053,6 +1059,7 @@ bad:
 
        return r;
 }
+EXPORT_SYMBOL_GPL(verity_ctr);
 
 static struct target_type verity_target = {
        .name           = "verity",
index fb419f422d7316f4e4e120cdb275e5222b3972f5..75effca400a3b170ae436334f0c961e335bd9096 100644 (file)
@@ -126,4 +126,14 @@ extern int verity_hash(struct dm_verity *v, struct shash_desc *desc,
 extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
                                 sector_t block, u8 *digest, bool *is_zero);
 
+extern void verity_status(struct dm_target *ti, status_type_t type,
+                       unsigned status_flags, char *result, unsigned maxlen);
+extern int verity_prepare_ioctl(struct dm_target *ti,
+                struct block_device **bdev, fmode_t *mode);
+extern int verity_iterate_devices(struct dm_target *ti,
+                               iterate_devices_callout_fn fn, void *data);
+extern void verity_io_hints(struct dm_target *ti, struct queue_limits *limits);
+extern void verity_dtr(struct dm_target *ti);
+extern int verity_ctr(struct dm_target *ti, unsigned argc, char **argv);
+extern int verity_map(struct dm_target *ti, struct bio *bio);
 #endif /* DM_VERITY_H */
index c338aebb4ccd54aa2ee40febd1103e1852b83b82..84aa8b1d048031d26f76d11972e8ba1e3449dfde 100644 (file)
@@ -2869,6 +2869,7 @@ EXPORT_SYMBOL_GPL(dm_device_name);
 
 static void __dm_destroy(struct mapped_device *md, bool wait)
 {
+       struct request_queue *q = dm_get_md_queue(md);
        struct dm_table *map;
        int srcu_idx;
 
@@ -2879,6 +2880,10 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
 
+       spin_lock_irq(q->queue_lock);
+       queue_flag_set(QUEUE_FLAG_DYING, q);
+       spin_unlock_irq(q->queue_lock);
+
        if (dm_request_based(md) && md->kworker_task)
                flush_kthread_worker(&md->kworker);
 
@@ -3078,7 +3083,8 @@ static void unlock_fs(struct mapped_device *md)
  * Caller must hold md->suspend_lock
  */
 static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
-                       unsigned suspend_flags, int interruptible)
+                       unsigned suspend_flags, int interruptible,
+                       int dmf_suspended_flag)
 {
        bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
        bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG;
@@ -3145,6 +3151,8 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
         * to finish.
         */
        r = dm_wait_for_completion(md, interruptible);
+       if (!r)
+               set_bit(dmf_suspended_flag, &md->flags);
 
        if (noflush)
                clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
@@ -3206,12 +3214,10 @@ retry:
 
        map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
 
-       r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE);
+       r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE, DMF_SUSPENDED);
        if (r)
                goto out_unlock;
 
-       set_bit(DMF_SUSPENDED, &md->flags);
-
        dm_table_postsuspend_targets(map);
 
 out_unlock:
@@ -3244,10 +3250,11 @@ static int __dm_resume(struct mapped_device *md, struct dm_table *map)
 
 int dm_resume(struct mapped_device *md)
 {
-       int r = -EINVAL;
+       int r;
        struct dm_table *map = NULL;
 
 retry:
+       r = -EINVAL;
        mutex_lock_nested(&md->suspend_lock, SINGLE_DEPTH_NESTING);
 
        if (!dm_suspended_md(md))
@@ -3271,8 +3278,6 @@ retry:
                goto out;
 
        clear_bit(DMF_SUSPENDED, &md->flags);
-
-       r = 0;
 out:
        mutex_unlock(&md->suspend_lock);
 
@@ -3305,9 +3310,8 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla
         * would require changing .presuspend to return an error -- avoid this
         * until there is a need for more elaborate variants of internal suspend.
         */
-       (void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE);
-
-       set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+       (void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
+                           DMF_SUSPENDED_INTERNALLY);
 
        dm_table_postsuspend_targets(map);
 }
index c57fdf847b4767bb86c8b42548fe221785fd9b2e..c1c7d4fb4b775dea78ac3d796ed332d7b6b5f68a 100644 (file)
@@ -7572,16 +7572,12 @@ EXPORT_SYMBOL(unregister_md_cluster_operations);
 
 int md_setup_cluster(struct mddev *mddev, int nodes)
 {
-       int err;
-
-       err = request_module("md-cluster");
-       if (err) {
-               pr_err("md-cluster module not found.\n");
-               return -ENOENT;
-       }
-
+       if (!md_cluster_ops)
+               request_module("md-cluster");
        spin_lock(&pers_lock);
+       /* ensure module won't be unloaded */
        if (!md_cluster_ops || !try_module_get(md_cluster_mod)) {
+               pr_err("can't find md-cluster module or get it's reference.\n");
                spin_unlock(&pers_lock);
                return -ENOENT;
        }
index 1100e98a7b1d36eaefe4440767d823d49d1ebf3b..7df7fb3738a088bcad69a7a26cbf892669ea93a6 100644 (file)
@@ -55,7 +55,13 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
 
 int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
 {
-       return (rbuf->pread==rbuf->pwrite);
+       /* smp_load_acquire() to load write pointer on reader side
+        * this pairs with smp_store_release() in dvb_ringbuffer_write(),
+        * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
+        *
+        * for memory barriers also see Documentation/circular-buffers.txt
+        */
+       return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
 }
 
 
@@ -64,7 +70,12 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
 {
        ssize_t free;
 
-       free = rbuf->pread - rbuf->pwrite;
+       /* ACCESS_ONCE() to load read pointer on writer side
+        * this pairs with smp_store_release() in dvb_ringbuffer_read(),
+        * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(),
+        * or dvb_ringbuffer_reset()
+        */
+       free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite;
        if (free <= 0)
                free += rbuf->size;
        return free-1;
@@ -76,7 +87,11 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
 {
        ssize_t avail;
 
-       avail = rbuf->pwrite - rbuf->pread;
+       /* smp_load_acquire() to load write pointer on reader side
+        * this pairs with smp_store_release() in dvb_ringbuffer_write(),
+        * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
+        */
+       avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
        if (avail < 0)
                avail += rbuf->size;
        return avail;
@@ -86,14 +101,25 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
 
 void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
 {
-       rbuf->pread = rbuf->pwrite;
+       /* dvb_ringbuffer_flush() counts as read operation
+        * smp_load_acquire() to load write pointer
+        * smp_store_release() to update read pointer, this ensures that the
+        * correct pointer is visible for subsequent dvb_ringbuffer_free()
+        * calls on other cpu cores
+        */
+       smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
        rbuf->error = 0;
 }
 EXPORT_SYMBOL(dvb_ringbuffer_flush);
 
 void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
 {
-       rbuf->pread = rbuf->pwrite = 0;
+       /* dvb_ringbuffer_reset() counts as read and write operation
+        * smp_store_release() to update read pointer
+        */
+       smp_store_release(&rbuf->pread, 0);
+       /* smp_store_release() to update write pointer */
+       smp_store_release(&rbuf->pwrite, 0);
        rbuf->error = 0;
 }
 
@@ -119,12 +145,17 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si
                        return -EFAULT;
                buf += split;
                todo -= split;
-               rbuf->pread = 0;
+               /* smp_store_release() for read pointer update to ensure
+                * that buf is not overwritten until read is complete,
+                * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+                */
+               smp_store_release(&rbuf->pread, 0);
        }
        if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
                return -EFAULT;
 
-       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+       /* smp_store_release() to update read pointer, see above */
+       smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
 
        return len;
 }
@@ -139,11 +170,16 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
                memcpy(buf, rbuf->data+rbuf->pread, split);
                buf += split;
                todo -= split;
-               rbuf->pread = 0;
+               /* smp_store_release() for read pointer update to ensure
+                * that buf is not overwritten until read is complete,
+                * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free()
+                */
+               smp_store_release(&rbuf->pread, 0);
        }
        memcpy(buf, rbuf->data+rbuf->pread, todo);
 
-       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+       /* smp_store_release() to update read pointer, see above */
+       smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
 }
 
 
@@ -158,10 +194,16 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t
                memcpy(rbuf->data+rbuf->pwrite, buf, split);
                buf += split;
                todo -= split;
-               rbuf->pwrite = 0;
+               /* smp_store_release() for write pointer update to ensure that
+                * written data is visible on other cpu cores before the pointer
+                * update, this pairs with smp_load_acquire() in
+                * dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
+                */
+               smp_store_release(&rbuf->pwrite, 0);
        }
        memcpy(rbuf->data+rbuf->pwrite, buf, todo);
-       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+       /* smp_store_release() for write pointer update, see above */
+       smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
 
        return len;
 }
@@ -181,12 +223,18 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
                        return len - todo;
                buf += split;
                todo -= split;
-               rbuf->pwrite = 0;
+               /* smp_store_release() for write pointer update to ensure that
+                * written data is visible on other cpu cores before the pointer
+                * update, this pairs with smp_load_acquire() in
+                * dvb_ringbuffer_empty() or dvb_ringbuffer_avail()
+                */
+               smp_store_release(&rbuf->pwrite, 0);
        }
        status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
        if (status)
                return len - todo;
-       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+       /* smp_store_release() for write pointer update, see above */
+       smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
 
        return len;
 }
index 292c9479bb75e391bdb82597cc2ba154abc839c5..310e4b8beae89672ed341747cca221b51d3ca1b3 100644 (file)
@@ -264,7 +264,7 @@ config DVB_MB86A16
 config DVB_TDA10071
        tristate "NXP TDA10071"
        depends on DVB_CORE && I2C
-       select REGMAP
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          Say Y when you want to support this frontend.
index cfc005ee11d8704e754008cdda3a775ac91613c2..7fc72de2434cfb3a50fd65160439f978198b0ecb 100644 (file)
@@ -71,25 +71,27 @@ static struct regdata mb86a20s_init1[] = {
 };
 
 static struct regdata mb86a20s_init2[] = {
-       { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
+       { 0x50, 0xd1 }, { 0x51, 0x22 },
+       { 0x39, 0x01 },
+       { 0x71, 0x00 },
        { 0x3b, 0x21 },
-       { 0x3c, 0x38 },
+       { 0x3c, 0x3a },
        { 0x01, 0x0d },
-       { 0x04, 0x08 }, { 0x05, 0x03 },
+       { 0x04, 0x08 }, { 0x05, 0x05 },
        { 0x04, 0x0e }, { 0x05, 0x00 },
-       { 0x04, 0x0f }, { 0x05, 0x37 },
-       { 0x04, 0x0b }, { 0x05, 0x78 },
+       { 0x04, 0x0f }, { 0x05, 0x14 },
+       { 0x04, 0x0b }, { 0x05, 0x8c },
        { 0x04, 0x00 }, { 0x05, 0x00 },
-       { 0x04, 0x01 }, { 0x05, 0x1e },
-       { 0x04, 0x02 }, { 0x05, 0x07 },
-       { 0x04, 0x03 }, { 0x05, 0xd0 },
+       { 0x04, 0x01 }, { 0x05, 0x07 },
+       { 0x04, 0x02 }, { 0x05, 0x0f },
+       { 0x04, 0x03 }, { 0x05, 0xa0 },
        { 0x04, 0x09 }, { 0x05, 0x00 },
        { 0x04, 0x0a }, { 0x05, 0xff },
-       { 0x04, 0x27 }, { 0x05, 0x00 },
+       { 0x04, 0x27 }, { 0x05, 0x64 },
        { 0x04, 0x28 }, { 0x05, 0x00 },
-       { 0x04, 0x1e }, { 0x05, 0x00 },
-       { 0x04, 0x29 }, { 0x05, 0x64 },
-       { 0x04, 0x32 }, { 0x05, 0x02 },
+       { 0x04, 0x1e }, { 0x05, 0xff },
+       { 0x04, 0x29 }, { 0x05, 0x0a },
+       { 0x04, 0x32 }, { 0x05, 0x0a },
        { 0x04, 0x14 }, { 0x05, 0x02 },
        { 0x04, 0x04 }, { 0x05, 0x00 },
        { 0x04, 0x05 }, { 0x05, 0x22 },
@@ -97,8 +99,6 @@ static struct regdata mb86a20s_init2[] = {
        { 0x04, 0x07 }, { 0x05, 0xd8 },
        { 0x04, 0x12 }, { 0x05, 0x00 },
        { 0x04, 0x13 }, { 0x05, 0xff },
-       { 0x04, 0x15 }, { 0x05, 0x4e },
-       { 0x04, 0x16 }, { 0x05, 0x20 },
 
        /*
         * On this demod, when the bit count reaches the count below,
@@ -152,42 +152,36 @@ static struct regdata mb86a20s_init2[] = {
        { 0x50, 0x51 }, { 0x51, 0x04 },         /* MER symbol 4 */
        { 0x45, 0x04 },                         /* CN symbol 4 */
        { 0x48, 0x04 },                         /* CN manual mode */
-
+       { 0x50, 0xd5 }, { 0x51, 0x01 },
        { 0x50, 0xd6 }, { 0x51, 0x1f },
        { 0x50, 0xd2 }, { 0x51, 0x03 },
-       { 0x50, 0xd7 }, { 0x51, 0xbf },
-       { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xff },
-       { 0x28, 0x46 }, { 0x29, 0x00 }, { 0x2a, 0x1a }, { 0x2b, 0x0c },
-
-       { 0x04, 0x40 }, { 0x05, 0x00 },
-       { 0x28, 0x00 }, { 0x2b, 0x08 },
-       { 0x28, 0x05 }, { 0x2b, 0x00 },
+       { 0x50, 0xd7 }, { 0x51, 0x3f },
        { 0x1c, 0x01 },
-       { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x1f },
-       { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x18 },
-       { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x12 },
-       { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x30 },
-       { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x37 },
-       { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
-       { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x09 },
-       { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x06 },
-       { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7b },
-       { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x76 },
-       { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7d },
-       { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x08 },
-       { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0b },
-       { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
-       { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf2 },
-       { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf3 },
-       { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x05 },
-       { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
-       { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
-       { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xef },
-       { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xd8 },
-       { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xf1 },
-       { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x3d },
-       { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x94 },
-       { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xba },
+       { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
+       { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
+       { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
+       { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
+       { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
+       { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
+       { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
+       { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
+       { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
+       { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
+       { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
+       { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
+       { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
+       { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
+       { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
+       { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
+       { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
+       { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
+       { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
+       { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
+       { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
+       { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
+       { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
+       { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
+       { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
        { 0x50, 0x1e }, { 0x51, 0x5d },
        { 0x50, 0x22 }, { 0x51, 0x00 },
        { 0x50, 0x23 }, { 0x51, 0xc8 },
@@ -196,9 +190,7 @@ static struct regdata mb86a20s_init2[] = {
        { 0x50, 0x26 }, { 0x51, 0x00 },
        { 0x50, 0x27 }, { 0x51, 0xc3 },
        { 0x50, 0x39 }, { 0x51, 0x02 },
-       { 0xec, 0x0f },
-       { 0xeb, 0x1f },
-       { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
+       { 0x50, 0xd5 }, { 0x51, 0x01 },
        { 0xd0, 0x00 },
 };
 
@@ -317,7 +309,11 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, enum fe_status *status)
        if (val >= 7)
                *status |= FE_HAS_SYNC;
 
-       if (val >= 8)                           /* Maybe 9? */
+       /*
+        * Actually, on state S8, it starts receiving TS, but the TS
+        * output is only on normal state after the transition to S9.
+        */
+       if (val >= 9)
                *status |= FE_HAS_LOCK;
 
        dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n",
@@ -2067,6 +2063,11 @@ static void mb86a20s_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
+static int mb86a20s_get_frontend_algo(struct dvb_frontend *fe)
+{
+        return DVBFE_ALGO_HW;
+}
+
 static struct dvb_frontend_ops mb86a20s_ops;
 
 struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
@@ -2140,6 +2141,7 @@ static struct dvb_frontend_ops mb86a20s_ops = {
        .read_status = mb86a20s_read_status_and_stats,
        .read_signal_strength = mb86a20s_read_signal_strength_from_cache,
        .tune = mb86a20s_tune,
+       .get_frontend_algo = mb86a20s_get_frontend_algo,
 };
 
 MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
index f0480d687f174b259affc527713a394187e069ee..ba780c45f6450847e87be7a6ee21c219988e6c04 100644 (file)
@@ -1706,7 +1706,7 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe,
                sdinfo = &cfg->sub_devs[i];
                client = v4l2_get_subdevdata(sdinfo->sd);
                if (client->addr == curr_client->addr &&
-                   client->adapter->nr == client->adapter->nr) {
+                   client->adapter->nr == curr_client->adapter->nr) {
                        if (vpfe->current_input >= 1)
                                return -1;
                        *app_input_index = j + vpfe->current_input;
index 3ffe2ecfd5efe37649750c64636c91c042f57a47..c8946f98ced45ee4a546b3c8fce2765616691666 100644 (file)
@@ -1029,6 +1029,11 @@ static int match_child(struct device *dev, void *data)
        return !strcmp(dev_name(dev), (char *)data);
 }
 
+static void s5p_mfc_memdev_release(struct device *dev)
+{
+       dma_release_declared_memory(dev);
+}
+
 static void *mfc_get_drv_data(struct platform_device *pdev);
 
 static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
@@ -1041,6 +1046,9 @@ static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
                mfc_err("Not enough memory\n");
                return -ENOMEM;
        }
+
+       dev_set_name(dev->mem_dev_l, "%s", "s5p-mfc-l");
+       dev->mem_dev_l->release = s5p_mfc_memdev_release;
        device_initialize(dev->mem_dev_l);
        of_property_read_u32_array(dev->plat_dev->dev.of_node,
                        "samsung,mfc-l", mem_info, 2);
@@ -1058,6 +1066,9 @@ static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
                mfc_err("Not enough memory\n");
                return -ENOMEM;
        }
+
+       dev_set_name(dev->mem_dev_r, "%s", "s5p-mfc-r");
+       dev->mem_dev_r->release = s5p_mfc_memdev_release;
        device_initialize(dev->mem_dev_r);
        of_property_read_u32_array(dev->plat_dev->dev.of_node,
                        "samsung,mfc-r", mem_info, 2);
index 84fa6e9b59a1acd9360364fbd30ca0a4e00d3a56..67314c034cdb12a0bbf79fd8209fe072fb250138 100644 (file)
@@ -29,7 +29,7 @@
 #define RC5_BIT_START          (1 * RC5_UNIT)
 #define RC5_BIT_END            (1 * RC5_UNIT)
 #define RC5X_SPACE             (4 * RC5_UNIT)
-#define RC5_TRAILER            (10 * RC5_UNIT) /* In reality, approx 100 */
+#define RC5_TRAILER            (6 * RC5_UNIT) /* In reality, approx 100 */
 
 enum rc5_state {
        STATE_INACTIVE,
index 4e941f00b6008f286b839d8e2f72c41978cc98e5..317ef63ee78999d673f85b62af14bed7e664549e 100644 (file)
@@ -1403,11 +1403,14 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
         * in order to avoid troubles during device release.
         */
        kfree(priv->ctrl.fname);
+       priv->ctrl.fname = NULL;
        memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
        if (p->fname) {
                priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
-               if (priv->ctrl.fname == NULL)
+               if (priv->ctrl.fname == NULL) {
                        rc = -ENOMEM;
+                       goto unlock;
+               }
        }
 
        /*
@@ -1439,6 +1442,7 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
                } else
                        priv->state = XC2028_WAITING_FIRMWARE;
        }
+unlock:
        mutex_unlock(&priv->lock);
 
        return rc;
index 565a59310747680858bb2bf30543e05becd579a0..34b35ebd60ac0c58503945b7e98e198436f3efcd 100644 (file)
@@ -1073,7 +1073,7 @@ static int airspy_probe(struct usb_interface *intf,
        if (ret) {
                dev_err(s->dev, "Failed to register as video device (%d)\n",
                                ret);
-               goto err_unregister_v4l2_dev;
+               goto err_free_controls;
        }
        dev_info(s->dev, "Registered as %s\n",
                        video_device_node_name(&s->vdev));
@@ -1082,7 +1082,6 @@ static int airspy_probe(struct usb_interface *intf,
 
 err_free_controls:
        v4l2_ctrl_handler_free(&s->hdl);
-err_unregister_v4l2_dev:
        v4l2_device_unregister(&s->v4l2_dev);
 err_free_mem:
        kfree(s);
index 491913778bcc5e5a209d0c53196f3bfd13c29154..2f52d66b4daec65cfb64a07244182d314ecb008e 100644 (file)
@@ -1264,7 +1264,10 @@ int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
                                   dev->board.agc_analog_digital_select_gpio,
                                   analog_or_digital);
 
-       return status;
+       if (status < 0)
+               return status;
+
+       return 0;
 }
 
 int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
index 4a117a58c39a0de5521759b564209811245b3567..8389c162bc89824de930ca0cc42a36f01d094803 100644 (file)
@@ -486,7 +486,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .output_mode = OUT_MODE_VIP11,
                .demod_xfer_mode = 0,
                .ctl_pin_status_mask = 0xFFFFFFC4,
-               .agc_analog_digital_select_gpio = 0x00, /* According with PV cxPolaris.inf file */
+               .agc_analog_digital_select_gpio = 0x1c,
                .tuner_sif_gpio = -1,
                .tuner_scl_gpio = -1,
                .tuner_sda_gpio = -1,
index a2fd49b6be837cef33fe694bd6f48520e21312e7..19b0293312a0bbd02c1a78bdfd5ed8dba9682a28 100644 (file)
@@ -712,6 +712,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
                        break;
                case CX231XX_BOARD_CNXT_RDE_253S:
                case CX231XX_BOARD_CNXT_RDU_253S:
+               case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
                        errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
                        break;
                case CX231XX_BOARD_HAUPPAUGE_EXETER:
@@ -738,7 +739,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
                case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
                case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
                case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
-               errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+                       errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
                        break;
                default:
                        break;
index a19b5c8b56ff79301d6f24d186ce54639efe6304..1a9e1e556706c46fae02f66be22b7690b0647e8f 100644 (file)
@@ -507,9 +507,8 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
        if (dev->disconnected)
                return -ENODEV;
 
-       rc = rt_mutex_trylock(&dev->i2c_bus_lock);
-       if (rc < 0)
-               return rc;
+       if (!rt_mutex_trylock(&dev->i2c_bus_lock))
+               return -EAGAIN;
 
        /* Switch I2C bus if needed */
        if (bus != dev->cur_i2c_bus &&
index f23df4a9d8c56e460840082bfd5bb9ebcafce511..52b88e9e656b5f87e3573a7a0afb7e49da8cfb95 100644 (file)
@@ -1624,7 +1624,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
+       struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
 
        command_pause(gspca_dev);
 
index 39c96bb4c985fce504372d306f96e8fe71ea7775..0712b1bc90b4dd5f3f87796865837de66f30c595 100644 (file)
@@ -243,7 +243,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
+       struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
 
        konica_stream_off(gspca_dev);
 #if IS_ENABLED(CONFIG_INPUT)
index e2cc4e5a0ccb77dce361f3cdc20517e7283394d1..bb52fc1fe598c66982a914cbb351fcb46b24d743 100644 (file)
@@ -837,7 +837,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
-       struct sd *sd = (struct sd *) gspca_dev;
+       struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
        int pkt_type;
 
        if (data[0] == 0x5a) {
index 78c12d22dfbb923d5c928bf42b0ed2a3a717ca2a..5dab02432e821af3d4750b923f55f0fe0cc20aa6 100644 (file)
@@ -278,6 +278,9 @@ static void snd_usbtv_trigger(struct work_struct *work)
 {
        struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
 
+       if (!chip->snd)
+               return;
+
        if (atomic_read(&chip->snd_stream))
                usbtv_audio_start(chip);
        else
@@ -378,6 +381,8 @@ err:
 
 void usbtv_audio_free(struct usbtv *usbtv)
 {
+       cancel_work_sync(&usbtv->snd_trigger);
+
        if (usbtv->snd && usbtv->udev) {
                snd_card_free(usbtv->snd);
                usbtv->snd = NULL;
index d11fd6ac2df050369a06641ade6e91fd2fddc649..5cefca95734efe3b3707966e5eba99f39448d419 100644 (file)
@@ -148,6 +148,26 @@ static struct uvc_format_desc uvc_fmts[] = {
                .guid           = UVC_GUID_FORMAT_H264,
                .fcc            = V4L2_PIX_FMT_H264,
        },
+       {
+               .name           = "Greyscale 8 L/R (Y8I)",
+               .guid           = UVC_GUID_FORMAT_Y8I,
+               .fcc            = V4L2_PIX_FMT_Y8I,
+       },
+       {
+               .name           = "Greyscale 12 L/R (Y12I)",
+               .guid           = UVC_GUID_FORMAT_Y12I,
+               .fcc            = V4L2_PIX_FMT_Y12I,
+       },
+       {
+               .name           = "Depth data 16-bit (Z16)",
+               .guid           = UVC_GUID_FORMAT_Z16,
+               .fcc            = V4L2_PIX_FMT_Z16,
+       },
+       {
+               .name           = "Bayer 10-bit (SRGGB10P)",
+               .guid           = UVC_GUID_FORMAT_RW10,
+               .fcc            = V4L2_PIX_FMT_SRGGB10P,
+       },
 };
 
 /* ------------------------------------------------------------------------
index f0f2391e1b436d7be1916d545421a0091b03bf92..7e4d3eea371b64dfab3d2a9126f1c2574dea4089 100644 (file)
 #define UVC_GUID_FORMAT_H264 \
        { 'H',  '2',  '6',  '4', 0x00, 0x00, 0x10, 0x00, \
         0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y8I \
+       { 'Y',  '8',  'I',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y12I \
+       { 'Y',  '1',  '2',  'I', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Z16 \
+       { 'Z',  '1',  '6',  ' ', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RW10 \
+       { 'R',  'W',  '1',  '0', 0x00, 0x00, 0x10, 0x00, \
+        0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
 /* ------------------------------------------------------------------------
  * Driver specific constants.
index 40dc1dd3292b91eda889596030991e1e0b197bb9..29bd346bdc8354d66b4a9a8e893320aa183cc83c 100644 (file)
@@ -1499,7 +1499,7 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
                             void *pb, int nonblocking)
 {
        unsigned long flags;
-       int ret;
+       int ret = 0;
 
        /*
         * Wait for at least one buffer to become available on the done_list.
@@ -1515,10 +1515,12 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
        spin_lock_irqsave(&q->done_lock, flags);
        *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
        /*
-        * Only remove the buffer from done_list if v4l2_buffer can handle all
-        * the planes.
+        * Only remove the buffer from done_list if all planes can be
+        * handled. Some cases such as V4L2 file I/O and DVB have pb
+        * == NULL; skip the check then as there's nothing to verify.
         */
-       ret = call_bufop(q, verify_planes_array, *vb, pb);
+       if (pb)
+               ret = call_bufop(q, verify_planes_array, *vb, pb);
        if (!ret)
                list_del(&(*vb)->done_entry);
        spin_unlock_irqrestore(&q->done_lock, flags);
index 15ed2aa2e532d218f6125399066722aa0d3687ac..9632f378a4adc138964b1eea665e4a39759013e0 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.
@@ -434,6 +439,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 1105db2355d200c454ee13b4baea9588bc2aa05e..83bfb1659abe4717a050dac021d831754ef33557 100644 (file)
@@ -524,6 +524,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
        int rc;
 
        if (!host->req) {
+               pm_runtime_get_sync(ms_dev(host));
                do {
                        rc = memstick_next_req(msh, &host->req);
                        dev_dbg(ms_dev(host), "next req %d\n", rc);
@@ -544,6 +545,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
                                                host->req->error);
                        }
                } while (!rc);
+               pm_runtime_put(ms_dev(host));
        }
 
 }
@@ -570,6 +572,7 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
        dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n",
                        __func__, param, value);
 
+       pm_runtime_get_sync(ms_dev(host));
        mutex_lock(&ucr->dev_mutex);
 
        err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD);
@@ -635,6 +638,7 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
        }
 out:
        mutex_unlock(&ucr->dev_mutex);
+       pm_runtime_put(ms_dev(host));
 
        /* power-on delay */
        if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
@@ -681,6 +685,7 @@ static int rtsx_usb_detect_ms_card(void *__host)
        int err;
 
        for (;;) {
+               pm_runtime_get_sync(ms_dev(host));
                mutex_lock(&ucr->dev_mutex);
 
                /* Check pending MS card changes */
@@ -703,6 +708,7 @@ static int rtsx_usb_detect_ms_card(void *__host)
                }
 
 poll_again:
+               pm_runtime_put(ms_dev(host));
                if (host->eject)
                        break;
 
index 936a701b230c99e93d3a0dd7284d338644b31807..f40ec41008d1e365675db06bb06b99452418e41b 100644 (file)
@@ -1460,6 +1460,7 @@ config MFD_WM8350
 config MFD_WM8350_I2C
        bool "Wolfson Microelectronics WM8350 with I2C"
        select MFD_WM8350
+       select REGMAP_I2C
        depends on I2C=y
        help
          The WM8350 is an integrated audio and power management
index 06c205868573e8d7d7b98e1c142156a2cc572454..c216c3a55793d9044f8c509aa1f097ca46332828 100644 (file)
@@ -50,8 +50,9 @@ static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
        if (reg <= ATMEL_HLCDC_DIS) {
                u32 status;
 
-               readl_poll_timeout(hregmap->regs + ATMEL_HLCDC_SR, status,
-                                  !(status & ATMEL_HLCDC_SIP), 1, 100);
+               readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
+                                         status, !(status & ATMEL_HLCDC_SIP),
+                                         1, 100);
        }
 
        writel(val, hregmap->regs + reg);
index 207a3bd6855979c9f3299b834889870bbb249b34..a867cc91657ef3c45a47bf3caf96dde68aff4e9a 100644 (file)
@@ -34,7 +34,13 @@ struct qcom_rpm_resource {
 struct qcom_rpm_data {
        u32 version;
        const struct qcom_rpm_resource *resource_table;
-       unsigned n_resources;
+       unsigned int n_resources;
+       unsigned int req_ctx_off;
+       unsigned int req_sel_off;
+       unsigned int ack_ctx_off;
+       unsigned int ack_sel_off;
+       unsigned int req_sel_size;
+       unsigned int ack_sel_size;
 };
 
 struct qcom_rpm {
@@ -61,11 +67,7 @@ struct qcom_rpm {
 
 #define RPM_REQUEST_TIMEOUT    (5 * HZ)
 
-#define RPM_REQUEST_CONTEXT    3
-#define RPM_REQ_SELECT         11
-#define RPM_ACK_CONTEXT                15
-#define RPM_ACK_SELECTOR       23
-#define RPM_SELECT_SIZE                7
+#define RPM_MAX_SEL_SIZE       7
 
 #define RPM_NOTIFICATION       BIT(30)
 #define RPM_REJECTED           BIT(31)
@@ -157,6 +159,12 @@ static const struct qcom_rpm_data apq8064_template = {
        .version = 3,
        .resource_table = apq8064_rpm_resource_table,
        .n_resources = ARRAY_SIZE(apq8064_rpm_resource_table),
+       .req_ctx_off = 3,
+       .req_sel_off = 11,
+       .ack_ctx_off = 15,
+       .ack_sel_off = 23,
+       .req_sel_size = 4,
+       .ack_sel_size = 7,
 };
 
 static const struct qcom_rpm_resource msm8660_rpm_resource_table[] = {
@@ -240,6 +248,12 @@ static const struct qcom_rpm_data msm8660_template = {
        .version = 2,
        .resource_table = msm8660_rpm_resource_table,
        .n_resources = ARRAY_SIZE(msm8660_rpm_resource_table),
+       .req_ctx_off = 3,
+       .req_sel_off = 11,
+       .ack_ctx_off = 19,
+       .ack_sel_off = 27,
+       .req_sel_size = 7,
+       .ack_sel_size = 7,
 };
 
 static const struct qcom_rpm_resource msm8960_rpm_resource_table[] = {
@@ -322,6 +336,12 @@ static const struct qcom_rpm_data msm8960_template = {
        .version = 3,
        .resource_table = msm8960_rpm_resource_table,
        .n_resources = ARRAY_SIZE(msm8960_rpm_resource_table),
+       .req_ctx_off = 3,
+       .req_sel_off = 11,
+       .ack_ctx_off = 15,
+       .ack_sel_off = 23,
+       .req_sel_size = 4,
+       .ack_sel_size = 7,
 };
 
 static const struct qcom_rpm_resource ipq806x_rpm_resource_table[] = {
@@ -362,6 +382,12 @@ static const struct qcom_rpm_data ipq806x_template = {
        .version = 3,
        .resource_table = ipq806x_rpm_resource_table,
        .n_resources = ARRAY_SIZE(ipq806x_rpm_resource_table),
+       .req_ctx_off = 3,
+       .req_sel_off = 11,
+       .ack_ctx_off = 15,
+       .ack_sel_off = 23,
+       .req_sel_size = 4,
+       .ack_sel_size = 7,
 };
 
 static const struct of_device_id qcom_rpm_of_match[] = {
@@ -380,7 +406,7 @@ int qcom_rpm_write(struct qcom_rpm *rpm,
 {
        const struct qcom_rpm_resource *res;
        const struct qcom_rpm_data *data = rpm->data;
-       u32 sel_mask[RPM_SELECT_SIZE] = { 0 };
+       u32 sel_mask[RPM_MAX_SEL_SIZE] = { 0 };
        int left;
        int ret = 0;
        int i;
@@ -398,12 +424,12 @@ int qcom_rpm_write(struct qcom_rpm *rpm,
                writel_relaxed(buf[i], RPM_REQ_REG(rpm, res->target_id + i));
 
        bitmap_set((unsigned long *)sel_mask, res->select_id, 1);
-       for (i = 0; i < ARRAY_SIZE(sel_mask); i++) {
+       for (i = 0; i < rpm->data->req_sel_size; i++) {
                writel_relaxed(sel_mask[i],
-                              RPM_CTRL_REG(rpm, RPM_REQ_SELECT + i));
+                              RPM_CTRL_REG(rpm, rpm->data->req_sel_off + i));
        }
 
-       writel_relaxed(BIT(state), RPM_CTRL_REG(rpm, RPM_REQUEST_CONTEXT));
+       writel_relaxed(BIT(state), RPM_CTRL_REG(rpm, rpm->data->req_ctx_off));
 
        reinit_completion(&rpm->ack);
        regmap_write(rpm->ipc_regmap, rpm->ipc_offset, BIT(rpm->ipc_bit));
@@ -426,10 +452,11 @@ static irqreturn_t qcom_rpm_ack_interrupt(int irq, void *dev)
        u32 ack;
        int i;
 
-       ack = readl_relaxed(RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
-       for (i = 0; i < RPM_SELECT_SIZE; i++)
-               writel_relaxed(0, RPM_CTRL_REG(rpm, RPM_ACK_SELECTOR + i));
-       writel(0, RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
+       ack = readl_relaxed(RPM_CTRL_REG(rpm, rpm->data->ack_ctx_off));
+       for (i = 0; i < rpm->data->ack_sel_size; i++)
+               writel_relaxed(0,
+                       RPM_CTRL_REG(rpm, rpm->data->ack_sel_off + i));
+       writel(0, RPM_CTRL_REG(rpm, rpm->data->ack_ctx_off));
 
        if (ack & RPM_NOTIFICATION) {
                dev_warn(rpm->dev, "ignoring notification!\n");
index dbd907d7170ebe990cb63fede374624ea03b6fd4..691dab791f7af81d91ed3892a945c74c1f0d3fa1 100644 (file)
@@ -46,9 +46,6 @@ static void rtsx_usb_sg_timed_out(unsigned long data)
 
        dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
        usb_sg_cancel(&ucr->current_sg);
-
-       /* we know the cancellation is caused by time-out */
-       ucr->current_sg.status = -ETIMEDOUT;
 }
 
 static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
@@ -67,12 +64,15 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
        ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
        add_timer(&ucr->sg_timer);
        usb_sg_wait(&ucr->current_sg);
-       del_timer_sync(&ucr->sg_timer);
+       if (!del_timer_sync(&ucr->sg_timer))
+               ret = -ETIMEDOUT;
+       else
+               ret = ucr->current_sg.status;
 
        if (act_len)
                *act_len = ucr->current_sg.bytes;
 
-       return ucr->current_sg.status;
+       return ret;
 }
 
 int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
index 2006cddc614fc186a02bbf82239934d99b7f84b9..84c2e7f663b17c5ff18c92ae344396cddd99bcad 100644 (file)
@@ -538,6 +538,12 @@ config UID_CPUTIME
        help
          Per UID based cpu time statistics exported to /proc/uid_cputime
 
+config MEMORY_STATE_TIME
+       tristate "Memory freq/bandwidth time statistics"
+       depends on PROFILING
+       help
+         Memory time statistics exported to /sys/kernel/memory_state_time
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index 48688403593b4eb02416050be7dd05514e5340d5..589997197504c274d3f8c468c634e5bdaf4b45ec 100644 (file)
@@ -58,3 +58,4 @@ obj-$(CONFIG_ECHO)            += echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)  += vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)         += cxl/
 obj-$(CONFIG_UID_CPUTIME) += uid_cputime.o
+obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o
index 6982f603fadc51a20154f38cbf1f82d95125f8df..ab6f392d3504128ae114c90cd061540839a297c3 100644 (file)
@@ -1,4 +1,4 @@
-ccflags-y := -Werror -Wno-unused-const-variable
+ccflags-y := -Werror $(call cc-disable-warning, unused-const-variable)
 
 cxl-y                          += main.o file.o irq.o fault.o native.o
 cxl-y                          += context.o sysfs.o debugfs.o pci.o trace.o
index 103baf0e0c5bfd9aa23537adf12f6035bb427d86..ea3eeb7011e1770e24f6287bac51826611bd0859 100644 (file)
@@ -25,7 +25,6 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
 
        afu = cxl_pci_to_afu(dev);
 
-       get_device(&afu->dev);
        ctx = cxl_context_alloc();
        if (IS_ERR(ctx)) {
                rc = PTR_ERR(ctx);
@@ -61,7 +60,6 @@ err_mapping:
 err_ctx:
        kfree(ctx);
 err_dev:
-       put_device(&afu->dev);
        return ERR_PTR(rc);
 }
 EXPORT_SYMBOL_GPL(cxl_dev_context_init);
@@ -87,8 +85,6 @@ int cxl_release_context(struct cxl_context *ctx)
        if (ctx->status >= STARTED)
                return -EBUSY;
 
-       put_device(&ctx->afu->dev);
-
        cxl_context_free(ctx);
 
        return 0;
@@ -176,7 +172,7 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
 
        if (task) {
                ctx->pid = get_task_pid(task, PIDTYPE_PID);
-               get_pid(ctx->pid);
+               ctx->glpid = get_task_pid(task->group_leader, PIDTYPE_PID);
                kernel = false;
        }
 
index 2faa1270d085b15f92e185f8f389f5790390fbef..262b88eac414a3e40d8edf42fc9fdffc7b54a6c0 100644 (file)
@@ -42,7 +42,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
        spin_lock_init(&ctx->sste_lock);
        ctx->afu = afu;
        ctx->master = master;
-       ctx->pid = NULL; /* Set in start work ioctl */
+       ctx->pid = ctx->glpid = NULL; /* Set in start work ioctl */
        mutex_init(&ctx->mapping_lock);
        ctx->mapping = mapping;
 
@@ -97,6 +97,12 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
        ctx->pe = i;
        ctx->elem = &ctx->afu->spa[i];
        ctx->pe_inserted = false;
+
+       /*
+        * take a ref on the afu so that it stays alive at-least till
+        * this context is reclaimed inside reclaim_ctx.
+        */
+       cxl_afu_get(afu);
        return 0;
 }
 
@@ -211,7 +217,11 @@ int __detach_context(struct cxl_context *ctx)
        WARN_ON(cxl_detach_process(ctx) &&
                cxl_adapter_link_ok(ctx->afu->adapter));
        flush_work(&ctx->fault_work); /* Only needed for dedicated process */
+
+       /* release the reference to the group leader and mm handling pid */
        put_pid(ctx->pid);
+       put_pid(ctx->glpid);
+
        cxl_ctx_put();
        return 0;
 }
@@ -278,6 +288,9 @@ static void reclaim_ctx(struct rcu_head *rcu)
        if (ctx->irq_bitmap)
                kfree(ctx->irq_bitmap);
 
+       /* Drop ref to the afu device taken during cxl_context_init */
+       cxl_afu_put(ctx->afu);
+
        kfree(ctx);
 }
 
index 0cfb9c129f273cbdf0a408c6b5d3008bd308596d..a521bc72cec2d83c88332703d6fe9f5795093401 100644 (file)
@@ -403,6 +403,18 @@ struct cxl_afu {
        bool enabled;
 };
 
+/* AFU refcount management */
+static inline struct cxl_afu *cxl_afu_get(struct cxl_afu *afu)
+{
+
+       return (get_device(&afu->dev) == NULL) ? NULL : afu;
+}
+
+static inline void  cxl_afu_put(struct cxl_afu *afu)
+{
+       put_device(&afu->dev);
+}
+
 
 struct cxl_irq_name {
        struct list_head list;
@@ -433,6 +445,9 @@ struct cxl_context {
        unsigned int sst_size, sst_lru;
 
        wait_queue_head_t wq;
+       /* pid of the group leader associated with the pid */
+       struct pid *glpid;
+       /* use mm context associated with this pid for ds faults */
        struct pid *pid;
        spinlock_t lock; /* Protects pending_irq_mask, pending_fault and fault_addr */
        /* Only used in PR mode */
index 25a5418c55cb897e245a8faf8f728f059f5756fa..81c3f75b73308c08e578aa8948930565ae1944d0 100644 (file)
@@ -166,13 +166,92 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
        cxl_ack_irq(ctx, CXL_PSL_TFC_An_R, 0);
 }
 
+/*
+ * Returns the mm_struct corresponding to the context ctx via ctx->pid
+ * In case the task has exited we use the task group leader accessible
+ * via ctx->glpid to find the next task in the thread group that has a
+ * valid  mm_struct associated with it. If a task with valid mm_struct
+ * is found the ctx->pid is updated to use the task struct for subsequent
+ * translations. In case no valid mm_struct is found in the task group to
+ * service the fault a NULL is returned.
+ */
+static struct mm_struct *get_mem_context(struct cxl_context *ctx)
+{
+       struct task_struct *task = NULL;
+       struct mm_struct *mm = NULL;
+       struct pid *old_pid = ctx->pid;
+
+       if (old_pid == NULL) {
+               pr_warn("%s: Invalid context for pe=%d\n",
+                        __func__, ctx->pe);
+               return NULL;
+       }
+
+       task = get_pid_task(old_pid, PIDTYPE_PID);
+
+       /*
+        * pid_alive may look racy but this saves us from costly
+        * get_task_mm when the task is a zombie. In worst case
+        * we may think a task is alive, which is about to die
+        * but get_task_mm will return NULL.
+        */
+       if (task != NULL && pid_alive(task))
+               mm = get_task_mm(task);
+
+       /* release the task struct that was taken earlier */
+       if (task)
+               put_task_struct(task);
+       else
+               pr_devel("%s: Context owning pid=%i for pe=%i dead\n",
+                       __func__, pid_nr(old_pid), ctx->pe);
+
+       /*
+        * If we couldn't find the mm context then use the group
+        * leader to iterate over the task group and find a task
+        * that gives us mm_struct.
+        */
+       if (unlikely(mm == NULL && ctx->glpid != NULL)) {
+
+               rcu_read_lock();
+               task = pid_task(ctx->glpid, PIDTYPE_PID);
+               if (task)
+                       do {
+                               mm = get_task_mm(task);
+                               if (mm) {
+                                       ctx->pid = get_task_pid(task,
+                                                               PIDTYPE_PID);
+                                       break;
+                               }
+                               task = next_thread(task);
+                       } while (task && !thread_group_leader(task));
+               rcu_read_unlock();
+
+               /* check if we switched pid */
+               if (ctx->pid != old_pid) {
+                       if (mm)
+                               pr_devel("%s:pe=%i switch pid %i->%i\n",
+                                        __func__, ctx->pe, pid_nr(old_pid),
+                                        pid_nr(ctx->pid));
+                       else
+                               pr_devel("%s:Cannot find mm for pid=%i\n",
+                                        __func__, pid_nr(old_pid));
+
+                       /* drop the reference to older pid */
+                       put_pid(old_pid);
+               }
+       }
+
+       return mm;
+}
+
+
+
 void cxl_handle_fault(struct work_struct *fault_work)
 {
        struct cxl_context *ctx =
                container_of(fault_work, struct cxl_context, fault_work);
        u64 dsisr = ctx->dsisr;
        u64 dar = ctx->dar;
-       struct task_struct *task = NULL;
        struct mm_struct *mm = NULL;
 
        if (cxl_p2n_read(ctx->afu, CXL_PSL_DSISR_An) != dsisr ||
@@ -195,17 +274,17 @@ void cxl_handle_fault(struct work_struct *fault_work)
                "DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar);
 
        if (!ctx->kernel) {
-               if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
-                       pr_devel("cxl_handle_fault unable to get task %i\n",
-                                pid_nr(ctx->pid));
+
+               mm = get_mem_context(ctx);
+               /* indicates all the thread in task group have exited */
+               if (mm == NULL) {
+                       pr_devel("%s: unable to get mm for pe=%d pid=%i\n",
+                                __func__, ctx->pe, pid_nr(ctx->pid));
                        cxl_ack_ae(ctx);
                        return;
-               }
-               if (!(mm = get_task_mm(task))) {
-                       pr_devel("cxl_handle_fault unable to get mm %i\n",
-                                pid_nr(ctx->pid));
-                       cxl_ack_ae(ctx);
-                       goto out;
+               } else {
+                       pr_devel("Handling page fault for pe=%d pid=%i\n",
+                                ctx->pe, pid_nr(ctx->pid));
                }
        }
 
@@ -218,33 +297,22 @@ void cxl_handle_fault(struct work_struct *fault_work)
 
        if (mm)
                mmput(mm);
-out:
-       if (task)
-               put_task_struct(task);
 }
 
 static void cxl_prefault_one(struct cxl_context *ctx, u64 ea)
 {
-       int rc;
-       struct task_struct *task;
        struct mm_struct *mm;
 
-       if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
-               pr_devel("cxl_prefault_one unable to get task %i\n",
-                        pid_nr(ctx->pid));
-               return;
-       }
-       if (!(mm = get_task_mm(task))) {
+       mm = get_mem_context(ctx);
+       if (mm == NULL) {
                pr_devel("cxl_prefault_one unable to get mm %i\n",
                         pid_nr(ctx->pid));
-               put_task_struct(task);
                return;
        }
 
-       rc = cxl_fault_segment(ctx, mm, ea);
+       cxl_fault_segment(ctx, mm, ea);
 
        mmput(mm);
-       put_task_struct(task);
 }
 
 static u64 next_segment(u64 ea, u64 vsid)
@@ -263,18 +331,13 @@ static void cxl_prefault_vma(struct cxl_context *ctx)
        struct copro_slb slb;
        struct vm_area_struct *vma;
        int rc;
-       struct task_struct *task;
        struct mm_struct *mm;
 
-       if (!(task = get_pid_task(ctx->pid, PIDTYPE_PID))) {
-               pr_devel("cxl_prefault_vma unable to get task %i\n",
-                        pid_nr(ctx->pid));
-               return;
-       }
-       if (!(mm = get_task_mm(task))) {
+       mm = get_mem_context(ctx);
+       if (mm == NULL) {
                pr_devel("cxl_prefault_vm unable to get mm %i\n",
                         pid_nr(ctx->pid));
-               goto out1;
+               return;
        }
 
        down_read(&mm->mmap_sem);
@@ -295,8 +358,6 @@ static void cxl_prefault_vma(struct cxl_context *ctx)
        up_read(&mm->mmap_sem);
 
        mmput(mm);
-out1:
-       put_task_struct(task);
 }
 
 void cxl_prefault(struct cxl_context *ctx, u64 wed)
index 7ccd2998be92b8b3f7cdca2a0acbf3f9586d0f34..783337d22f36ab4c1841ba5635de5bc5fc193594 100644 (file)
@@ -67,7 +67,13 @@ static int __afu_open(struct inode *inode, struct file *file, bool master)
                spin_unlock(&adapter->afu_list_lock);
                goto err_put_adapter;
        }
-       get_device(&afu->dev);
+
+       /*
+        * taking a ref to the afu so that it doesn't go away
+        * for rest of the function. This ref is released before
+        * we return.
+        */
+       cxl_afu_get(afu);
        spin_unlock(&adapter->afu_list_lock);
 
        if (!afu->current_mode)
@@ -90,13 +96,12 @@ static int __afu_open(struct inode *inode, struct file *file, bool master)
        file->private_data = ctx;
        cxl_ctx_get();
 
-       /* Our ref on the AFU will now hold the adapter */
-       put_device(&adapter->dev);
-
-       return 0;
+       /* indicate success */
+       rc = 0;
 
 err_put_afu:
-       put_device(&afu->dev);
+       /* release the ref taken earlier */
+       cxl_afu_put(afu);
 err_put_adapter:
        put_device(&adapter->dev);
        return rc;
@@ -131,8 +136,6 @@ int afu_release(struct inode *inode, struct file *file)
                mutex_unlock(&ctx->mapping_lock);
        }
 
-       put_device(&ctx->afu->dev);
-
        /*
         * At this this point all bottom halfs have finished and we should be
         * getting no more IRQs from the hardware for this context.  Once it's
@@ -198,8 +201,12 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
         * where a process (master, some daemon, etc) has opened the chardev on
         * behalf of another process, so the AFU's mm gets bound to the process
         * that performs this ioctl and not the process that opened the file.
+        * Also we grab the PID of the group leader so that if the task that
+        * has performed the attach operation exits the mm context of the
+        * process is still accessible.
         */
-       ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
+       ctx->pid = get_task_pid(current, PIDTYPE_PID);
+       ctx->glpid = get_task_pid(current->group_leader, PIDTYPE_PID);
 
        trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
 
index be2c8e248e2e30e31518738e8b16c30a766d905a..0c6c17a1c59e3a9417dde5ab842fffbab4f09e69 100644 (file)
@@ -138,6 +138,7 @@ static const struct pci_device_id cxl_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
        { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
        { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x04cf), },
+       { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0601), },
        { PCI_DEVICE_CLASS(0x120000, ~0), },
 
        { }
index a8a68acd326752980e8b31a61c8b0b9a891018c8..4e8069866c85a34be63b3c24acd3397eb935e7aa 100644 (file)
@@ -66,6 +66,9 @@
 #ifndef _MEI_HW_MEI_REGS_H_
 #define _MEI_HW_MEI_REGS_H_
 
+#define MEI_DEV_ID_KBP        0xA2BA  /* Kaby Point */
+#define MEI_DEV_ID_KBP_2      0xA2BB  /* Kaby Point 2 */
+
 /*
  * MEI device IDs
  */
index 27678d8154e074ea698952832aac64bb843032f9..0af3d7d3041951666ac6179d3eff50ed02b4c293 100644 (file)
@@ -87,6 +87,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
        {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_cfg)},
        {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_cfg)},
 
+       {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, mei_me_pch8_cfg)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, mei_me_pch8_cfg)},
+
        /* required last entry */
        {0, }
 };
diff --git a/drivers/misc/memory_state_time.c b/drivers/misc/memory_state_time.c
new file mode 100644 (file)
index 0000000..34c797a
--- /dev/null
@@ -0,0 +1,454 @@
+/* drivers/misc/memory_state_time.c
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/hashtable.h>
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/memory-state-time.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/time.h>
+#include <linux/timekeeping.h>
+#include <linux/workqueue.h>
+
+#define KERNEL_ATTR_RO(_name) \
+static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
+
+#define KERNEL_ATTR_RW(_name) \
+static struct kobj_attribute _name##_attr = \
+       __ATTR(_name, 0644, _name##_show, _name##_store)
+
+#define FREQ_HASH_BITS 4
+DECLARE_HASHTABLE(freq_hash_table, FREQ_HASH_BITS);
+
+static DEFINE_MUTEX(mem_lock);
+
+#define TAG "memory_state_time"
+#define BW_NODE "/soc/memory-state-time"
+#define FREQ_TBL "freq-tbl"
+#define BW_TBL "bw-buckets"
+#define NUM_SOURCES "num-sources"
+
+#define LOWEST_FREQ 2
+
+static int curr_bw;
+static int curr_freq;
+static u32 *bw_buckets;
+static u32 *freq_buckets;
+static int num_freqs;
+static int num_buckets;
+static int registered_bw_sources;
+static u64 last_update;
+static bool init_success;
+static struct workqueue_struct *memory_wq;
+static u32 num_sources = 10;
+static int *bandwidths;
+
+struct freq_entry {
+       int freq;
+       u64 *buckets; /* Bandwidth buckets. */
+       struct hlist_node hash;
+};
+
+struct queue_container {
+       struct work_struct update_state;
+       int value;
+       u64 time_now;
+       int id;
+       struct mutex *lock;
+};
+
+static int find_bucket(int bw)
+{
+       int i;
+
+       if (bw_buckets != NULL) {
+               for (i = 0; i < num_buckets; i++) {
+                       if (bw_buckets[i] > bw) {
+                               pr_debug("Found bucket %d for bandwidth %d\n",
+                                       i, bw);
+                               return i;
+                       }
+               }
+               return num_buckets - 1;
+       }
+       return 0;
+}
+
+static u64 get_time_diff(u64 time_now)
+{
+       u64 ms;
+
+       ms = time_now - last_update;
+       last_update = time_now;
+       return ms;
+}
+
+static ssize_t show_stat_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       int i, j;
+       int len = 0;
+       struct freq_entry *freq_entry;
+
+       for (i = 0; i < num_freqs; i++) {
+               hash_for_each_possible(freq_hash_table, freq_entry, hash,
+                               freq_buckets[i]) {
+                       if (freq_entry->freq == freq_buckets[i]) {
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                               "%d ", freq_buckets[i]);
+                               if (len >= PAGE_SIZE)
+                                       break;
+                               for (j = 0; j < num_buckets; j++) {
+                                       len += scnprintf(buf + len,
+                                                       PAGE_SIZE - len,
+                                                       "%llu ",
+                                                       freq_entry->buckets[j]);
+                               }
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                               "\n");
+                       }
+               }
+       }
+       pr_debug("Current Time: %llu\n", ktime_get_boot_ns());
+       return len;
+}
+KERNEL_ATTR_RO(show_stat);
+
+static void update_table(u64 time_now)
+{
+       struct freq_entry *freq_entry;
+
+       pr_debug("Last known bw %d freq %d\n", curr_bw, curr_freq);
+       hash_for_each_possible(freq_hash_table, freq_entry, hash, curr_freq) {
+               if (curr_freq == freq_entry->freq) {
+                       freq_entry->buckets[find_bucket(curr_bw)]
+                                       += get_time_diff(time_now);
+                       break;
+               }
+       }
+}
+
+static bool freq_exists(int freq)
+{
+       int i;
+
+       for (i = 0; i < num_freqs; i++) {
+               if (freq == freq_buckets[i])
+                       return true;
+       }
+       return false;
+}
+
+static int calculate_total_bw(int bw, int index)
+{
+       int i;
+       int total_bw = 0;
+
+       pr_debug("memory_state_time New bw %d for id %d\n", bw, index);
+       bandwidths[index] = bw;
+       for (i = 0; i < registered_bw_sources; i++)
+               total_bw += bandwidths[i];
+       return total_bw;
+}
+
+static void freq_update_do_work(struct work_struct *work)
+{
+       struct queue_container *freq_state_update
+                       = container_of(work, struct queue_container,
+                       update_state);
+       if (freq_state_update) {
+               mutex_lock(&mem_lock);
+               update_table(freq_state_update->time_now);
+               curr_freq = freq_state_update->value;
+               mutex_unlock(&mem_lock);
+               kfree(freq_state_update);
+       }
+}
+
+static void bw_update_do_work(struct work_struct *work)
+{
+       struct queue_container *bw_state_update
+                       = container_of(work, struct queue_container,
+                       update_state);
+       if (bw_state_update) {
+               mutex_lock(&mem_lock);
+               update_table(bw_state_update->time_now);
+               curr_bw = calculate_total_bw(bw_state_update->value,
+                               bw_state_update->id);
+               mutex_unlock(&mem_lock);
+               kfree(bw_state_update);
+       }
+}
+
+static void memory_state_freq_update(struct memory_state_update_block *ub,
+               int value)
+{
+       if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
+               if (freq_exists(value) && init_success) {
+                       struct queue_container *freq_container
+                               = kmalloc(sizeof(struct queue_container),
+                               GFP_KERNEL);
+                       if (!freq_container)
+                               return;
+                       INIT_WORK(&freq_container->update_state,
+                                       freq_update_do_work);
+                       freq_container->time_now = ktime_get_boot_ns();
+                       freq_container->value = value;
+                       pr_debug("Scheduling freq update in work queue\n");
+                       queue_work(memory_wq, &freq_container->update_state);
+               } else {
+                       pr_debug("Freq does not exist.\n");
+               }
+       }
+}
+
+static void memory_state_bw_update(struct memory_state_update_block *ub,
+               int value)
+{
+       if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
+               if (init_success) {
+                       struct queue_container *bw_container
+                               = kmalloc(sizeof(struct queue_container),
+                               GFP_KERNEL);
+                       if (!bw_container)
+                               return;
+                       INIT_WORK(&bw_container->update_state,
+                                       bw_update_do_work);
+                       bw_container->time_now = ktime_get_boot_ns();
+                       bw_container->value = value;
+                       bw_container->id = ub->id;
+                       pr_debug("Scheduling bandwidth update in work queue\n");
+                       queue_work(memory_wq, &bw_container->update_state);
+               }
+       }
+}
+
+struct memory_state_update_block *memory_state_register_frequency_source(void)
+{
+       struct memory_state_update_block *block;
+
+       if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
+               pr_debug("Allocating frequency source\n");
+               block = kmalloc(sizeof(struct memory_state_update_block),
+                                       GFP_KERNEL);
+               if (!block)
+                       return NULL;
+               block->update_call = memory_state_freq_update;
+               return block;
+       }
+       pr_err("Config option disabled.\n");
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(memory_state_register_frequency_source);
+
+struct memory_state_update_block *memory_state_register_bandwidth_source(void)
+{
+       struct memory_state_update_block *block;
+
+       if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
+               pr_debug("Allocating bandwidth source %d\n",
+                               registered_bw_sources);
+               block = kmalloc(sizeof(struct memory_state_update_block),
+                                       GFP_KERNEL);
+               if (!block)
+                       return NULL;
+               block->update_call = memory_state_bw_update;
+               if (registered_bw_sources < num_sources) {
+                       block->id = registered_bw_sources++;
+               } else {
+                       pr_err("Unable to allocate source; max number reached\n");
+                       kfree(block);
+                       return NULL;
+               }
+               return block;
+       }
+       pr_err("Config option disabled.\n");
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(memory_state_register_bandwidth_source);
+
+/* Buckets are designated by their maximum.
+ * Returns the buckets decided by the capability of the device.
+ */
+static int get_bw_buckets(struct device *dev)
+{
+       int ret, lenb;
+       struct device_node *node = dev->of_node;
+
+       of_property_read_u32(node, NUM_SOURCES, &num_sources);
+       if (of_find_property(node, BW_TBL, &lenb)) {
+               bandwidths = devm_kzalloc(dev,
+                               sizeof(*bandwidths) * num_sources, GFP_KERNEL);
+               if (!bandwidths)
+                       return -ENOMEM;
+               lenb /= sizeof(*bw_buckets);
+               bw_buckets = devm_kzalloc(dev, lenb * sizeof(*bw_buckets),
+                               GFP_KERNEL);
+               if (!bw_buckets) {
+                       devm_kfree(dev, bandwidths);
+                       return -ENOMEM;
+               }
+               ret = of_property_read_u32_array(node, BW_TBL, bw_buckets,
+                               lenb);
+               if (ret < 0) {
+                       devm_kfree(dev, bandwidths);
+                       devm_kfree(dev, bw_buckets);
+                       pr_err("Unable to read bandwidth table from device tree.\n");
+                       return ret;
+               }
+       }
+       curr_bw = 0;
+       num_buckets = lenb;
+       return 0;
+}
+
+/* Adds struct freq_entry nodes to the hashtable for each compatible frequency.
+ * Returns the supported number of frequencies.
+ */
+static int freq_buckets_init(struct device *dev)
+{
+       struct freq_entry *freq_entry;
+       int i;
+       int ret, lenf;
+       struct device_node *node = dev->of_node;
+
+       if (of_find_property(node, FREQ_TBL, &lenf)) {
+               lenf /= sizeof(*freq_buckets);
+               freq_buckets = devm_kzalloc(dev, lenf * sizeof(*freq_buckets),
+                               GFP_KERNEL);
+               if (!freq_buckets)
+                       return -ENOMEM;
+               pr_debug("freqs found len %d\n", lenf);
+               ret = of_property_read_u32_array(node, FREQ_TBL, freq_buckets,
+                               lenf);
+               if (ret < 0) {
+                       devm_kfree(dev, freq_buckets);
+                       pr_err("Unable to read frequency table from device tree.\n");
+                       return ret;
+               }
+               pr_debug("ret freq %d\n", ret);
+       }
+       num_freqs = lenf;
+       curr_freq = freq_buckets[LOWEST_FREQ];
+
+       for (i = 0; i < num_freqs; i++) {
+               freq_entry = devm_kzalloc(dev, sizeof(struct freq_entry),
+                               GFP_KERNEL);
+               if (!freq_entry)
+                       return -ENOMEM;
+               freq_entry->buckets = devm_kzalloc(dev, sizeof(u64)*num_buckets,
+                               GFP_KERNEL);
+               if (!freq_entry->buckets) {
+                       devm_kfree(dev, freq_entry);
+                       return -ENOMEM;
+               }
+               pr_debug("memory_state_time Adding freq to ht %d\n",
+                               freq_buckets[i]);
+               freq_entry->freq = freq_buckets[i];
+               hash_add(freq_hash_table, &freq_entry->hash, freq_buckets[i]);
+       }
+       return 0;
+}
+
+struct kobject *memory_kobj;
+EXPORT_SYMBOL_GPL(memory_kobj);
+
+static struct attribute *memory_attrs[] = {
+       &show_stat_attr.attr,
+       NULL
+};
+
+static struct attribute_group memory_attr_group = {
+       .attrs = memory_attrs,
+};
+
+static int memory_state_time_probe(struct platform_device *pdev)
+{
+       int error;
+
+       error = get_bw_buckets(&pdev->dev);
+       if (error)
+               return error;
+       error = freq_buckets_init(&pdev->dev);
+       if (error)
+               return error;
+       last_update = ktime_get_boot_ns();
+       init_success = true;
+
+       pr_debug("memory_state_time initialized with num_freqs %d\n",
+                       num_freqs);
+       return 0;
+}
+
+static const struct of_device_id match_table[] = {
+       { .compatible = "memory-state-time" },
+       {}
+};
+
+static struct platform_driver memory_state_time_driver = {
+       .probe = memory_state_time_probe,
+       .driver = {
+               .name = "memory-state-time",
+               .of_match_table = match_table,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init memory_state_time_init(void)
+{
+       int error;
+
+       hash_init(freq_hash_table);
+       memory_wq = create_singlethread_workqueue("memory_wq");
+       if (!memory_wq) {
+               pr_err("Unable to create workqueue.\n");
+               return -EINVAL;
+       }
+       /*
+        * Create sys/kernel directory for memory_state_time.
+        */
+       memory_kobj = kobject_create_and_add(TAG, kernel_kobj);
+       if (!memory_kobj) {
+               pr_err("Unable to allocate memory_kobj for sysfs directory.\n");
+               error = -ENOMEM;
+               goto wq;
+       }
+       error = sysfs_create_group(memory_kobj, &memory_attr_group);
+       if (error) {
+               pr_err("Unable to create sysfs folder.\n");
+               goto kobj;
+       }
+
+       error = platform_driver_register(&memory_state_time_driver);
+       if (error) {
+               pr_err("Unable to register memory_state_time platform driver.\n");
+               goto group;
+       }
+       return 0;
+
+group: sysfs_remove_group(memory_kobj, &memory_attr_group);
+kobj:  kobject_put(memory_kobj);
+wq:    destroy_workqueue(memory_wq);
+       return error;
+}
+module_init(memory_state_time_init);
index b5d8a71d5b25cb055d181ce147ff533494633b95..c7e0db49783b7cc2aed8ecf059979eebf0605303 100644 (file)
@@ -2015,7 +2015,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
        struct mmc_blk_data *md = mq->data;
        struct mmc_packed *packed = mqrq->packed;
        bool do_rel_wr, do_data_tag;
-       u32 *packed_cmd_hdr;
+       __le32 *packed_cmd_hdr;
        u8 hdr_blocks;
        u8 i = 1;
 
@@ -2027,8 +2027,8 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
 
        packed_cmd_hdr = packed->cmd_hdr;
        memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr));
-       packed_cmd_hdr[0] = (packed->nr_entries << 16) |
-               (PACKED_CMD_WR << 8) | PACKED_CMD_VER;
+       packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) |
+               (PACKED_CMD_WR << 8) | PACKED_CMD_VER);
        hdr_blocks = mmc_large_sector(card) ? 8 : 1;
 
        /*
@@ -2041,14 +2041,14 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
                        (rq_data_dir(prq) == WRITE) &&
                        blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
                /* Argument of CMD23 */
-               packed_cmd_hdr[(i * 2)] =
+               packed_cmd_hdr[(i * 2)] = cpu_to_le32(
                        (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
                        (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
-                       blk_rq_sectors(prq);
+                       blk_rq_sectors(prq));
                /* Argument of CMD18 or CMD25 */
-               packed_cmd_hdr[((i * 2)) + 1] =
+               packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32(
                        mmc_card_blockaddr(card) ?
-                       blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
+                       blk_rq_pos(prq) : blk_rq_pos(prq) << 9);
                packed->blocks += blk_rq_sectors(prq);
                i++;
        }
@@ -2531,7 +2531,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        set_capacity(md->disk, size);
 
        if (mmc_host_cmd23(card->host)) {
-               if (mmc_card_mmc(card) ||
+               if ((mmc_card_mmc(card) &&
+                    card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
                    (mmc_card_sd(card) &&
                     card->scr.cmds & SD_SCR_CMD23_SUPPORT))
                        md->flags |= MMC_BLK_CMD23;
index d890d8832e217a94f6d55aa79d25faadbbb7e352..1dc4c99f52a17585f67820d428001a8ae6f7bb14 100644 (file)
@@ -25,7 +25,7 @@ enum mmc_packed_type {
 
 struct mmc_packed {
        struct list_head        list;
-       u32                     cmd_hdr[1024];
+       __le32                  cmd_hdr[1024];
        unsigned int            blocks;
        u8                      nr_entries;
        u8                      retries;
index d72977c999adee37c7b9c9fec2719a04cdfcc6d6..31fc5362f99ab358e79dde0d6be02f7102610e89 100644 (file)
@@ -176,6 +176,19 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
                        pr_debug("%s:     %d bytes transferred: %d\n",
                                mmc_hostname(host),
                                mrq->data->bytes_xfered, mrq->data->error);
+#ifdef CONFIG_BLOCK
+                       if (mrq->lat_hist_enabled) {
+                               ktime_t completion;
+                               u_int64_t delta_us;
+
+                               completion = ktime_get();
+                               delta_us = ktime_us_delta(completion,
+                                                         mrq->io_start);
+                               blk_update_latency_hist(&host->io_lat_s,
+                                       (mrq->data->flags & MMC_DATA_READ),
+                                       delta_us);
+                       }
+#endif
                        trace_mmc_blk_rw_end(cmd->opcode, cmd->arg, mrq->data);
                }
 
@@ -620,6 +633,13 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
        }
 
        if (!err && areq) {
+#ifdef CONFIG_BLOCK
+               if (host->latency_hist_enabled) {
+                       areq->mrq->io_start = ktime_get();
+                       areq->mrq->lat_hist_enabled = 1;
+               } else
+                       areq->mrq->lat_hist_enabled = 0;
+#endif
                trace_mmc_blk_rw_start(areq->mrq->cmd->opcode,
                                       areq->mrq->cmd->arg,
                                       areq->mrq->data);
@@ -1962,7 +1982,7 @@ void mmc_init_erase(struct mmc_card *card)
 }
 
 static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
-                                         unsigned int arg, unsigned int qty)
+                                         unsigned int arg, unsigned int qty)
 {
        unsigned int erase_timeout;
 
@@ -2918,6 +2938,56 @@ static void __exit mmc_exit(void)
        mmc_unregister_bus();
 }
 
+#ifdef CONFIG_BLOCK
+static ssize_t
+latency_hist_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+       return blk_latency_hist_show(&host->io_lat_s, buf);
+}
+
+/*
+ * Values permitted 0, 1, 2.
+ * 0 -> Disable IO latency histograms (default)
+ * 1 -> Enable IO latency histograms
+ * 2 -> Zero out IO latency histograms
+ */
+static ssize_t
+latency_hist_store(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       long value;
+
+       if (kstrtol(buf, 0, &value))
+               return -EINVAL;
+       if (value == BLK_IO_LAT_HIST_ZERO)
+               blk_zero_latency_hist(&host->io_lat_s);
+       else if (value == BLK_IO_LAT_HIST_ENABLE ||
+                value == BLK_IO_LAT_HIST_DISABLE)
+               host->latency_hist_enabled = value;
+       return count;
+}
+
+static DEVICE_ATTR(latency_hist, S_IRUGO | S_IWUSR,
+                  latency_hist_show, latency_hist_store);
+
+void
+mmc_latency_hist_sysfs_init(struct mmc_host *host)
+{
+       if (device_create_file(&host->class_dev, &dev_attr_latency_hist))
+               dev_err(&host->class_dev,
+                       "Failed to create latency_hist sysfs entry\n");
+}
+
+void
+mmc_latency_hist_sysfs_exit(struct mmc_host *host)
+{
+       device_remove_file(&host->class_dev, &dev_attr_latency_hist);
+}
+#endif
+
 subsys_initcall(mmc_init);
 module_exit(mmc_exit);
 
index a346775929c8644d0b8e3745684df78cc5e78a1b..bbe4380a8a3088d1ede040a1b0c7c3788b9157f9 100644 (file)
@@ -32,8 +32,6 @@
 #include "slot-gpio.h"
 #include "pwrseq.h"
 
-#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
-
 static DEFINE_IDR(mmc_host_idr);
 static DEFINE_SPINLOCK(mmc_host_lock);
 
@@ -404,6 +402,10 @@ int mmc_add_host(struct mmc_host *host)
        mmc_add_host_debugfs(host);
 #endif
 
+#ifdef CONFIG_BLOCK
+       mmc_latency_hist_sysfs_init(host);
+#endif
+
        mmc_start_host(host);
        if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
                register_pm_notifier(&host->pm_notify);
@@ -435,6 +437,10 @@ void mmc_remove_host(struct mmc_host *host)
        mmc_remove_host_debugfs(host);
 #endif
 
+#ifdef CONFIG_BLOCK
+       mmc_latency_hist_sysfs_exit(host);
+#endif
+
        device_del(&host->class_dev);
 
        led_trigger_unregister_simple(host->led);
index 992bf53976337f0edf3f64fe4f9a007f4693b3a6..bf38533406fd88e27afdecee36d46928c9f0e47f 100644 (file)
@@ -12,6 +12,8 @@
 #define _MMC_CORE_HOST_H
 #include <linux/mmc/host.h>
 
+#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
+
 int mmc_register_host_class(void);
 void mmc_unregister_host_class(void);
 
@@ -21,5 +23,8 @@ void mmc_retune_hold(struct mmc_host *host);
 void mmc_retune_release(struct mmc_host *host);
 int mmc_retune(struct mmc_host *host);
 
+void mmc_latency_hist_sysfs_init(struct mmc_host *host);
+void mmc_latency_hist_sysfs_exit(struct mmc_host *host);
+
 #endif
 
index 1dee533634c986d71176917f4d510a4c7214bf5a..2e6d2fff1096ac53b8a87790aad75cb09428a62a 100644 (file)
@@ -97,6 +97,7 @@ config MMC_RICOH_MMC
 config MMC_SDHCI_ACPI
        tristate "SDHCI support for ACPI enumerated SDHCI controllers"
        depends on MMC_SDHCI && ACPI
+       select IOSF_MBI if X86
        help
          This selects support for ACPI enumerated SDHCI controllers,
          identified by ACPI Compatibility ID PNP0D40 or specific
index 28a057fae0a196092c113af946bc5ef32629f28a..72bbb12fb938022da4e9720af05c305a415052f7 100644 (file)
@@ -798,14 +798,16 @@ static int pxamci_probe(struct platform_device *pdev)
                gpio_direction_output(gpio_power,
                                      host->pdata->gpio_power_invert);
        }
-       if (gpio_is_valid(gpio_ro))
+       if (gpio_is_valid(gpio_ro)) {
                ret = mmc_gpio_request_ro(mmc, gpio_ro);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
-               goto out;
-       } else {
-               mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
-                       0 : MMC_CAP2_RO_ACTIVE_HIGH;
+               if (ret) {
+                       dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n",
+                               gpio_ro);
+                       goto out;
+               } else {
+                       mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
+                               0 : MMC_CAP2_RO_ACTIVE_HIGH;
+               }
        }
 
        if (gpio_is_valid(gpio_cd))
index 6c71fc9f76c7ecab19a5a7ac24a53ab38a6125fd..da9f71b8deb0b3fa423437d16cbae53658fd4c50 100644 (file)
@@ -1138,11 +1138,6 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        dev_dbg(sdmmc_dev(host), "%s\n", __func__);
        mutex_lock(&ucr->dev_mutex);
 
-       if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) {
-               mutex_unlock(&ucr->dev_mutex);
-               return;
-       }
-
        sd_set_power_mode(host, ios->power_mode);
        sd_set_bus_width(host, ios->bus_width);
        sd_set_timing(host, ios->timing, &host->ddr_mode);
@@ -1314,6 +1309,7 @@ static void rtsx_usb_update_led(struct work_struct *work)
                container_of(work, struct rtsx_usb_sdmmc, led_work);
        struct rtsx_ucr *ucr = host->ucr;
 
+       pm_runtime_get_sync(sdmmc_dev(host));
        mutex_lock(&ucr->dev_mutex);
 
        if (host->led.brightness == LED_OFF)
@@ -1322,6 +1318,7 @@ static void rtsx_usb_update_led(struct work_struct *work)
                rtsx_usb_turn_on_led(ucr);
 
        mutex_unlock(&ucr->dev_mutex);
+       pm_runtime_put(sdmmc_dev(host));
 }
 #endif
 
index 8aea3fa6938b59e41da882c3f650638423bc0b01..5a05bf400ca8aa5df66c0a0cea253322bcd74f65 100644 (file)
 #include <linux/mmc/pm.h>
 #include <linux/mmc/slot-gpio.h>
 
+#ifdef CONFIG_X86
+#include <asm/cpu_device_id.h>
+#include <asm/iosf_mbi.h>
+#endif
+
 #include "sdhci.h"
 
 enum {
@@ -146,6 +151,75 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
        .ops = &sdhci_acpi_ops_int,
 };
 
+#ifdef CONFIG_X86
+
+static bool sdhci_acpi_byt(void)
+{
+       static const struct x86_cpu_id byt[] = {
+               { X86_VENDOR_INTEL, 6, 0x37 },
+               {}
+       };
+
+       return x86_match_cpu(byt);
+}
+
+#define BYT_IOSF_SCCEP                 0x63
+#define BYT_IOSF_OCP_NETCTRL0          0x1078
+#define BYT_IOSF_OCP_TIMEOUT_BASE      GENMASK(10, 8)
+
+static void sdhci_acpi_byt_setting(struct device *dev)
+{
+       u32 val = 0;
+
+       if (!sdhci_acpi_byt())
+               return;
+
+       if (iosf_mbi_read(BYT_IOSF_SCCEP, 0x06, BYT_IOSF_OCP_NETCTRL0,
+                         &val)) {
+               dev_err(dev, "%s read error\n", __func__);
+               return;
+       }
+
+       if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE))
+               return;
+
+       val &= ~BYT_IOSF_OCP_TIMEOUT_BASE;
+
+       if (iosf_mbi_write(BYT_IOSF_SCCEP, 0x07, BYT_IOSF_OCP_NETCTRL0,
+                          val)) {
+               dev_err(dev, "%s write error\n", __func__);
+               return;
+       }
+
+       dev_dbg(dev, "%s completed\n", __func__);
+}
+
+static bool sdhci_acpi_byt_defer(struct device *dev)
+{
+       if (!sdhci_acpi_byt())
+               return false;
+
+       if (!iosf_mbi_available())
+               return true;
+
+       sdhci_acpi_byt_setting(dev);
+
+       return false;
+}
+
+#else
+
+static inline void sdhci_acpi_byt_setting(struct device *dev)
+{
+}
+
+static inline bool sdhci_acpi_byt_defer(struct device *dev)
+{
+       return false;
+}
+
+#endif
+
 static int bxt_get_cd(struct mmc_host *mmc)
 {
        int gpio_cd = mmc_gpio_get_cd(mmc);
@@ -337,6 +411,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (acpi_bus_get_status(device) || !device->status.present)
                return -ENODEV;
 
+       if (sdhci_acpi_byt_defer(dev))
+               return -EPROBE_DEFER;
+
        hid = acpi_device_hid(device);
        uid = device->pnp.unique_id;
 
@@ -460,6 +537,8 @@ static int sdhci_acpi_resume(struct device *dev)
 {
        struct sdhci_acpi_host *c = dev_get_drvdata(dev);
 
+       sdhci_acpi_byt_setting(&c->pdev->dev);
+
        return sdhci_resume_host(c->host);
 }
 
@@ -483,6 +562,8 @@ static int sdhci_acpi_runtime_resume(struct device *dev)
 {
        struct sdhci_acpi_host *c = dev_get_drvdata(dev);
 
+       sdhci_acpi_byt_setting(&c->pdev->dev);
+
        return sdhci_runtime_resume_host(c->host);
 }
 
index 8de66ef259880133ea89d7e9658e0adb99701e17..d1a07558166959b09d8475f9d4ead3247ca3bf59 100644 (file)
@@ -492,7 +492,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                host->align_buffer, host->align_buffer_sz, direction);
        if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
                goto fail;
-       BUG_ON(host->align_addr & host->align_mask);
+       BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
 
        host->sg_count = sdhci_pre_dma_transfer(host, data);
        if (host->sg_count < 0)
@@ -514,8 +514,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                 * the (up to three) bytes that screw up the
                 * alignment.
                 */
-               offset = (host->align_sz - (addr & host->align_mask)) &
-                        host->align_mask;
+               offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
+                        SDHCI_ADMA2_MASK;
                if (offset) {
                        if (data->flags & MMC_DATA_WRITE) {
                                buffer = sdhci_kmap_atomic(sg, &flags);
@@ -529,8 +529,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
                        BUG_ON(offset > 65536);
 
-                       align += host->align_sz;
-                       align_addr += host->align_sz;
+                       align += SDHCI_ADMA2_ALIGN;
+                       align_addr += SDHCI_ADMA2_ALIGN;
 
                        desc += host->desc_sz;
 
@@ -611,7 +611,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        /* Do a quick scan of the SG list for any unaligned mappings */
        has_unaligned = false;
        for_each_sg(data->sg, sg, host->sg_count, i)
-               if (sg_dma_address(sg) & host->align_mask) {
+               if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
                        has_unaligned = true;
                        break;
                }
@@ -623,15 +623,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                align = host->align_buffer;
 
                for_each_sg(data->sg, sg, host->sg_count, i) {
-                       if (sg_dma_address(sg) & host->align_mask) {
-                               size = host->align_sz -
-                                      (sg_dma_address(sg) & host->align_mask);
+                       if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+                               size = SDHCI_ADMA2_ALIGN -
+                                      (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
 
                                buffer = sdhci_kmap_atomic(sg, &flags);
                                memcpy(buffer, align, size);
                                sdhci_kunmap_atomic(buffer, &flags);
 
-                               align += host->align_sz;
+                               align += SDHCI_ADMA2_ALIGN;
                        }
                }
        }
@@ -675,7 +675,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
                         * host->clock is in Hz.  target_timeout is in us.
                         * Hence, us = 1000000 * cycles / Hz.  Round up.
                         */
-                       val = 1000000 * data->timeout_clks;
+                       val = 1000000ULL * data->timeout_clks;
                        if (do_div(val, host->clock))
                                target_timeout++;
                        target_timeout += val;
@@ -1315,7 +1315,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                        pwr = SDHCI_POWER_330;
                        break;
                default:
-                       BUG();
+                       WARN(1, "%s: Invalid vdd %#x\n",
+                            mmc_hostname(host->mmc), vdd);
+                       break;
                }
        }
 
@@ -2981,24 +2983,17 @@ int sdhci_add_host(struct sdhci_host *host)
                if (host->flags & SDHCI_USE_64_BIT_DMA) {
                        host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
                                              SDHCI_ADMA2_64_DESC_SZ;
-                       host->align_buffer_sz = SDHCI_MAX_SEGS *
-                                               SDHCI_ADMA2_64_ALIGN;
                        host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
-                       host->align_sz = SDHCI_ADMA2_64_ALIGN;
-                       host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
                } else {
                        host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
                                              SDHCI_ADMA2_32_DESC_SZ;
-                       host->align_buffer_sz = SDHCI_MAX_SEGS *
-                                               SDHCI_ADMA2_32_ALIGN;
                        host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
-                       host->align_sz = SDHCI_ADMA2_32_ALIGN;
-                       host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
                }
                host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
                                                      host->adma_table_sz,
                                                      &host->adma_addr,
                                                      GFP_KERNEL);
+               host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
                host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
                if (!host->adma_table || !host->align_buffer) {
                        if (host->adma_table)
@@ -3012,7 +3007,7 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->flags &= ~SDHCI_USE_ADMA;
                        host->adma_table = NULL;
                        host->align_buffer = NULL;
-               } else if (host->adma_addr & host->align_mask) {
+               } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) {
                        pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
index 9c331ac5ad6b0d8a6b9b88c7ef1de6b966989bc2..0115e9907bf8243aa394de60ac959e5876d5a3a9 100644 (file)
 /* ADMA2 32-bit DMA descriptor size */
 #define SDHCI_ADMA2_32_DESC_SZ 8
 
-/* ADMA2 32-bit DMA alignment */
-#define SDHCI_ADMA2_32_ALIGN   4
-
 /* ADMA2 32-bit descriptor */
 struct sdhci_adma2_32_desc {
        __le16  cmd;
        __le16  len;
        __le32  addr;
-}  __packed __aligned(SDHCI_ADMA2_32_ALIGN);
+}  __packed __aligned(4);
+
+/* ADMA2 data alignment */
+#define SDHCI_ADMA2_ALIGN      4
+#define SDHCI_ADMA2_MASK       (SDHCI_ADMA2_ALIGN - 1)
+
+/*
+ * ADMA2 descriptor alignment.  Some controllers (e.g. Intel) require 8 byte
+ * alignment for the descriptor table even in 32-bit DMA mode.  Memory
+ * allocation is at least 8 byte aligned anyway, so just stipulate 8 always.
+ */
+#define SDHCI_ADMA2_DESC_ALIGN 8
 
 /* ADMA2 64-bit DMA descriptor size */
 #define SDHCI_ADMA2_64_DESC_SZ 12
 
-/* ADMA2 64-bit DMA alignment */
-#define SDHCI_ADMA2_64_ALIGN   8
-
 /*
  * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
  * aligned.
@@ -483,8 +488,6 @@ struct sdhci_host {
        dma_addr_t align_addr;  /* Mapped bounce buffer */
 
        unsigned int desc_sz;   /* ADMA descriptor size */
-       unsigned int align_sz;  /* ADMA alignment */
-       unsigned int align_mask;        /* ADMA alignment mask */
 
        struct tasklet_struct finish_tasklet;   /* Tasklet structures */
 
index 744ca5cacc9b2e8b6f10189dc169f29426cad9e9..f9fa3fad728e5e3b0687c5affadd7cf8d0b129b0 100644 (file)
@@ -75,15 +75,15 @@ static int __init init_msp_flash(void)
 
        printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
 
-       msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+       msp_flash = kcalloc(fcnt, sizeof(*msp_flash), GFP_KERNEL);
        if (!msp_flash)
                return -ENOMEM;
 
-       msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+       msp_parts = kcalloc(fcnt, sizeof(*msp_parts), GFP_KERNEL);
        if (!msp_parts)
                goto free_msp_flash;
 
-       msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
+       msp_maps = kcalloc(fcnt, sizeof(*msp_maps), GFP_KERNEL);
        if (!msp_maps)
                goto free_msp_parts;
 
index 142fc3d794637366cc4a4996b5e07f882d14b7a2..784c6e1a0391e92c90723e698d8bc148fe3e4916 100644 (file)
@@ -230,8 +230,10 @@ static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
 
                info->mtd = mtd_concat_create(cdev, info->num_subdev,
                                              plat->name);
-               if (info->mtd == NULL)
+               if (info->mtd == NULL) {
                        ret = -ENXIO;
+                       goto err;
+               }
        }
        info->mtd->dev.parent = &pdev->dev;
 
index c72313d66cf6a0d3034ba82d519a3bd315d21c59..bc054a5ed7f8cb6b419b3df884915ce584e9dbdd 100644 (file)
@@ -241,6 +241,9 @@ static void nand_davinci_hwctl_4bit(struct mtd_info *mtd, int mode)
        unsigned long flags;
        u32 val;
 
+       /* Reset ECC hardware */
+       davinci_nand_readl(info, NAND_4BIT_ECC1_OFFSET);
+
        spin_lock_irqsave(&davinci_nand_lock, flags);
 
        /* Start 4-bit ECC calculation for read/write */
index ce7b2cab5762e5854cc4a11175876a53162e6215..54ab48827258b138a3833fd664df8ccfe29bd5db 100644 (file)
@@ -2586,7 +2586,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                int cached = writelen > bytes && page != blockmask;
                uint8_t *wbuf = buf;
                int use_bufpoi;
-               int part_pagewr = (column || writelen < (mtd->writesize - 1));
+               int part_pagewr = (column || writelen < mtd->writesize);
 
                if (part_pagewr)
                        use_bufpoi = 1;
index 22fd19c0c5d3fa56d0a4b84fa508973d96dcc8ff..27de0463226efb6709eca6dae396c6dbb30128b4 100644 (file)
@@ -869,7 +869,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
        for (i = 0; i < UBI_MAX_DEVICES; i++) {
                ubi = ubi_devices[i];
                if (ubi && mtd->index == ubi->mtd->index) {
-                       ubi_err(ubi, "mtd%d is already attached to ubi%d",
+                       pr_err("ubi: mtd%d is already attached to ubi%d",
                                mtd->index, i);
                        return -EEXIST;
                }
@@ -884,7 +884,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
         * no sense to attach emulated MTD devices, so we prohibit this.
         */
        if (mtd->type == MTD_UBIVOLUME) {
-               ubi_err(ubi, "refuse attaching mtd%d - it is already emulated on top of UBI",
+               pr_err("ubi: refuse attaching mtd%d - it is already emulated on top of UBI",
                        mtd->index);
                return -EINVAL;
        }
@@ -895,7 +895,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
                        if (!ubi_devices[ubi_num])
                                break;
                if (ubi_num == UBI_MAX_DEVICES) {
-                       ubi_err(ubi, "only %d UBI devices may be created",
+                       pr_err("ubi: only %d UBI devices may be created",
                                UBI_MAX_DEVICES);
                        return -ENFILE;
                }
@@ -905,7 +905,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
 
                /* Make sure ubi_num is not busy */
                if (ubi_devices[ubi_num]) {
-                       ubi_err(ubi, "already exists");
+                       pr_err("ubi: ubi%i already exists", ubi_num);
                        return -EEXIST;
                }
        }
@@ -987,6 +987,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
                        goto out_detach;
        }
 
+       /* Make device "available" before it becomes accessible via sysfs */
+       ubi_devices[ubi_num] = ubi;
+
        err = uif_init(ubi, &ref);
        if (err)
                goto out_detach;
@@ -1031,7 +1034,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
        wake_up_process(ubi->bgt_thread);
        spin_unlock(&ubi->wl_lock);
 
-       ubi_devices[ubi_num] = ubi;
        ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
        return ubi_num;
 
@@ -1042,6 +1044,7 @@ out_uif:
        ubi_assert(ref);
        uif_close(ubi);
 out_detach:
+       ubi_devices[ubi_num] = NULL;
        ubi_wl_close(ubi);
        ubi_free_internal_volumes(ubi);
        vfree(ubi->vtbl);
index 1ae17bb9b88946ca7666938646c111e564d9a4a3..3ea4c022cbb9cd136a0746beabf240cc1f94ef0f 100644 (file)
@@ -488,13 +488,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                spin_unlock(&ubi->volumes_lock);
        }
 
-       /* Change volume table record */
-       vtbl_rec = ubi->vtbl[vol_id];
-       vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
-       err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
-       if (err)
-               goto out_acc;
-
        if (pebs < 0) {
                for (i = 0; i < -pebs; i++) {
                        err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
@@ -512,6 +505,24 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                spin_unlock(&ubi->volumes_lock);
        }
 
+       /*
+        * When we shrink a volume we have to flush all pending (erase) work.
+        * Otherwise it can happen that upon next attach UBI finds a LEB with
+        * lnum > highest_lnum and refuses to attach.
+        */
+       if (pebs < 0) {
+               err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
+               if (err)
+                       goto out_acc;
+       }
+
+       /* Change volume table record */
+       vtbl_rec = ubi->vtbl[vol_id];
+       vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
+       err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+       if (err)
+               goto out_acc;
+
        vol->reserved_pebs = reserved_pebs;
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = reserved_pebs;
index 56065632a5b85ebf50022f883e1edc968a069f93..75286588b82341110afd31f62e202422b896aaea 100644 (file)
@@ -643,7 +643,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                                int shutdown)
 {
        int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
-       int vol_id = -1, lnum = -1;
+       int erase = 0, keep = 0, vol_id = -1, lnum = -1;
 #ifdef CONFIG_MTD_UBI_FASTMAP
        int anchor = wrk->anchor;
 #endif
@@ -777,6 +777,16 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                               e1->pnum);
                        scrubbing = 1;
                        goto out_not_moved;
+               } else if (ubi->fast_attach && err == UBI_IO_BAD_HDR_EBADMSG) {
+                       /*
+                        * While a full scan would detect interrupted erasures
+                        * at attach time we can face them here when attached from
+                        * Fastmap.
+                        */
+                       dbg_wl("PEB %d has ECC errors, maybe from an interrupted erasure",
+                              e1->pnum);
+                       erase = 1;
+                       goto out_not_moved;
                }
 
                ubi_err(ubi, "error %d while reading VID header from PEB %d",
@@ -810,6 +820,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                         * Target PEB had bit-flips or write error - torture it.
                         */
                        torture = 1;
+                       keep = 1;
                        goto out_not_moved;
                }
 
@@ -895,7 +906,7 @@ out_not_moved:
                ubi->erroneous_peb_count += 1;
        } else if (scrubbing)
                wl_tree_add(e1, &ubi->scrub);
-       else
+       else if (keep)
                wl_tree_add(e1, &ubi->used);
        ubi_assert(!ubi->move_to_put);
        ubi->move_from = ubi->move_to = NULL;
@@ -907,6 +918,12 @@ out_not_moved:
        if (err)
                goto out_ro;
 
+       if (erase) {
+               err = do_sync_erase(ubi, e1, vol_id, lnum, 1);
+               if (err)
+                       goto out_ro;
+       }
+
        mutex_unlock(&ubi->move_mutex);
        return 0;
 
index b3d70a7a52620ff8d228b3b1a96a7f89fab081b3..5dca77e0ffed19879311b2d183b797a78927f1ec 100644 (file)
@@ -1317,9 +1317,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                            slave_dev->name);
        }
 
-       /* already enslaved */
-       if (slave_dev->flags & IFF_SLAVE) {
-               netdev_dbg(bond_dev, "Error: Device was already enslaved\n");
+       /* already in-use? */
+       if (netdev_is_rx_handler_busy(slave_dev)) {
+               netdev_err(bond_dev,
+                          "Error: Device is in use and cannot be enslaved\n");
                return -EBUSY;
        }
 
index db760e84119fcb970b7b34f7c4fac92b1acfed52..b8df0f5e8c25ae35b1ce368b04536c40761a1c96 100644 (file)
@@ -446,7 +446,11 @@ static int bond_newlink(struct net *src_net, struct net_device *bond_dev,
        if (err < 0)
                return err;
 
-       return register_netdevice(bond_dev);
+       err = register_netdevice(bond_dev);
+
+       netif_carrier_off(bond_dev);
+
+       return err;
 }
 
 static size_t bond_get_size(const struct net_device *bond_dev)
index 8b3275d7792acbab2d0ba9efe9fe3e2a6b283231..8f5e93cb79752703c141704011490535664b941e 100644 (file)
@@ -712,9 +712,10 @@ static int at91_poll_rx(struct net_device *dev, int quota)
 
        /* upper group completed, look again in lower */
        if (priv->rx_next > get_mb_rx_low_last(priv) &&
-           quota > 0 && mb > get_mb_rx_last(priv)) {
+           mb > get_mb_rx_last(priv)) {
                priv->rx_next = get_mb_rx_first(priv);
-               goto again;
+               if (quota > 0)
+                       goto again;
        }
 
        return received;
index f91b094288dad3d86064f24a33a97ad58756f3ca..e3dccd3200d5d834f13ad036c290c51e3091052e 100644 (file)
@@ -332,9 +332,23 @@ static void c_can_setup_tx_object(struct net_device *dev, int iface,
 
        priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), ctrl);
 
-       for (i = 0; i < frame->can_dlc; i += 2) {
-               priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
-                               frame->data[i] | (frame->data[i + 1] << 8));
+       if (priv->type == BOSCH_D_CAN) {
+               u32 data = 0, dreg = C_CAN_IFACE(DATA1_REG, iface);
+
+               for (i = 0; i < frame->can_dlc; i += 4, dreg += 2) {
+                       data = (u32)frame->data[i];
+                       data |= (u32)frame->data[i + 1] << 8;
+                       data |= (u32)frame->data[i + 2] << 16;
+                       data |= (u32)frame->data[i + 3] << 24;
+                       priv->write_reg32(priv, dreg, data);
+               }
+       } else {
+               for (i = 0; i < frame->can_dlc; i += 2) {
+                       priv->write_reg(priv,
+                                       C_CAN_IFACE(DATA1_REG, iface) + i / 2,
+                                       frame->data[i] |
+                                       (frame->data[i + 1] << 8));
+               }
        }
 }
 
@@ -402,10 +416,20 @@ static int c_can_read_msg_object(struct net_device *dev, int iface, u32 ctrl)
        } else {
                int i, dreg = C_CAN_IFACE(DATA1_REG, iface);
 
-               for (i = 0; i < frame->can_dlc; i += 2, dreg ++) {
-                       data = priv->read_reg(priv, dreg);
-                       frame->data[i] = data;
-                       frame->data[i + 1] = data >> 8;
+               if (priv->type == BOSCH_D_CAN) {
+                       for (i = 0; i < frame->can_dlc; i += 4, dreg += 2) {
+                               data = priv->read_reg32(priv, dreg);
+                               frame->data[i] = data;
+                               frame->data[i + 1] = data >> 8;
+                               frame->data[i + 2] = data >> 16;
+                               frame->data[i + 3] = data >> 24;
+                       }
+               } else {
+                       for (i = 0; i < frame->can_dlc; i += 2, dreg++) {
+                               data = priv->read_reg(priv, dreg);
+                               frame->data[i] = data;
+                               frame->data[i + 1] = data >> 8;
+                       }
                }
        }
 
index 910c12e2638e3615084ca9f6a148030c8f2358e1..eab132778e67241cc5ba2a436af2c338cfef61b9 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
+#include <linux/workqueue.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/skb.h>
@@ -471,9 +472,8 @@ EXPORT_SYMBOL_GPL(can_free_echo_skb);
 /*
  * CAN device restart for bus-off recovery
  */
-static void can_restart(unsigned long data)
+static void can_restart(struct net_device *dev)
 {
-       struct net_device *dev = (struct net_device *)data;
        struct can_priv *priv = netdev_priv(dev);
        struct net_device_stats *stats = &dev->stats;
        struct sk_buff *skb;
@@ -513,6 +513,14 @@ restart:
                netdev_err(dev, "Error %d during restart", err);
 }
 
+static void can_restart_work(struct work_struct *work)
+{
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct can_priv *priv = container_of(dwork, struct can_priv, restart_work);
+
+       can_restart(priv->dev);
+}
+
 int can_restart_now(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
@@ -526,8 +534,8 @@ int can_restart_now(struct net_device *dev)
        if (priv->state != CAN_STATE_BUS_OFF)
                return -EBUSY;
 
-       /* Runs as soon as possible in the timer context */
-       mod_timer(&priv->restart_timer, jiffies);
+       cancel_delayed_work_sync(&priv->restart_work);
+       can_restart(dev);
 
        return 0;
 }
@@ -548,8 +556,8 @@ void can_bus_off(struct net_device *dev)
        netif_carrier_off(dev);
 
        if (priv->restart_ms)
-               mod_timer(&priv->restart_timer,
-                         jiffies + (priv->restart_ms * HZ) / 1000);
+               schedule_delayed_work(&priv->restart_work,
+                                     msecs_to_jiffies(priv->restart_ms));
 }
 EXPORT_SYMBOL_GPL(can_bus_off);
 
@@ -658,6 +666,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
                return NULL;
 
        priv = netdev_priv(dev);
+       priv->dev = dev;
 
        if (echo_skb_max) {
                priv->echo_skb_max = echo_skb_max;
@@ -667,7 +676,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
 
        priv->state = CAN_STATE_STOPPED;
 
-       init_timer(&priv->restart_timer);
+       INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
 
        return dev;
 }
@@ -748,8 +757,6 @@ int open_candev(struct net_device *dev)
        if (!netif_carrier_ok(dev))
                netif_carrier_on(dev);
 
-       setup_timer(&priv->restart_timer, can_restart, (unsigned long)dev);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(open_candev);
@@ -764,7 +771,7 @@ void close_candev(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
 
-       del_timer_sync(&priv->restart_timer);
+       cancel_delayed_work_sync(&priv->restart_work);
        can_flush_echo_skb(dev);
 }
 EXPORT_SYMBOL_GPL(close_candev);
@@ -798,6 +805,9 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[])
         * - control mode with CAN_CTRLMODE_FD set
         */
 
+       if (!data)
+               return 0;
+
        if (data[IFLA_CAN_CTRLMODE]) {
                struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
 
@@ -1008,6 +1018,11 @@ static int can_newlink(struct net *src_net, struct net_device *dev,
        return -EOPNOTSUPP;
 }
 
+static void can_dellink(struct net_device *dev, struct list_head *head)
+{
+       return;
+}
+
 static struct rtnl_link_ops can_link_ops __read_mostly = {
        .kind           = "can",
        .maxtype        = IFLA_CAN_MAX,
@@ -1016,6 +1031,7 @@ static struct rtnl_link_ops can_link_ops __read_mostly = {
        .validate       = can_validate,
        .newlink        = can_newlink,
        .changelink     = can_changelink,
+       .dellink        = can_dellink,
        .get_size       = can_get_size,
        .fill_info      = can_fill_info,
        .get_xstats_size = can_get_xstats_size,
index 41c0fc9f3b1465d9dbbde6b5c7798b1e40cf43ef..16f7cadda5c32b430c0d25aea9746a93a063bd39 100644 (file)
@@ -1268,11 +1268,10 @@ static int __maybe_unused flexcan_suspend(struct device *device)
        struct flexcan_priv *priv = netdev_priv(dev);
        int err;
 
-       err = flexcan_chip_disable(priv);
-       if (err)
-               return err;
-
        if (netif_running(dev)) {
+               err = flexcan_chip_disable(priv);
+               if (err)
+                       return err;
                netif_stop_queue(dev);
                netif_device_detach(dev);
        }
@@ -1285,13 +1284,17 @@ static int __maybe_unused flexcan_resume(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
        if (netif_running(dev)) {
                netif_device_attach(dev);
                netif_start_queue(dev);
+               err = flexcan_chip_enable(priv);
+               if (err)
+                       return err;
        }
-       return flexcan_chip_enable(priv);
+       return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
index 6bba1c98d764cf2b4222c82211677e30c448a4f0..c7994e37228438b664098bad041a5ae4f808fd01 100644 (file)
@@ -187,8 +187,8 @@ static inline void name##_writeq(struct bcm_sf2_priv *priv, u64 val,        \
 static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
                                                u32 mask)               \
 {                                                                      \
-       intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);     \
        priv->irq##which##_mask &= ~(mask);                             \
+       intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);     \
 }                                                                      \
 static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
                                                u32 mask)               \
index 28f7610b03febf79e11056308f3a4e3695274bf6..c32f5d32f81187d5ca4e6baba780f8eca142d632 100644 (file)
@@ -219,7 +219,7 @@ err_dma:
        dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
                         DMA_TO_DEVICE);
 
-       while (i > 0) {
+       while (i-- > 0) {
                int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
                struct bgmac_slot_info *slot = &ring->slots[index];
                u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
index 2e611dc5f16210393852110c7dda5dadf4dfc560..1c8123816745b81bc479ef52c3af123962d5319d 100644 (file)
@@ -14819,6 +14819,10 @@ static int bnx2x_get_fc_npiv(struct net_device *dev,
        }
 
        offset = SHMEM2_RD(bp, fc_npiv_nvram_tbl_addr[BP_PORT(bp)]);
+       if (!offset) {
+               DP(BNX2X_MSG_MCP, "No FC-NPIV in NVRAM\n");
+               goto out;
+       }
        DP(BNX2X_MSG_MCP, "Offset of FC-NPIV in NVRAM: %08x\n", offset);
 
        /* Read the table contents from nvram */
index b89504405b7207f12663aee0d6d3ecf78d392235..7445da218bd98e2359826ff54e36e4e25ff576e6 100644 (file)
@@ -2526,7 +2526,7 @@ static void handle_timestamp(struct octeon_device *oct,
 
        octeon_swap_8B_data(&resp->timestamp, 1);
 
-       if (unlikely((skb_shinfo(skb)->tx_flags | SKBTX_IN_PROGRESS) != 0)) {
+       if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) != 0)) {
                struct skb_shared_hwtstamps ts;
                u64 ns = resp->timestamp;
 
index 39ca6744a4e68fe317f93e1318e729509c1b978e..22471d283a952ad6b43115badf339acd3a0c3418 100644 (file)
 #define NIC_PF_INTR_ID_MBOX0           8
 #define NIC_PF_INTR_ID_MBOX1           9
 
+/* Minimum FIFO level before all packets for the CQ are dropped
+ *
+ * This value ensures that once a packet has been "accepted"
+ * for reception it will not get dropped due to non-availability
+ * of CQ descriptor. An errata in HW mandates this value to be
+ * atleast 0x100.
+ */
+#define NICPF_CQM_MIN_DROP_LEVEL       0x100
+
 /* Global timer for CQ timer thresh interrupts
  * Calculated for SCLK of 700Mhz
  * value written should be a 1/16th of what is expected
index 5f24d11cb16aad5ae6bd474d538053ac6465c868..16baaafed26c31523f61b43684d28c2c4a648544 100644 (file)
@@ -309,6 +309,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic)
 static void nic_init_hw(struct nicpf *nic)
 {
        int i;
+       u64 cqm_cfg;
 
        /* Enable NIC HW block */
        nic_reg_write(nic, NIC_PF_CFG, 0x3);
@@ -345,6 +346,11 @@ static void nic_init_hw(struct nicpf *nic)
        /* Enable VLAN ethertype matching and stripping */
        nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
                      (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q);
+
+       /* Check if HW expected value is higher (could be in future chips) */
+       cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG);
+       if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL)
+               nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL);
 }
 
 /* Channel parse index configuration */
index dd536be20193119c3465cd772a4bff6d649e3319..fab35a5938987c757f5faa2cbf808d7f28c05922 100644 (file)
@@ -21,7 +21,7 @@
 #define   NIC_PF_TCP_TIMER                     (0x0060)
 #define   NIC_PF_BP_CFG                                (0x0080)
 #define   NIC_PF_RRM_CFG                       (0x0088)
-#define   NIC_PF_CQM_CF                                (0x00A0)
+#define   NIC_PF_CQM_CFG                       (0x00A0)
 #define   NIC_PF_CNM_CF                                (0x00A8)
 #define   NIC_PF_CNM_STATUS                    (0x00B0)
 #define   NIC_PF_CQ_AVG_CFG                    (0x00C0)
 #define   NIC_QSET_SQ_0_7_DOOR                 (0x010838)
 #define   NIC_QSET_SQ_0_7_STATUS               (0x010840)
 #define   NIC_QSET_SQ_0_7_DEBUG                        (0x010848)
-#define   NIC_QSET_SQ_0_7_CNM_CHG              (0x010860)
 #define   NIC_QSET_SQ_0_7_STAT_0_1             (0x010900)
 
 #define   NIC_QSET_RBDR_0_1_CFG                        (0x010C00)
index a12b2e38cf61221fc4de44f6395eb60de76825a5..ff1d777f3ed98af0a33c5dcc997ed9edb62254a8 100644 (file)
@@ -380,7 +380,10 @@ static void nicvf_get_regs(struct net_device *dev,
                p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DOOR, q);
                p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STATUS, q);
                p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_DEBUG, q);
-               p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_CNM_CHG, q);
+               /* Padding, was NIC_QSET_SQ_0_7_CNM_CHG, which
+                * produces bus errors when read
+                */
+               p[i++] = 0;
                p[i++] = nicvf_queue_reg_read(nic, NIC_QSET_SQ_0_7_STAT_0_1, q);
                reg_offset = NIC_QSET_SQ_0_7_STAT_0_1 | (1 << 3);
                p[i++] = nicvf_queue_reg_read(nic, reg_offset, q);
index dde8dc720cd3f3b7d513776662a4f05b1241486d..b7093b9cd1e859e27f6fb4087ce0b14ed9a79e12 100644 (file)
@@ -566,8 +566,7 @@ static inline void nicvf_set_rxhash(struct net_device *netdev,
 
 static void nicvf_rcv_pkt_handler(struct net_device *netdev,
                                  struct napi_struct *napi,
-                                 struct cmp_queue *cq,
-                                 struct cqe_rx_t *cqe_rx, int cqe_type)
+                                 struct cqe_rx_t *cqe_rx)
 {
        struct sk_buff *skb;
        struct nicvf *nic = netdev_priv(netdev);
@@ -583,7 +582,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
        }
 
        /* Check for errors */
-       err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx);
+       err = nicvf_check_cqe_rx_errs(nic, cqe_rx);
        if (err && !cqe_rx->rb_cnt)
                return;
 
@@ -674,8 +673,7 @@ loop:
                           cq_idx, cq_desc->cqe_type);
                switch (cq_desc->cqe_type) {
                case CQE_TYPE_RX:
-                       nicvf_rcv_pkt_handler(netdev, napi, cq,
-                                             cq_desc, CQE_TYPE_RX);
+                       nicvf_rcv_pkt_handler(netdev, napi, cq_desc);
                        work_done++;
                break;
                case CQE_TYPE_SEND:
@@ -1117,7 +1115,6 @@ int nicvf_stop(struct net_device *netdev)
 
        /* Clear multiqset info */
        nic->pnicvf = nic;
-       nic->sqs_count = 0;
 
        return 0;
 }
@@ -1346,6 +1343,9 @@ void nicvf_update_stats(struct nicvf *nic)
        drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +
                                  stats->tx_bcast_frames_ok +
                                  stats->tx_mcast_frames_ok;
+       drv_stats->rx_frames_ok = stats->rx_ucast_frames +
+                                 stats->rx_bcast_frames +
+                                 stats->rx_mcast_frames;
        drv_stats->rx_drops = stats->rx_drop_red +
                              stats->rx_drop_overrun;
        drv_stats->tx_drops = stats->tx_drops;
index d1c217eaf4171803ec48e2fcee5685627cabaffb..912ee28ab58ba32436acd1f3c7bd26f0a55fcfc1 100644 (file)
@@ -1414,16 +1414,12 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
 }
 
 /* Check for errors in the receive cmp.queue entry */
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
-                           struct cmp_queue *cq, struct cqe_rx_t *cqe_rx)
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 {
        struct nicvf_hw_stats *stats = &nic->hw_stats;
-       struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
 
-       if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
-               drv_stats->rx_frames_ok++;
+       if (!cqe_rx->err_level && !cqe_rx->err_opcode)
                return 0;
-       }
 
        if (netif_msg_rx_err(nic))
                netdev_err(nic->netdev,
index 033e8306e91c6942862ffe9dae0ca3836a8228f5..5652c612e20bb255763382a341d6c2530e937d6f 100644 (file)
@@ -344,8 +344,7 @@ u64  nicvf_queue_reg_read(struct nicvf *nic,
 /* Stats */
 void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
 void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
-                           struct cmp_queue *cq, struct cqe_rx_t *cqe_rx);
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
 int nicvf_check_cqe_tx_errs(struct nicvf *nic,
                            struct cmp_queue *cq, struct cqe_send_t *cqe_tx);
 #endif /* NICVF_QUEUES_H */
index 9df26c2263bcc37bdfced23e2db688c151942733..42718cc7d4e8148aa0d15c9ecae4bf1790d131f0 100644 (file)
@@ -549,7 +549,9 @@ static int bgx_xaui_check_link(struct lmac *lmac)
        }
 
        /* Clear rcvflt bit (latching high) and read it back */
-       bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
+       if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT)
+               bgx_reg_modify(bgx, lmacid,
+                              BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
        if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
                dev_err(&bgx->pdev->dev, "Receive fault, retry training\n");
                if (bgx->use_training) {
@@ -568,13 +570,6 @@ static int bgx_xaui_check_link(struct lmac *lmac)
                return -1;
        }
 
-       /* Wait for MAC RX to be ready */
-       if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_RX_CTL,
-                        SMU_RX_CTL_STATUS, true)) {
-               dev_err(&bgx->pdev->dev, "SMU RX link not okay\n");
-               return -1;
-       }
-
        /* Wait for BGX RX to be idle */
        if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL, SMU_CTL_RX_IDLE, false)) {
                dev_err(&bgx->pdev->dev, "SMU RX not idle\n");
@@ -587,29 +582,30 @@ static int bgx_xaui_check_link(struct lmac *lmac)
                return -1;
        }
 
-       if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
-               dev_err(&bgx->pdev->dev, "Receive fault\n");
-               return -1;
-       }
-
-       /* Receive link is latching low. Force it high and verify it */
-       bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS1, SPU_STATUS1_RCV_LNK);
-       if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_STATUS1,
-                        SPU_STATUS1_RCV_LNK, false)) {
-               dev_err(&bgx->pdev->dev, "SPU receive link down\n");
-               return -1;
-       }
-
+       /* Clear receive packet disable */
        cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
        cfg &= ~SPU_MISC_CTL_RX_DIS;
        bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
-       return 0;
+
+       /* Check for MAC RX faults */
+       cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_CTL);
+       /* 0 - Link is okay, 1 - Local fault, 2 - Remote fault */
+       cfg &= SMU_RX_CTL_STATUS;
+       if (!cfg)
+               return 0;
+
+       /* Rx local/remote fault seen.
+        * Do lmac reinit to see if condition recovers
+        */
+       bgx_lmac_xaui_init(bgx, lmacid, bgx->lmac_type);
+
+       return -1;
 }
 
 static void bgx_poll_for_link(struct work_struct *work)
 {
        struct lmac *lmac;
-       u64 link;
+       u64 spu_link, smu_link;
 
        lmac = container_of(work, struct lmac, dwork.work);
 
@@ -619,8 +615,11 @@ static void bgx_poll_for_link(struct work_struct *work)
        bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1,
                     SPU_STATUS1_RCV_LNK, false);
 
-       link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1);
-       if (link & SPU_STATUS1_RCV_LNK) {
+       spu_link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1);
+       smu_link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SMUX_RX_CTL);
+
+       if ((spu_link & SPU_STATUS1_RCV_LNK) &&
+           !(smu_link & SMU_RX_CTL_STATUS)) {
                lmac->link_up = 1;
                if (lmac->bgx->lmac_type == BGX_MODE_XLAUI)
                        lmac->last_speed = 40000;
@@ -634,9 +633,15 @@ static void bgx_poll_for_link(struct work_struct *work)
        }
 
        if (lmac->last_link != lmac->link_up) {
+               if (lmac->link_up) {
+                       if (bgx_xaui_check_link(lmac)) {
+                               /* Errors, clear link_up state */
+                               lmac->link_up = 0;
+                               lmac->last_speed = SPEED_UNKNOWN;
+                               lmac->last_duplex = DUPLEX_UNKNOWN;
+                       }
+               }
                lmac->last_link = lmac->link_up;
-               if (lmac->link_up)
-                       bgx_xaui_check_link(lmac);
        }
 
        queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 2);
@@ -708,7 +713,7 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
 static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
 {
        struct lmac *lmac;
-       u64 cmrx_cfg;
+       u64 cfg;
 
        lmac = &bgx->lmac[lmacid];
        if (lmac->check_link) {
@@ -717,9 +722,33 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
                destroy_workqueue(lmac->check_link);
        }
 
-       cmrx_cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
-       cmrx_cfg &= ~(1 << 15);
-       bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
+       /* Disable packet reception */
+       cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+       cfg &= ~CMR_PKT_RX_EN;
+       bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
+       /* Give chance for Rx/Tx FIFO to get drained */
+       bgx_poll_reg(bgx, lmacid, BGX_CMRX_RX_FIFO_LEN, (u64)0x1FFF, true);
+       bgx_poll_reg(bgx, lmacid, BGX_CMRX_TX_FIFO_LEN, (u64)0x3FFF, true);
+
+       /* Disable packet transmission */
+       cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+       cfg &= ~CMR_PKT_TX_EN;
+       bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
+       /* Disable serdes lanes */
+        if (!lmac->is_sgmii)
+                bgx_reg_modify(bgx, lmacid,
+                               BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
+        else
+                bgx_reg_modify(bgx, lmacid,
+                               BGX_GMP_PCS_MRX_CTL, PCS_MRX_CTL_PWR_DN);
+
+       /* Disable LMAC */
+       cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+       cfg &= ~CMR_EN;
+       bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+
        bgx_flush_dmac_addrs(bgx, lmacid);
 
        if ((bgx->lmac_type != BGX_MODE_XFI) &&
index 149e179363a1e6dd71e0b7cbd00f26a5e5ef0116..42010d2e5ddf4e3d46eab4b2c9cee6caac5e252a 100644 (file)
@@ -41,6 +41,7 @@
 #define BGX_CMRX_RX_STAT10             0xC0
 #define BGX_CMRX_RX_BP_DROP            0xC8
 #define BGX_CMRX_RX_DMAC_CTL           0x0E8
+#define BGX_CMRX_RX_FIFO_LEN           0x108
 #define BGX_CMR_RX_DMACX_CAM           0x200
 #define  RX_DMACX_CAM_EN                       BIT_ULL(48)
 #define  RX_DMACX_CAM_LMACID(x)                        (x << 49)
@@ -50,6 +51,7 @@
 #define BGX_CMR_CHAN_MSK_AND           0x450
 #define BGX_CMR_BIST_STATUS            0x460
 #define BGX_CMR_RX_LMACS               0x468
+#define BGX_CMRX_TX_FIFO_LEN           0x518
 #define BGX_CMRX_TX_STAT0              0x600
 #define BGX_CMRX_TX_STAT1              0x608
 #define BGX_CMRX_TX_STAT2              0x610
index 69707108d23cdeb57bda5c6dd5e3e1aa29faa2b6..98fe5a2cd6e3e1020ac1c346c63e6a21a5a6832a 100644 (file)
@@ -213,8 +213,11 @@ struct e1000_rx_ring {
 };
 
 #define E1000_DESC_UNUSED(R)                                           \
-       ((((R)->next_to_clean > (R)->next_to_use)                       \
-         ? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
+({                                                                     \
+       unsigned int clean = smp_load_acquire(&(R)->next_to_clean);     \
+       unsigned int use = READ_ONCE((R)->next_to_use);                 \
+       (clean > use ? 0 : (R)->count) + clean - use - 1;               \
+})
 
 #define E1000_RX_DESC_EXT(R, i)                                                \
        (&(((union e1000_rx_desc_extended *)((R).desc))[i]))
index fd7be860c20131e7db9a557dcdd40db348d9edf5..068023595d8439c5b1264a105828ba80d3a54309 100644 (file)
@@ -3876,7 +3876,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
                eop_desc = E1000_TX_DESC(*tx_ring, eop);
        }
 
-       tx_ring->next_to_clean = i;
+       /* Synchronize with E1000_DESC_UNUSED called from e1000_xmit_frame,
+        * which will reuse the cleaned buffers.
+        */
+       smp_store_release(&tx_ring->next_to_clean, i);
 
        netdev_completed_queue(netdev, pkts_compl, bytes_compl);
 
index 0a854a47d31a77ef0723231dd75e3aceddc5d6b0..80ec587d510efeeeb758d8566db3cfbe9ec2acb1 100644 (file)
@@ -1959,8 +1959,10 @@ static irqreturn_t e1000_intr_msix_rx(int __always_unused irq, void *data)
         * previous interrupt.
         */
        if (rx_ring->set_itr) {
-               writel(1000000000 / (rx_ring->itr_val * 256),
-                      rx_ring->itr_register);
+               u32 itr = rx_ring->itr_val ?
+                         1000000000 / (rx_ring->itr_val * 256) : 0;
+
+               writel(itr, rx_ring->itr_register);
                rx_ring->set_itr = 0;
        }
 
index 14440200499b0300978caabc6d877a91f4ca91a9..48809e5d3f7975fcb2d825cf2be35f1a114b5491 100644 (file)
@@ -33,7 +33,7 @@
 #include "fm10k_pf.h"
 #include "fm10k_vf.h"
 
-#define FM10K_MAX_JUMBO_FRAME_SIZE     15358   /* Maximum supported size 15K */
+#define FM10K_MAX_JUMBO_FRAME_SIZE     15342   /* Maximum supported size 15K */
 
 #define MAX_QUEUES     FM10K_MAX_QUEUES_PF
 
index e76a44cf330cd47d57084a05fd69611985a79e15..09281558bfbcb8757d38a670babb44e6f41433b8 100644 (file)
@@ -1428,6 +1428,10 @@ static int fm10k_poll(struct napi_struct *napi, int budget)
        fm10k_for_each_ring(ring, q_vector->tx)
                clean_complete &= fm10k_clean_tx_irq(q_vector, ring);
 
+       /* Handle case where we are called by netpoll with a budget of 0 */
+       if (budget <= 0)
+               return budget;
+
        /* attempt to distribute budget to each queue fairly, but don't
         * allow the budget to go below 1 because we'll exit polling
         */
@@ -1966,8 +1970,10 @@ int fm10k_init_queueing_scheme(struct fm10k_intfc *interface)
 
        /* Allocate memory for queues */
        err = fm10k_alloc_q_vectors(interface);
-       if (err)
+       if (err) {
+               fm10k_reset_msix_capability(interface);
                return err;
+       }
 
        /* Map rings to devices, and map devices to physical queues */
        fm10k_assign_rings(interface);
index 74be792f3f1b7e0d31e729980b27c6602aeac263..7f3fb51bc37b59bc74bc71fc7bfb43ebca220a7b 100644 (file)
@@ -159,13 +159,30 @@ static void fm10k_reinit(struct fm10k_intfc *interface)
 
        fm10k_mbx_free_irq(interface);
 
+       /* free interrupts */
+       fm10k_clear_queueing_scheme(interface);
+
        /* delay any future reset requests */
        interface->last_reset = jiffies + (10 * HZ);
 
        /* reset and initialize the hardware so it is in a known state */
-       err = hw->mac.ops.reset_hw(hw) ? : hw->mac.ops.init_hw(hw);
-       if (err)
+       err = hw->mac.ops.reset_hw(hw);
+       if (err) {
+               dev_err(&interface->pdev->dev, "reset_hw failed: %d\n", err);
+               goto reinit_err;
+       }
+
+       err = hw->mac.ops.init_hw(hw);
+       if (err) {
                dev_err(&interface->pdev->dev, "init_hw failed: %d\n", err);
+               goto reinit_err;
+       }
+
+       err = fm10k_init_queueing_scheme(interface);
+       if (err) {
+               dev_err(&interface->pdev->dev, "init_queueing_scheme failed: %d\n", err);
+               goto reinit_err;
+       }
 
        /* reassociate interrupts */
        fm10k_mbx_request_irq(interface);
@@ -193,6 +210,10 @@ static void fm10k_reinit(struct fm10k_intfc *interface)
 
        fm10k_iov_resume(interface->pdev);
 
+reinit_err:
+       if (err)
+               netif_device_detach(netdev);
+
        rtnl_unlock();
 
        clear_bit(__FM10K_RESETTING, &interface->state);
@@ -1101,6 +1122,10 @@ void fm10k_mbx_free_irq(struct fm10k_intfc *interface)
        struct fm10k_hw *hw = &interface->hw;
        int itr_reg;
 
+       /* no mailbox IRQ to free if MSI-X is not enabled */
+       if (!interface->msix_entries)
+               return;
+
        /* disconnect the mailbox */
        hw->mbx.ops.disconnect(hw, &hw->mbx);
 
@@ -1423,10 +1448,15 @@ int fm10k_mbx_request_irq(struct fm10k_intfc *interface)
                err = fm10k_mbx_request_irq_pf(interface);
        else
                err = fm10k_mbx_request_irq_vf(interface);
+       if (err)
+               return err;
 
        /* connect mailbox */
-       if (!err)
-               err = hw->mbx.ops.connect(hw, &hw->mbx);
+       err = hw->mbx.ops.connect(hw, &hw->mbx);
+
+       /* if the mailbox failed to connect, then free IRQ */
+       if (err)
+               fm10k_mbx_free_irq(interface);
 
        return err;
 }
@@ -1684,7 +1714,13 @@ static int fm10k_sw_init(struct fm10k_intfc *interface,
        interface->last_reset = jiffies + (10 * HZ);
 
        /* reset and initialize the hardware so it is in a known state */
-       err = hw->mac.ops.reset_hw(hw) ? : hw->mac.ops.init_hw(hw);
+       err = hw->mac.ops.reset_hw(hw);
+       if (err) {
+               dev_err(&pdev->dev, "reset_hw failed: %d\n", err);
+               return err;
+       }
+
+       err = hw->mac.ops.init_hw(hw);
        if (err) {
                dev_err(&pdev->dev, "init_hw failed: %d\n", err);
                return err;
@@ -2071,8 +2107,10 @@ static int fm10k_resume(struct pci_dev *pdev)
 
        /* reset hardware to known state */
        err = hw->mac.ops.init_hw(&interface->hw);
-       if (err)
+       if (err) {
+               dev_err(&pdev->dev, "init_hw failed: %d\n", err);
                return err;
+       }
 
        /* reset statistics starting values */
        hw->mac.ops.rebind_hw_stats(hw, &interface->stats);
@@ -2185,6 +2223,9 @@ static pci_ers_result_t fm10k_io_error_detected(struct pci_dev *pdev,
        if (netif_running(netdev))
                fm10k_close(netdev);
 
+       /* free interrupts */
+       fm10k_clear_queueing_scheme(interface);
+
        fm10k_mbx_free_irq(interface);
 
        pci_disable_device(pdev);
@@ -2248,11 +2289,21 @@ static void fm10k_io_resume(struct pci_dev *pdev)
        int err = 0;
 
        /* reset hardware to known state */
-       hw->mac.ops.init_hw(&interface->hw);
+       err = hw->mac.ops.init_hw(&interface->hw);
+       if (err) {
+               dev_err(&pdev->dev, "init_hw failed: %d\n", err);
+               return;
+       }
 
        /* reset statistics starting values */
        hw->mac.ops.rebind_hw_stats(hw, &interface->stats);
 
+       err = fm10k_init_queueing_scheme(interface);
+       if (err) {
+               dev_err(&interface->pdev->dev, "init_queueing_scheme failed: %d\n", err);
+               return;
+       }
+
        /* reassociate interrupts */
        fm10k_mbx_request_irq(interface);
 
index 318a212f0a78e54e9705780b23a6ba3dd6ddba4b..35afd711d14460eb28c8a7c10e0120898b80a19c 100644 (file)
@@ -77,6 +77,7 @@ struct fm10k_hw;
 #define FM10K_PCIE_SRIOV_CTRL_VFARI            0x10
 
 #define FM10K_ERR_PARAM                                -2
+#define FM10K_ERR_NO_RESOURCES                 -3
 #define FM10K_ERR_REQUESTS_PENDING             -4
 #define FM10K_ERR_RESET_REQUESTED              -5
 #define FM10K_ERR_DMA_PENDING                  -6
index 36c8b0aa08fd2eeadfbc7b87ee5ce9d8d619b589..d512575c33f3b1d35525bdb197ac7b0e4e46fa42 100644 (file)
@@ -103,7 +103,14 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
        s32 err;
        u16 i;
 
-       /* assume we always have at least 1 queue */
+       /* verify we have at least 1 queue */
+       if (!~fm10k_read_reg(hw, FM10K_TXQCTL(0)) ||
+           !~fm10k_read_reg(hw, FM10K_RXQCTL(0))) {
+               err = FM10K_ERR_NO_RESOURCES;
+               goto reset_max_queues;
+       }
+
+       /* determine how many queues we have */
        for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) {
                /* verify the Descriptor cache offsets are increasing */
                tqdloc = ~fm10k_read_reg(hw, FM10K_TQDLOC(i));
@@ -119,7 +126,7 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
        /* shut down queues we own and reset DMA configuration */
        err = fm10k_disable_queues_generic(hw, i);
        if (err)
-               return err;
+               goto reset_max_queues;
 
        /* record maximum queue count */
        hw->mac.max_queues = i;
@@ -129,6 +136,11 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
                               FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
 
        return 0;
+
+reset_max_queues:
+       hw->mac.max_queues = 0;
+
+       return err;
 }
 
 /* This structure defines the attibutes to be parsed below */
index 4dd3e26129b44657cdb05e2e9335ab4f554bcd76..7e258a83ccab1d62c52412c012c85b65e3c77e9c 100644 (file)
@@ -767,6 +767,8 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid);
 int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid);
 struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
                                             bool is_vf, bool is_netdev);
+int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, u8 *macaddr,
+                         bool is_vf, bool is_netdev);
 bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi);
 struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
                                      bool is_vf, bool is_netdev);
index 2d74c6e4d7b618fe3c5dd44d3ae93c2a433d3491..1cf715c72683b1dc2c7c4f758b136061e4bffb82 100644 (file)
@@ -302,13 +302,15 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
                   void *buffer, u16 buf_len)
 {
        struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
-       u16 len = le16_to_cpu(aq_desc->datalen);
+       u16 len;
        u8 *buf = (u8 *)buffer;
        u16 i = 0;
 
        if ((!(mask & hw->debug_mask)) || (desc == NULL))
                return;
 
+       len = le16_to_cpu(aq_desc->datalen);
+
        i40e_debug(hw, mask,
                   "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
                   le16_to_cpu(aq_desc->opcode),
index 3f385ffe420f712abbda79b14c46e2b6196d8dc8..488a50d59dca08d5b224adec89c4e737402c221e 100644 (file)
@@ -2164,8 +2164,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
        case TCP_V4_FLOW:
                switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
                case 0:
-                       hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
-                       break;
+                       return -EINVAL;
                case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
                        hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
                        break;
@@ -2176,8 +2175,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
        case TCP_V6_FLOW:
                switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
                case 0:
-                       hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
-                       break;
+                       return -EINVAL;
                case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
                        hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
                        break;
@@ -2188,9 +2186,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
        case UDP_V4_FLOW:
                switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
                case 0:
-                       hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
-                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
-                       break;
+                       return -EINVAL;
                case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
                        hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
@@ -2202,9 +2198,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
        case UDP_V6_FLOW:
                switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
                case 0:
-                       hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
-                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
-                       break;
+                       return -EINVAL;
                case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
                        hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
index 4a9873ec28c7119d28aabb791bd0628ceccf56ad..979cc024bca7a54ba1ecc8e9cd1f0f4e488ad6be 100644 (file)
@@ -1316,6 +1316,42 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
                                        struct i40e_mac_filter, list);
 }
 
+/**
+ * i40e_del_mac_all_vlan - Remove a MAC filter from all VLANS
+ * @vsi: the VSI to be searched
+ * @macaddr: the mac address to be removed
+ * @is_vf: true if it is a VF
+ * @is_netdev: true if it is a netdev
+ *
+ * Removes a given MAC address from a VSI, regardless of VLAN
+ *
+ * Returns 0 for success, or error
+ **/
+int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, u8 *macaddr,
+                         bool is_vf, bool is_netdev)
+{
+       struct i40e_mac_filter *f = NULL;
+       int changed = 0;
+
+       WARN(!spin_is_locked(&vsi->mac_filter_list_lock),
+            "Missing mac_filter_list_lock\n");
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               if ((ether_addr_equal(macaddr, f->macaddr)) &&
+                   (is_vf == f->is_vf) &&
+                   (is_netdev == f->is_netdev)) {
+                       f->counter--;
+                       f->changed = true;
+                       changed = 1;
+               }
+       }
+       if (changed) {
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+               return 0;
+       }
+       return -ENOENT;
+}
+
 /**
  * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM
  * @vsi: the PF Main VSI - inappropriate for any other VSI
@@ -1547,9 +1583,11 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
                spin_unlock_bh(&vsi->mac_filter_list_lock);
        }
 
-       i40e_sync_vsi_filters(vsi, false);
        ether_addr_copy(netdev->dev_addr, addr->sa_data);
-
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
        return 0;
 }
 
@@ -1935,11 +1973,13 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
 
        /* Now process 'del_list' outside the lock */
        if (!list_empty(&tmp_del_list)) {
+               int del_list_size;
+
                filter_list_len = pf->hw.aq.asq_buf_size /
                            sizeof(struct i40e_aqc_remove_macvlan_element_data);
-               del_list = kcalloc(filter_list_len,
-                           sizeof(struct i40e_aqc_remove_macvlan_element_data),
-                           GFP_KERNEL);
+               del_list_size = filter_list_len *
+                           sizeof(struct i40e_aqc_remove_macvlan_element_data);
+               del_list = kzalloc(del_list_size, GFP_KERNEL);
                if (!del_list) {
                        i40e_cleanup_add_list(&tmp_add_list);
 
@@ -1971,7 +2011,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
                                                  NULL);
                                aq_err = pf->hw.aq.asq_last_status;
                                num_del = 0;
-                               memset(del_list, 0, sizeof(*del_list));
+                               memset(del_list, 0, del_list_size);
 
                                if (ret && aq_err != I40E_AQ_RC_ENOENT)
                                        dev_err(&pf->pdev->dev,
@@ -2004,13 +2044,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
        }
 
        if (!list_empty(&tmp_add_list)) {
+               int add_list_size;
 
                /* do all the adds now */
                filter_list_len = pf->hw.aq.asq_buf_size /
                               sizeof(struct i40e_aqc_add_macvlan_element_data),
-               add_list = kcalloc(filter_list_len,
-                              sizeof(struct i40e_aqc_add_macvlan_element_data),
-                              GFP_KERNEL);
+               add_list_size = filter_list_len *
+                              sizeof(struct i40e_aqc_add_macvlan_element_data);
+               add_list = kzalloc(add_list_size, GFP_KERNEL);
                if (!add_list) {
                        /* Purge element from temporary lists */
                        i40e_cleanup_add_list(&tmp_add_list);
@@ -2048,7 +2089,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
 
                                if (ret)
                                        break;
-                               memset(add_list, 0, sizeof(*add_list));
+                               memset(add_list, 0, add_list_size);
                        }
                        /* Entries from tmp_add_list were cloned from MAC
                         * filter list, hence clean those cloned entries
@@ -2112,12 +2153,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
                         */
                        if (pf->cur_promisc != cur_promisc) {
                                pf->cur_promisc = cur_promisc;
-                               if (grab_rtnl)
-                                       i40e_do_reset_safe(pf,
-                                               BIT(__I40E_PF_RESET_REQUESTED));
-                               else
-                                       i40e_do_reset(pf,
-                                               BIT(__I40E_PF_RESET_REQUESTED));
+                               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
                        }
                } else {
                        ret = i40e_aq_set_vsi_unicast_promiscuous(
@@ -2377,16 +2413,13 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
                }
        }
 
-       /* Make sure to release before sync_vsi_filter because that
-        * function will lock/unlock as necessary
-        */
        spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-       if (test_bit(__I40E_DOWN, &vsi->back->state) ||
-           test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
-               return 0;
-
-       return i40e_sync_vsi_filters(vsi, false);
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
+       return 0;
 }
 
 /**
@@ -2459,16 +2492,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
                }
        }
 
-       /* Make sure to release before sync_vsi_filter because that
-        * function with lock/unlock as necessary
-        */
        spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-       if (test_bit(__I40E_DOWN, &vsi->back->state) ||
-           test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
-               return 0;
-
-       return i40e_sync_vsi_filters(vsi, false);
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
+       return 0;
 }
 
 /**
@@ -2711,6 +2741,11 @@ static void i40e_config_xps_tx_ring(struct i40e_ring *ring)
                netif_set_xps_queue(ring->netdev, mask, ring->queue_index);
                free_cpumask_var(mask);
        }
+
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
 }
 
 /**
@@ -6685,6 +6720,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        struct i40e_hw *hw = &pf->hw;
        u8 set_fc_aq_fail = 0;
        i40e_status ret;
+       u32 val;
        u32 v;
 
        /* Now we wait for GRST to settle out.
@@ -6823,6 +6859,20 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
                }
        }
 
+       /* Reconfigure hardware for allowing smaller MSS in the case
+        * of TSO, so that we avoid the MDD being fired and causing
+        * a reset in the case of small MSS+TSO.
+        */
+#define I40E_REG_MSS          0x000E64DC
+#define I40E_REG_MSS_MIN_MASK 0x3FF0000
+#define I40E_64BYTE_MSS       0x400000
+       val = rd32(hw, I40E_REG_MSS);
+       if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
+               val &= ~I40E_REG_MSS_MIN_MASK;
+               val |= I40E_64BYTE_MSS;
+               wr32(hw, I40E_REG_MSS, val);
+       }
+
        if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
            (pf->hw.aq.fw_maj_ver < 4)) {
                msleep(75);
@@ -10183,6 +10233,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        u16 link_status;
        int err;
        u32 len;
+       u32 val;
        u32 i;
        u8 set_fc_aq_fail;
 
@@ -10493,6 +10544,17 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                         i40e_stat_str(&pf->hw, err),
                         i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 
+       /* Reconfigure hardware for allowing smaller MSS in the case
+        * of TSO, so that we avoid the MDD being fired and causing
+        * a reset in the case of small MSS+TSO.
+        */
+       val = rd32(hw, I40E_REG_MSS);
+       if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
+               val &= ~I40E_REG_MSS_MIN_MASK;
+               val |= I40E_64BYTE_MSS;
+               wr32(hw, I40E_REG_MSS, val);
+       }
+
        if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
            (pf->hw.aq.fw_maj_ver < 4)) {
                msleep(75);
@@ -10791,6 +10853,12 @@ static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev,
 
        dev_info(&pdev->dev, "%s: error %d\n", __func__, error);
 
+       if (!pf) {
+               dev_info(&pdev->dev,
+                        "Cannot recover - error happened during device probe\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
        /* shutdown all operations */
        if (!test_bit(__I40E_SUSPENDED, &pf->state)) {
                rtnl_lock();
index 635b3ac17877b153eba5c77a352ab8428d2b0742..26c55bba4bf3f81f24ce57b2a8b73d32952e95d9 100644 (file)
@@ -235,6 +235,9 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
                                 "Filter deleted for PCTYPE %d loc = %d\n",
                                 fd_data->pctype, fd_data->fd_id);
        }
+       if (err)
+               kfree(raw_packet);
+
        return err ? -EOPNOTSUPP : 0;
 }
 
@@ -312,6 +315,9 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
                                 fd_data->pctype, fd_data->fd_id);
        }
 
+       if (err)
+               kfree(raw_packet);
+
        return err ? -EOPNOTSUPP : 0;
 }
 
@@ -387,6 +393,9 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
                }
        }
 
+       if (err)
+               kfree(raw_packet);
+
        return err ? -EOPNOTSUPP : 0;
 }
 
@@ -526,11 +535,7 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
                                            struct i40e_tx_buffer *tx_buffer)
 {
        if (tx_buffer->skb) {
-               if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
-                       kfree(tx_buffer->raw_buf);
-               else
-                       dev_kfree_skb_any(tx_buffer->skb);
-
+               dev_kfree_skb_any(tx_buffer->skb);
                if (dma_unmap_len(tx_buffer, len))
                        dma_unmap_single(ring->dev,
                                         dma_unmap_addr(tx_buffer, dma),
@@ -542,6 +547,10 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
                               dma_unmap_len(tx_buffer, len),
                               DMA_TO_DEVICE);
        }
+
+       if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
+               kfree(tx_buffer->raw_buf);
+
        tx_buffer->next_to_watch = NULL;
        tx_buffer->skb = NULL;
        dma_unmap_len_set(tx_buffer, len, 0);
@@ -1416,31 +1425,12 @@ checksum_fail:
 }
 
 /**
- * i40e_rx_hash - returns the hash value from the Rx descriptor
- * @ring: descriptor ring
- * @rx_desc: specific descriptor
- **/
-static inline u32 i40e_rx_hash(struct i40e_ring *ring,
-                              union i40e_rx_desc *rx_desc)
-{
-       const __le64 rss_mask =
-               cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
-                           I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
-
-       if ((ring->netdev->features & NETIF_F_RXHASH) &&
-           (rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask)
-               return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
-       else
-               return 0;
-}
-
-/**
- * i40e_ptype_to_hash - get a hash type
+ * i40e_ptype_to_htype - get a hash type
  * @ptype: the ptype value from the descriptor
  *
  * Returns a hash type to be used by skb_set_hash
  **/
-static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+static inline enum pkt_hash_types i40e_ptype_to_htype(u8 ptype)
 {
        struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
 
@@ -1457,6 +1447,30 @@ static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
                return PKT_HASH_TYPE_L2;
 }
 
+/**
+ * i40e_rx_hash - set the hash value in the skb
+ * @ring: descriptor ring
+ * @rx_desc: specific descriptor
+ **/
+static inline void i40e_rx_hash(struct i40e_ring *ring,
+                               union i40e_rx_desc *rx_desc,
+                               struct sk_buff *skb,
+                               u8 rx_ptype)
+{
+       u32 hash;
+       const __le64 rss_mask  =
+               cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
+                           I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
+
+       if (ring->netdev->features & NETIF_F_RXHASH)
+               return;
+
+       if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) {
+               hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
+               skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype));
+       }
+}
+
 /**
  * i40e_clean_rx_irq_ps - Reclaim resources after receive; packet split
  * @rx_ring:  rx ring to clean
@@ -1606,8 +1620,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                        continue;
                }
 
-               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-                            i40e_ptype_to_hash(rx_ptype));
+               i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
+
                if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
                        i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
                                           I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
@@ -1736,8 +1750,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
                        continue;
                }
 
-               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-                            i40e_ptype_to_hash(rx_ptype));
+               i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
                if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
                        i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
                                           I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
index 44462b40f2d7666f059b6741123107755e18e415..e116d9a99b8e9156a7b7379c6dcde35fbec9fd5d 100644 (file)
@@ -549,12 +549,15 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
                        i40e_vsi_add_pvid(vsi, vf->port_vlan_id);
 
                spin_lock_bh(&vsi->mac_filter_list_lock);
-               f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
-                                   vf->port_vlan_id ? vf->port_vlan_id : -1,
-                                   true, false);
-               if (!f)
-                       dev_info(&pf->pdev->dev,
-                                "Could not allocate VF MAC addr\n");
+               if (is_valid_ether_addr(vf->default_lan_addr.addr)) {
+                       f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
+                                      vf->port_vlan_id ? vf->port_vlan_id : -1,
+                                      true, false);
+                       if (!f)
+                               dev_info(&pf->pdev->dev,
+                                        "Could not add MAC filter %pM for VF %d\n",
+                                       vf->default_lan_addr.addr, vf->vf_id);
+               }
                f = i40e_add_filter(vsi, brdcast,
                                    vf->port_vlan_id ? vf->port_vlan_id : -1,
                                    true, false);
@@ -1680,8 +1683,12 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
        spin_lock_bh(&vsi->mac_filter_list_lock);
        /* delete addresses from the list */
        for (i = 0; i < al->num_elements; i++)
-               i40e_del_filter(vsi, al->list[i].addr,
-                               I40E_VLAN_ANY, true, false);
+               if (i40e_del_mac_all_vlan(vsi, al->list[i].addr, true, false)) {
+                       ret = I40E_ERR_INVALID_MAC_ADDR;
+                       spin_unlock_bh(&vsi->mac_filter_list_lock);
+                       goto error_param;
+               }
+
        spin_unlock_bh(&vsi->mac_filter_list_lock);
 
        /* program the updated filter list */
index 47e9a90d6b100d9874c6a6e77e123c7e5ccc7ac2..39db70a597ed65890653c2887ff9bd3406c9d62a 100644 (file)
@@ -51,11 +51,7 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
                                            struct i40e_tx_buffer *tx_buffer)
 {
        if (tx_buffer->skb) {
-               if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
-                       kfree(tx_buffer->raw_buf);
-               else
-                       dev_kfree_skb_any(tx_buffer->skb);
-
+               dev_kfree_skb_any(tx_buffer->skb);
                if (dma_unmap_len(tx_buffer, len))
                        dma_unmap_single(ring->dev,
                                         dma_unmap_addr(tx_buffer, dma),
@@ -67,6 +63,10 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
                               dma_unmap_len(tx_buffer, len),
                               DMA_TO_DEVICE);
        }
+
+       if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
+               kfree(tx_buffer->raw_buf);
+
        tx_buffer->next_to_watch = NULL;
        tx_buffer->skb = NULL;
        dma_unmap_len_set(tx_buffer, len, 0);
@@ -245,16 +245,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
        tx_ring->q_vector->tx.total_bytes += total_bytes;
        tx_ring->q_vector->tx.total_packets += total_packets;
 
-       /* check to see if there are any non-cache aligned descriptors
-        * waiting to be written back, and kick the hardware to force
-        * them to be written back in case of napi polling
-        */
-       if (budget &&
-           !((i & WB_STRIDE) == WB_STRIDE) &&
-           !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
-           (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
-               tx_ring->arm_wb = true;
-
        netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev,
                                                      tx_ring->queue_index),
                                  total_packets, total_bytes);
@@ -889,31 +879,12 @@ checksum_fail:
 }
 
 /**
- * i40e_rx_hash - returns the hash value from the Rx descriptor
- * @ring: descriptor ring
- * @rx_desc: specific descriptor
- **/
-static inline u32 i40e_rx_hash(struct i40e_ring *ring,
-                              union i40e_rx_desc *rx_desc)
-{
-       const __le64 rss_mask =
-               cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
-                           I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
-
-       if ((ring->netdev->features & NETIF_F_RXHASH) &&
-           (rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask)
-               return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
-       else
-               return 0;
-}
-
-/**
- * i40e_ptype_to_hash - get a hash type
+ * i40e_ptype_to_htype - get a hash type
  * @ptype: the ptype value from the descriptor
  *
  * Returns a hash type to be used by skb_set_hash
  **/
-static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+static inline enum pkt_hash_types i40e_ptype_to_htype(u8 ptype)
 {
        struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
 
@@ -930,6 +901,30 @@ static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
                return PKT_HASH_TYPE_L2;
 }
 
+/**
+ * i40e_rx_hash - set the hash value in the skb
+ * @ring: descriptor ring
+ * @rx_desc: specific descriptor
+ **/
+static inline void i40e_rx_hash(struct i40e_ring *ring,
+                               union i40e_rx_desc *rx_desc,
+                               struct sk_buff *skb,
+                               u8 rx_ptype)
+{
+       u32 hash;
+       const __le64 rss_mask  =
+               cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH <<
+                           I40E_RX_DESC_STATUS_FLTSTAT_SHIFT);
+
+       if (ring->netdev->features & NETIF_F_RXHASH)
+               return;
+
+       if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) {
+               hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
+               skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype));
+       }
+}
+
 /**
  * i40e_clean_rx_irq_ps - Reclaim resources after receive; packet split
  * @rx_ring:  rx ring to clean
@@ -1071,8 +1066,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                        continue;
                }
 
-               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-                            i40e_ptype_to_hash(rx_ptype));
+               i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
+
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
                total_rx_packets++;
@@ -1189,8 +1184,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
                        continue;
                }
 
-               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
-                            i40e_ptype_to_hash(rx_ptype));
+               i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype);
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
                total_rx_packets++;
@@ -1770,6 +1764,9 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
        u32 td_tag = 0;
        dma_addr_t dma;
        u16 gso_segs;
+       u16 desc_count = 0;
+       bool tail_bump = true;
+       bool do_rs = false;
 
        if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
                td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
@@ -1810,6 +1807,8 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
                        tx_desc++;
                        i++;
+                       desc_count++;
+
                        if (i == tx_ring->count) {
                                tx_desc = I40E_TX_DESC(tx_ring, 0);
                                i = 0;
@@ -1829,6 +1828,8 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
                tx_desc++;
                i++;
+               desc_count++;
+
                if (i == tx_ring->count) {
                        tx_desc = I40E_TX_DESC(tx_ring, 0);
                        i = 0;
@@ -1843,35 +1844,7 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
                tx_bi = &tx_ring->tx_bi[i];
        }
 
-       /* Place RS bit on last descriptor of any packet that spans across the
-        * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
-        */
 #define WB_STRIDE 0x3
-       if (((i & WB_STRIDE) != WB_STRIDE) &&
-           (first <= &tx_ring->tx_bi[i]) &&
-           (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
-               tx_desc->cmd_type_offset_bsz =
-                       build_ctob(td_cmd, td_offset, size, td_tag) |
-                       cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
-                                        I40E_TXD_QW1_CMD_SHIFT);
-       } else {
-               tx_desc->cmd_type_offset_bsz =
-                       build_ctob(td_cmd, td_offset, size, td_tag) |
-                       cpu_to_le64((u64)I40E_TXD_CMD <<
-                                        I40E_TXD_QW1_CMD_SHIFT);
-       }
-
-       netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
-                                                tx_ring->queue_index),
-                            first->bytecount);
-
-       /* Force memory writes to complete before letting h/w
-        * know there are new descriptors to fetch.  (Only
-        * applicable for weak-ordered memory model archs,
-        * such as IA-64).
-        */
-       wmb();
-
        /* set next_to_watch value indicating a packet is present */
        first->next_to_watch = tx_desc;
 
@@ -1881,15 +1854,78 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        tx_ring->next_to_use = i;
 
+       netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
+                                                tx_ring->queue_index),
+                                                first->bytecount);
        i40evf_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+       /* Algorithm to optimize tail and RS bit setting:
+        * if xmit_more is supported
+        *      if xmit_more is true
+        *              do not update tail and do not mark RS bit.
+        *      if xmit_more is false and last xmit_more was false
+        *              if every packet spanned less than 4 desc
+        *                      then set RS bit on 4th packet and update tail
+        *                      on every packet
+        *              else
+        *                      update tail and set RS bit on every packet.
+        *      if xmit_more is false and last_xmit_more was true
+        *              update tail and set RS bit.
+        * else (kernel < 3.18)
+        *      if every packet spanned less than 4 desc
+        *              then set RS bit on 4th packet and update tail
+        *              on every packet
+        *      else
+        *              set RS bit on EOP for every packet and update tail
+        *
+        * Optimization: wmb to be issued only in case of tail update.
+        * Also optimize the Descriptor WB path for RS bit with the same
+        * algorithm.
+        *
+        * Note: If there are less than 4 packets
+        * pending and interrupts were disabled the service task will
+        * trigger a force WB.
+        */
+       if (skb->xmit_more  &&
+           !netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
+                                                   tx_ring->queue_index))) {
+               tx_ring->flags |= I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
+               tail_bump = false;
+       } else if (!skb->xmit_more &&
+                  !netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
+                                                      tx_ring->queue_index)) &&
+                  (!(tx_ring->flags & I40E_TXR_FLAGS_LAST_XMIT_MORE_SET)) &&
+                  (tx_ring->packet_stride < WB_STRIDE) &&
+                  (desc_count < WB_STRIDE)) {
+               tx_ring->packet_stride++;
+       } else {
+               tx_ring->packet_stride = 0;
+               tx_ring->flags &= ~I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
+               do_rs = true;
+       }
+       if (do_rs)
+               tx_ring->packet_stride = 0;
+
+       tx_desc->cmd_type_offset_bsz =
+                       build_ctob(td_cmd, td_offset, size, td_tag) |
+                       cpu_to_le64((u64)(do_rs ? I40E_TXD_CMD :
+                                                 I40E_TX_DESC_CMD_EOP) <<
+                                                 I40E_TXD_QW1_CMD_SHIFT);
+
        /* notify HW of packet */
-       if (!skb->xmit_more ||
-           netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev,
-                                                  tx_ring->queue_index)))
-               writel(i, tx_ring->tail);
-       else
+       if (!tail_bump)
                prefetchw(tx_desc + 1);
 
+       if (tail_bump) {
+               /* Force memory writes to complete before letting h/w
+                * know there are new descriptors to fetch.  (Only
+                * applicable for weak-ordered memory model archs,
+                * such as IA-64).
+                */
+               wmb();
+               writel(i, tx_ring->tail);
+       }
+
        return;
 
 dma_error:
index ebc1bf77f03606fb05312b2a5c84e788b92435cb..998976844e4e27bac3c8843bf3b5266d79d72d72 100644 (file)
@@ -267,6 +267,8 @@ struct i40e_ring {
 
        bool ring_active;               /* is ring online or not */
        bool arm_wb;            /* do something to arm write back */
+       u8 packet_stride;
+#define I40E_TXR_FLAGS_LAST_XMIT_MORE_SET BIT(2)
 
        u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR       BIT(0)
index 4790437a50ac0d3e7f94b2733acf8e7c50c3f18e..2ac62efc36f778dc29c6ee125c7809ff87678895 100644 (file)
@@ -477,54 +477,30 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter,
 
        switch (nfc->flow_type) {
        case TCP_V4_FLOW:
-               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-               case 0:
-                       hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
-                       break;
-               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+               if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3))
                        hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
-                       break;
-               default:
+               else
                        return -EINVAL;
-               }
                break;
        case TCP_V6_FLOW:
-               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-               case 0:
-                       hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
-                       break;
-               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+               if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3))
                        hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
-                       break;
-               default:
+               else
                        return -EINVAL;
-               }
                break;
        case UDP_V4_FLOW:
-               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-               case 0:
-                       hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
-                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
-                       break;
-               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+               if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
                        hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4));
-                       break;
-               default:
+               } else {
                        return -EINVAL;
                }
                break;
        case UDP_V6_FLOW:
-               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
-               case 0:
-                       hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
-                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
-                       break;
-               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+               if (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
                        hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
                                 BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6));
-                       break;
-               default:
+               } else {
                        return -EINVAL;
                }
                break;
index 99d2cffae0cd8c2b4c583f4453aa3c09cc58f3eb..5f03ab3dfa191899072a80e4851279e9df6454fc 100644 (file)
@@ -1864,6 +1864,9 @@ void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
 {
        int i;
 
+       if (!adapter->tx_rings)
+               return;
+
        for (i = 0; i < adapter->num_active_queues; i++)
                if (adapter->tx_rings[i]->desc)
                        i40evf_free_tx_resources(adapter->tx_rings[i]);
@@ -1932,6 +1935,9 @@ void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
 {
        int i;
 
+       if (!adapter->rx_rings)
+               return;
+
        for (i = 0; i < adapter->num_active_queues; i++)
                if (adapter->rx_rings[i]->desc)
                        i40evf_free_rx_resources(adapter->rx_rings[i]);
index 32e620e1eb5c9549db7f2743a1b2b2986523666f..5de3f52fd31f3236090c984bd5081648a447e6ea 100644 (file)
@@ -391,6 +391,7 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
        struct i40e_virtchnl_ether_addr_list *veal;
        int len, i = 0, count = 0;
        struct i40evf_mac_filter *f;
+       bool more = false;
 
        if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
                /* bail because we already have a command pending */
@@ -415,7 +416,9 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
                count = (I40EVF_MAX_AQ_BUF_SIZE -
                         sizeof(struct i40e_virtchnl_ether_addr_list)) /
                        sizeof(struct i40e_virtchnl_ether_addr);
-               len = I40EVF_MAX_AQ_BUF_SIZE;
+               len = sizeof(struct i40e_virtchnl_ether_addr_list) +
+                     (count * sizeof(struct i40e_virtchnl_ether_addr));
+               more = true;
        }
 
        veal = kzalloc(len, GFP_ATOMIC);
@@ -431,7 +434,8 @@ void i40evf_add_ether_addrs(struct i40evf_adapter *adapter)
                        f->add = false;
                }
        }
-       adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER;
+       if (!more)
+               adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_MAC_FILTER;
        i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
                           (u8 *)veal, len);
        kfree(veal);
@@ -450,6 +454,7 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
        struct i40e_virtchnl_ether_addr_list *veal;
        struct i40evf_mac_filter *f, *ftmp;
        int len, i = 0, count = 0;
+       bool more = false;
 
        if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
                /* bail because we already have a command pending */
@@ -474,7 +479,9 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
                count = (I40EVF_MAX_AQ_BUF_SIZE -
                         sizeof(struct i40e_virtchnl_ether_addr_list)) /
                        sizeof(struct i40e_virtchnl_ether_addr);
-               len = I40EVF_MAX_AQ_BUF_SIZE;
+               len = sizeof(struct i40e_virtchnl_ether_addr_list) +
+                     (count * sizeof(struct i40e_virtchnl_ether_addr));
+               more = true;
        }
        veal = kzalloc(len, GFP_ATOMIC);
        if (!veal)
@@ -490,7 +497,8 @@ void i40evf_del_ether_addrs(struct i40evf_adapter *adapter)
                        kfree(f);
                }
        }
-       adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+       if (!more)
+               adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_MAC_FILTER;
        i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS,
                           (u8 *)veal, len);
        kfree(veal);
@@ -509,6 +517,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
        struct i40e_virtchnl_vlan_filter_list *vvfl;
        int len, i = 0, count = 0;
        struct i40evf_vlan_filter *f;
+       bool more = false;
 
        if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
                /* bail because we already have a command pending */
@@ -534,7 +543,9 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
                count = (I40EVF_MAX_AQ_BUF_SIZE -
                         sizeof(struct i40e_virtchnl_vlan_filter_list)) /
                        sizeof(u16);
-               len = I40EVF_MAX_AQ_BUF_SIZE;
+               len = sizeof(struct i40e_virtchnl_vlan_filter_list) +
+                     (count * sizeof(u16));
+               more = true;
        }
        vvfl = kzalloc(len, GFP_ATOMIC);
        if (!vvfl)
@@ -549,7 +560,8 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter)
                        f->add = false;
                }
        }
-       adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
+       if (!more)
+               adapter->aq_required &= ~I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
        i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
        kfree(vvfl);
 }
@@ -567,6 +579,7 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
        struct i40e_virtchnl_vlan_filter_list *vvfl;
        struct i40evf_vlan_filter *f, *ftmp;
        int len, i = 0, count = 0;
+       bool more = false;
 
        if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
                /* bail because we already have a command pending */
@@ -592,7 +605,9 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
                count = (I40EVF_MAX_AQ_BUF_SIZE -
                         sizeof(struct i40e_virtchnl_vlan_filter_list)) /
                        sizeof(u16);
-               len = I40EVF_MAX_AQ_BUF_SIZE;
+               len = sizeof(struct i40e_virtchnl_vlan_filter_list) +
+                     (count * sizeof(u16));
+               more = true;
        }
        vvfl = kzalloc(len, GFP_ATOMIC);
        if (!vvfl)
@@ -608,7 +623,8 @@ void i40evf_del_vlans(struct i40evf_adapter *adapter)
                        kfree(f);
                }
        }
-       adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+       if (!more)
+               adapter->aq_required &= ~I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
        i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
        kfree(vvfl);
 }
index 7a73510e547cd49f38629b4d60fbab8b8dce945a..97bf0c3d5c69e06fd604c9685cfab129cd83e66c 100644 (file)
@@ -294,6 +294,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
        case I210_I_PHY_ID:
                phy->type               = e1000_phy_i210;
                phy->ops.check_polarity = igb_check_polarity_m88;
+               phy->ops.get_cfg_done   = igb_get_cfg_done_i210;
                phy->ops.get_phy_info   = igb_get_phy_info_m88;
                phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
                phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
index 65d931669f813bbcca0a21cc13a68c53663b03ee..29f59c76878a59a61e4e7d61a084b25db33e8726 100644 (file)
@@ -900,3 +900,30 @@ s32 igb_pll_workaround_i210(struct e1000_hw *hw)
        wr32(E1000_MDICNFG, mdicnfg);
        return ret_val;
 }
+
+/**
+ *  igb_get_cfg_done_i210 - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  0.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+s32 igb_get_cfg_done_i210(struct e1000_hw *hw)
+{
+       s32 timeout = PHY_CFG_TIMEOUT;
+       u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+       while (timeout) {
+               if (rd32(E1000_EEMNGCTL_I210) & mask)
+                       break;
+               usleep_range(1000, 2000);
+               timeout--;
+       }
+       if (!timeout)
+               hw_dbg("MNG configuration cycle has not completed.\n");
+
+       return 0;
+}
index 3442b6357d01211d9edd310f1b8339202ae5af19..eaa68a50cb3b7e7bda4db83c666725b224b80bf0 100644 (file)
@@ -34,6 +34,7 @@ s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data);
 s32 igb_init_nvm_params_i210(struct e1000_hw *hw);
 bool igb_get_flash_presence_i210(struct e1000_hw *hw);
 s32 igb_pll_workaround_i210(struct e1000_hw *hw);
+s32 igb_get_cfg_done_i210(struct e1000_hw *hw);
 
 #define E1000_STM_OPCODE               0xDB00
 #define E1000_EEPROM_FLASH_SIZE_WORD   0x11
index 4af2870e49f88aaa67559e6d454328eb1ff1d6db..0fdcd4d1b982f2a0f80cac1c7755c03fab1f67a9 100644 (file)
@@ -66,6 +66,7 @@
 #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
 #define E1000_PBS      0x01008  /* Packet Buffer Size */
 #define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEMNGCTL_I210 0x12030  /* MNG EEprom Control */
 #define E1000_EEARBC_I210 0x12024  /* EEPROM Auto Read Bus Control */
 #define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
 #define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
index 1a2f1cc44b2836499dc231be9edb896b8b6ddbe6..e3cb93bdb21aed5341a758694735283058f8b71f 100644 (file)
@@ -389,6 +389,8 @@ struct igb_adapter {
        u16 link_speed;
        u16 link_duplex;
 
+       u8 __iomem *io_addr; /* Mainly for iounmap use */
+
        struct work_struct reset_task;
        struct work_struct watchdog_task;
        bool fc_autoneg;
index ea7b098872456e5903bbfd5dead770eba52f69ef..fa3b4cbea23bbffb17fa208663e9514015949243 100644 (file)
@@ -2294,9 +2294,11 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
        err = -EIO;
-       hw->hw_addr = pci_iomap(pdev, 0, 0);
-       if (!hw->hw_addr)
+       adapter->io_addr = pci_iomap(pdev, 0, 0);
+       if (!adapter->io_addr)
                goto err_ioremap;
+       /* hw->hw_addr can be altered, we'll use adapter->io_addr for unmap */
+       hw->hw_addr = adapter->io_addr;
 
        netdev->netdev_ops = &igb_netdev_ops;
        igb_set_ethtool_ops(netdev);
@@ -2656,7 +2658,7 @@ err_sw_init:
 #ifdef CONFIG_PCI_IOV
        igb_disable_sriov(pdev);
 #endif
-       pci_iounmap(pdev, hw->hw_addr);
+       pci_iounmap(pdev, adapter->io_addr);
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
@@ -2823,7 +2825,7 @@ static void igb_remove(struct pci_dev *pdev)
 
        igb_clear_interrupt_scheme(adapter);
 
-       pci_iounmap(pdev, hw->hw_addr);
+       pci_iounmap(pdev, adapter->io_addr);
        if (hw->flash_address)
                iounmap(hw->flash_address);
        pci_release_selected_regions(pdev,
@@ -2856,6 +2858,13 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
        if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
                return;
 
+       /* Of the below we really only want the effect of getting
+        * IGB_FLAG_HAS_MSIX set (if available), without which
+        * igb_enable_sriov() has no effect.
+        */
+       igb_set_interrupt_capability(adapter, true);
+       igb_reset_interrupt_capability(adapter);
+
        pci_sriov_set_totalvfs(pdev, 7);
        igb_enable_sriov(pdev, max_vfs);
 
index aed8d029b23dc53a7a630d74816e37d35bdbbc4a..cd9b284bc83b6294e47361005b21e1e96352324b 100644 (file)
@@ -2786,7 +2786,8 @@ int ixgbe_poll(struct napi_struct *napi, int budget)
        ixgbe_for_each_ring(ring, q_vector->tx)
                clean_complete &= !!ixgbe_clean_tx_irq(q_vector, ring);
 
-       if (!ixgbe_qv_lock_napi(q_vector))
+       /* Exit if we are called by netpoll or busy polling is active */
+       if ((budget <= 0) || !ixgbe_qv_lock_napi(q_vector))
                return budget;
 
        /* attempt to distribute budget to each queue fairly, but don't allow
index a4ac6fedac75b714231040215bdb9d7bdeda3d9d..71ec9cb08e067a7d03e874d7c1d2f6ae32ed646d 100644 (file)
 /* Various constants */
 
 /* Coalescing */
-#define MVNETA_TXDONE_COAL_PKTS                1
+#define MVNETA_TXDONE_COAL_PKTS                0       /* interrupt per packet */
 #define MVNETA_RX_COAL_PKTS            32
 #define MVNETA_RX_COAL_USEC            100
 
index 67e9633ea9c7cfa6aa2a6a93402d10a5d60da0ba..232191417b93ffad77f360c04236d128234765a2 100644 (file)
@@ -2282,7 +2282,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
        struct mlx4_en_dev *mdev = en_priv->mdev;
        u64 mac_u64 = mlx4_mac_to_u64(mac);
 
-       if (!is_valid_ether_addr(mac))
+       if (is_multicast_ether_addr(mac))
                return -EINVAL;
 
        return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
index 037fc4cdf5af675e811f5f50950816d8dfeaff51..cc199063612ac97bf504680707399f8d7a7e8dd2 100644 (file)
@@ -143,13 +143,14 @@ static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
        return cmd->cmd_buf + (idx << cmd->log_stride);
 }
 
-static u8 xor8_buf(void *buf, int len)
+static u8 xor8_buf(void *buf, size_t offset, int len)
 {
        u8 *ptr = buf;
        u8 sum = 0;
        int i;
+       int end = len + offset;
 
-       for (i = 0; i < len; i++)
+       for (i = offset; i < end; i++)
                sum ^= ptr[i];
 
        return sum;
@@ -157,41 +158,49 @@ static u8 xor8_buf(void *buf, int len)
 
 static int verify_block_sig(struct mlx5_cmd_prot_block *block)
 {
-       if (xor8_buf(block->rsvd0, sizeof(*block) - sizeof(block->data) - 1) != 0xff)
+       size_t rsvd0_off = offsetof(struct mlx5_cmd_prot_block, rsvd0);
+       int xor_len = sizeof(*block) - sizeof(block->data) - 1;
+
+       if (xor8_buf(block, rsvd0_off, xor_len) != 0xff)
                return -EINVAL;
 
-       if (xor8_buf(block, sizeof(*block)) != 0xff)
+       if (xor8_buf(block, 0, sizeof(*block)) != 0xff)
                return -EINVAL;
 
        return 0;
 }
 
-static void calc_block_sig(struct mlx5_cmd_prot_block *block, u8 token,
-                          int csum)
+static void calc_block_sig(struct mlx5_cmd_prot_block *block)
 {
-       block->token = token;
-       if (csum) {
-               block->ctrl_sig = ~xor8_buf(block->rsvd0, sizeof(*block) -
-                                           sizeof(block->data) - 2);
-               block->sig = ~xor8_buf(block, sizeof(*block) - 1);
-       }
+       int ctrl_xor_len = sizeof(*block) - sizeof(block->data) - 2;
+       size_t rsvd0_off = offsetof(struct mlx5_cmd_prot_block, rsvd0);
+
+       block->ctrl_sig = ~xor8_buf(block, rsvd0_off, ctrl_xor_len);
+       block->sig = ~xor8_buf(block, 0, sizeof(*block) - 1);
 }
 
-static void calc_chain_sig(struct mlx5_cmd_msg *msg, u8 token, int csum)
+static void calc_chain_sig(struct mlx5_cmd_msg *msg)
 {
        struct mlx5_cmd_mailbox *next = msg->next;
-
-       while (next) {
-               calc_block_sig(next->buf, token, csum);
+       int size = msg->len;
+       int blen = size - min_t(int, sizeof(msg->first.data), size);
+       int n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1)
+               / MLX5_CMD_DATA_BLOCK_SIZE;
+       int i = 0;
+
+       for (i = 0; i < n && next; i++)  {
+               calc_block_sig(next->buf);
                next = next->next;
        }
 }
 
 static void set_signature(struct mlx5_cmd_work_ent *ent, int csum)
 {
-       ent->lay->sig = ~xor8_buf(ent->lay, sizeof(*ent->lay));
-       calc_chain_sig(ent->in, ent->token, csum);
-       calc_chain_sig(ent->out, ent->token, csum);
+       ent->lay->sig = ~xor8_buf(ent->lay, 0,  sizeof(*ent->lay));
+       if (csum) {
+               calc_chain_sig(ent->in);
+               calc_chain_sig(ent->out);
+       }
 }
 
 static void poll_timeout(struct mlx5_cmd_work_ent *ent)
@@ -222,12 +231,17 @@ static int verify_signature(struct mlx5_cmd_work_ent *ent)
        struct mlx5_cmd_mailbox *next = ent->out->next;
        int err;
        u8 sig;
+       int size = ent->out->len;
+       int blen = size - min_t(int, sizeof(ent->out->first.data), size);
+       int n = (blen + MLX5_CMD_DATA_BLOCK_SIZE - 1)
+               / MLX5_CMD_DATA_BLOCK_SIZE;
+       int i = 0;
 
-       sig = xor8_buf(ent->lay, sizeof(*ent->lay));
+       sig = xor8_buf(ent->lay, 0, sizeof(*ent->lay));
        if (sig != 0xff)
                return -EINVAL;
 
-       while (next) {
+       for (i = 0; i < n && next; i++) {
                err = verify_block_sig(next->buf);
                if (err)
                        return err;
@@ -641,7 +655,6 @@ static void cmd_work_handler(struct work_struct *work)
                spin_unlock_irqrestore(&cmd->alloc_lock, flags);
        }
 
-       ent->token = alloc_token(cmd);
        cmd->ent_arr[ent->idx] = ent;
        lay = get_inst(cmd, ent->idx);
        ent->lay = lay;
@@ -755,7 +768,8 @@ static u8 *get_status_ptr(struct mlx5_outbox_hdr *out)
 static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
                           struct mlx5_cmd_msg *out, void *uout, int uout_size,
                           mlx5_cmd_cbk_t callback,
-                          void *context, int page_queue, u8 *status)
+                          void *context, int page_queue, u8 *status,
+                          u8 token)
 {
        struct mlx5_cmd *cmd = &dev->cmd;
        struct mlx5_cmd_work_ent *ent;
@@ -772,6 +786,8 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
        if (IS_ERR(ent))
                return PTR_ERR(ent);
 
+       ent->token = token;
+
        if (!callback)
                init_completion(&ent->done);
 
@@ -844,7 +860,8 @@ static const struct file_operations fops = {
        .write  = dbg_write,
 };
 
-static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size)
+static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size,
+                           u8 token)
 {
        struct mlx5_cmd_prot_block *block;
        struct mlx5_cmd_mailbox *next;
@@ -870,6 +887,7 @@ static int mlx5_copy_to_msg(struct mlx5_cmd_msg *to, void *from, int size)
                memcpy(block->data, from, copy);
                from += copy;
                size -= copy;
+               block->token = token;
                next = next->next;
        }
 
@@ -939,7 +957,8 @@ static void free_cmd_box(struct mlx5_core_dev *dev,
 }
 
 static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev,
-                                              gfp_t flags, int size)
+                                              gfp_t flags, int size,
+                                              u8 token)
 {
        struct mlx5_cmd_mailbox *tmp, *head = NULL;
        struct mlx5_cmd_prot_block *block;
@@ -968,6 +987,7 @@ static struct mlx5_cmd_msg *mlx5_alloc_cmd_msg(struct mlx5_core_dev *dev,
                tmp->next = head;
                block->next = cpu_to_be64(tmp->next ? tmp->next->dma : 0);
                block->block_num = cpu_to_be32(n - i - 1);
+               block->token = token;
                head = tmp;
        }
        msg->next = head;
@@ -1351,7 +1371,7 @@ static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
        }
 
        if (IS_ERR(msg))
-               msg = mlx5_alloc_cmd_msg(dev, gfp, in_size);
+               msg = mlx5_alloc_cmd_msg(dev, gfp, in_size, 0);
 
        return msg;
 }
@@ -1376,6 +1396,7 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
        int err;
        u8 status = 0;
        u32 drv_synd;
+       u8 token;
 
        if (pci_channel_offline(dev->pdev) ||
            dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
@@ -1394,20 +1415,22 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
                return err;
        }
 
-       err = mlx5_copy_to_msg(inb, in, in_size);
+       token = alloc_token(&dev->cmd);
+
+       err = mlx5_copy_to_msg(inb, in, in_size, token);
        if (err) {
                mlx5_core_warn(dev, "err %d\n", err);
                goto out_in;
        }
 
-       outb = mlx5_alloc_cmd_msg(dev, gfp, out_size);
+       outb = mlx5_alloc_cmd_msg(dev, gfp, out_size, token);
        if (IS_ERR(outb)) {
                err = PTR_ERR(outb);
                goto out_in;
        }
 
        err = mlx5_cmd_invoke(dev, inb, outb, out, out_size, callback, context,
-                             pages_queue, &status);
+                             pages_queue, &status, token);
        if (err)
                goto out_out;
 
@@ -1475,7 +1498,7 @@ static int create_msg_cache(struct mlx5_core_dev *dev)
        INIT_LIST_HEAD(&cmd->cache.med.head);
 
        for (i = 0; i < NUM_LONG_LISTS; i++) {
-               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE);
+               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, LONG_LIST_SIZE, 0);
                if (IS_ERR(msg)) {
                        err = PTR_ERR(msg);
                        goto ex_err;
@@ -1485,7 +1508,7 @@ static int create_msg_cache(struct mlx5_core_dev *dev)
        }
 
        for (i = 0; i < NUM_MED_LISTS; i++) {
-               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE);
+               msg = mlx5_alloc_cmd_msg(dev, GFP_KERNEL, MED_LIST_SIZE, 0);
                if (IS_ERR(msg)) {
                        err = PTR_ERR(msg);
                        goto ex_err;
index 2e022e9009393eee6e923c7e8b02c8bf24fa2f13..7cc9df717323ed39566a4b4b94942ff6ede3d42c 100644 (file)
@@ -399,6 +399,9 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
+               return -ENOTSUPP;
+
        coal->rx_coalesce_usecs       = priv->params.rx_cq_moderation_usec;
        coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts;
        coal->tx_coalesce_usecs       = priv->params.tx_cq_moderation_usec;
@@ -416,11 +419,18 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
        int tc;
        int i;
 
+       if (!MLX5_CAP_GEN(mdev, cq_moderation))
+               return -ENOTSUPP;
+
+       mutex_lock(&priv->state_lock);
        priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs;
        priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames;
        priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs;
        priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames;
 
+       if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+               goto out;
+
        for (i = 0; i < priv->params.num_channels; ++i) {
                c = priv->channel[i];
 
@@ -436,6 +446,8 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
                                               coal->rx_max_coalesced_frames);
        }
 
+out:
+       mutex_unlock(&priv->state_lock);
        return 0;
 }
 
index cbd17e25beeb37680209abcce5969021469e7b09..90e876ecc720b2786514375214de8724bf9a0f8a 100644 (file)
@@ -863,12 +863,10 @@ static int mlx5e_open_cq(struct mlx5e_channel *c,
        if (err)
                goto err_destroy_cq;
 
-       err = mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
-                                            moderation_usecs,
-                                            moderation_frames);
-       if (err)
-               goto err_destroy_cq;
-
+       if (MLX5_CAP_GEN(mdev, cq_moderation))
+               mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
+                                              moderation_usecs,
+                                              moderation_frames);
        return 0;
 
 err_destroy_cq:
@@ -1963,6 +1961,8 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
        }
        if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
                mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
+       if (!MLX5_CAP_GEN(mdev, cq_moderation))
+               mlx5_core_warn(mdev, "CQ modiration is not supported\n");
 
        return 0;
 }
index 3dd548ab8df14aabf9fa6a551cf54aa97f704d12..40365cb1abe6c33f7d90661c639333d24b569c27 100644 (file)
@@ -794,13 +794,12 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
                         * in a bitmap and increasing the chain consumer only
                         * for the first successive completed entries.
                         */
-                       bitmap_set(p_spq->p_comp_bitmap, pos, SPQ_RING_SIZE);
+                       __set_bit(pos, p_spq->p_comp_bitmap);
 
                        while (test_bit(p_spq->comp_bitmap_idx,
                                        p_spq->p_comp_bitmap)) {
-                               bitmap_clear(p_spq->p_comp_bitmap,
-                                            p_spq->comp_bitmap_idx,
-                                            SPQ_RING_SIZE);
+                               __clear_bit(p_spq->comp_bitmap_idx,
+                                           p_spq->p_comp_bitmap);
                                p_spq->comp_bitmap_idx++;
                                qed_chain_return_produced(&p_spq->chain);
                        }
index 0e2fc1a844ab2b2453681750368e1cf9d288e779..8c44cf6ff7a2f16e96bd91f577a028d5dee9e754 100644 (file)
@@ -2269,6 +2269,13 @@ static int smc_drv_probe(struct platform_device *pdev)
        if (pd) {
                memcpy(&lp->cfg, pd, sizeof(lp->cfg));
                lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags);
+
+               if (!SMC_8BIT(lp) && !SMC_16BIT(lp)) {
+                       dev_err(&pdev->dev,
+                               "at least one of 8-bit or 16-bit access support is required.\n");
+                       ret = -ENXIO;
+                       goto out_free_netdev;
+               }
        }
 
 #if IS_BUILTIN(CONFIG_OF)
index a3c129e1e40ac1e2c6785ff30fd4af41cb68ecb2..29df0465daf46c29780e0834f92c13b7c3f00155 100644 (file)
 #include <linux/dmaengine.h>
 #include <linux/smc91x.h>
 
+/*
+ * Any 16-bit access is performed with two 8-bit accesses if the hardware
+ * can't do it directly. Most registers are 16-bit so those are mandatory.
+ */
+#define SMC_outw_b(x, a, r)                                            \
+       do {                                                            \
+               unsigned int __val16 = (x);                             \
+               unsigned int __reg = (r);                               \
+               SMC_outb(__val16, a, __reg);                            \
+               SMC_outb(__val16 >> 8, a, __reg + (1 << SMC_IO_SHIFT)); \
+       } while (0)
+
+#define SMC_inw_b(a, r)                                                        \
+       ({                                                              \
+               unsigned int __val16;                                   \
+               unsigned int __reg = r;                                 \
+               __val16  = SMC_inb(a, __reg);                           \
+               __val16 |= SMC_inb(a, __reg + (1 << SMC_IO_SHIFT)) << 8; \
+               __val16;                                                \
+       })
+
 /*
  * Define your architecture specific bus configuration parameters here.
  */
 #define SMC_IO_SHIFT           (lp->io_shift)
 
 #define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_inw(a, r)                                                  \
+       ({                                                              \
+               unsigned int __smc_r = r;                               \
+               SMC_16BIT(lp) ? readw((a) + __smc_r) :                  \
+               SMC_8BIT(lp) ? SMC_inw_b(a, __smc_r) :                  \
+               ({ BUG(); 0; });                                        \
+       })
+
 #define SMC_inl(a, r)          readl((a) + (r))
 #define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_outw(v, a, r)                                              \
+       do {                                                            \
+               unsigned int __v = v, __smc_r = r;                      \
+               if (SMC_16BIT(lp))                                      \
+                       __SMC_outw(__v, a, __smc_r);                    \
+               else if (SMC_8BIT(lp))                                  \
+                       SMC_outw_b(__v, a, __smc_r);                    \
+               else                                                    \
+                       BUG();                                          \
+       } while (0)
+
 #define SMC_outl(v, a, r)      writel(v, (a) + (r))
+#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, l)
+#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, l)
 #define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
 #define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
 #define SMC_IRQ_FLAGS          (-1)    /* from resource */
 
 /* We actually can't write halfwords properly if not word aligned */
-static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
+static inline void __SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 {
        if ((machine_is_mainstone() || machine_is_stargate2() ||
             machine_is_pxa_idp()) && reg & 2) {
@@ -405,24 +446,8 @@ smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
 
 #if ! SMC_CAN_USE_16BIT
 
-/*
- * Any 16-bit access is performed with two 8-bit accesses if the hardware
- * can't do it directly. Most registers are 16-bit so those are mandatory.
- */
-#define SMC_outw(x, ioaddr, reg)                                       \
-       do {                                                            \
-               unsigned int __val16 = (x);                             \
-               SMC_outb( __val16, ioaddr, reg );                       \
-               SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\
-       } while (0)
-#define SMC_inw(ioaddr, reg)                                           \
-       ({                                                              \
-               unsigned int __val16;                                   \
-               __val16 =  SMC_inb( ioaddr, reg );                      \
-               __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \
-               __val16;                                                \
-       })
-
+#define SMC_outw(x, ioaddr, reg)       SMC_outw_b(x, ioaddr, reg)
+#define SMC_inw(ioaddr, reg)           SMC_inw_b(ioaddr, reg)
 #define SMC_insw(a, r, p, l)           BUG()
 #define SMC_outsw(a, r, p, l)          BUG()
 
index 47cd306dbb3c4909ae95feb586f0b89198126995..bba0ca786aaac22bf5afc2d6acd5b584d0ecb958 100644 (file)
@@ -640,8 +640,10 @@ phy_err:
 int phy_start_interrupts(struct phy_device *phydev)
 {
        atomic_set(&phydev->irq_disable, 0);
-       if (request_irq(phydev->irq, phy_interrupt, 0, "phy_interrupt",
-                       phydev) < 0) {
+       if (request_irq(phydev->irq, phy_interrupt,
+                               IRQF_SHARED,
+                               "phy_interrupt",
+                               phydev) < 0) {
                pr_warn("%s: Can't get IRQ %d (PHY)\n",
                        phydev->bus->name, phydev->irq);
                phydev->irq = PHY_POLL;
index 174e06ec7c2fe88014ee77c8a60e99788e459072..e5bb870b5461aa9afd81b1a41f36bbf6f4a58234 100644 (file)
@@ -2390,8 +2390,6 @@ 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);
@@ -2984,6 +2982,9 @@ ppp_disconnect_channel(struct channel *pch)
  */
 static void ppp_destroy_channel(struct channel *pch)
 {
+       put_net(pch->chan_net);
+       pch->chan_net = NULL;
+
        atomic_dec(&channel_count);
 
        if (!pch->file.dead) {
index 62f2d80a9fe01e2767114a3bc6de4ab8f94981f1..6941f0888b0023e1eb0f4ca3647ee39e241e1776 100644 (file)
@@ -862,10 +862,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
                goto drop;
 
-       if (skb->sk && sk_fullsock(skb->sk)) {
-               sock_tx_timestamp(skb->sk, &skb_shinfo(skb)->tx_flags);
-               sw_tx_timestamp(skb);
-       }
+       skb_tx_timestamp(skb);
 
        /* Orphan the skb - required as we might hang on to it
         * for indefinite time.
index 8b4561e8ce1aacf0ff2523cad1069d67bf2ca15f..ef493271c7129307ecb3de7acebbd8a8d8f760bf 100644 (file)
@@ -4176,7 +4176,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
                ar9003_hw_internal_regulator_apply(ah);
        ar9003_hw_apply_tuning_caps(ah);
-       ar9003_hw_apply_minccapwr_thresh(ah, chan);
+       ar9003_hw_apply_minccapwr_thresh(ah, is2ghz);
        ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
        ar9003_hw_thermometer_apply(ah);
        ar9003_hw_thermo_cal_apply(ah);
index 1bdeacf7b25754fbe72a29009e5ea03dac58ce29..bc70ce62bc03ce5e82844afc11ad268426a0cd3a 100644 (file)
@@ -869,8 +869,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                        hw->wiphy->interface_modes |=
                                        BIT(NL80211_IFTYPE_P2P_DEVICE);
 
-                       hw->wiphy->iface_combinations = if_comb;
-                       hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+               hw->wiphy->iface_combinations = if_comb;
+               hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
        }
 
        hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
index d184e682e63642955960fbcfc8602dda4ac1997c..8c5d2cf9c97981c42c4b792b878cb87589f1a120 100644 (file)
@@ -1550,13 +1550,13 @@ static int ath9k_sta_state(struct ieee80211_hw *hw,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int ret = 0;
 
-       if (old_state == IEEE80211_STA_AUTH &&
-           new_state == IEEE80211_STA_ASSOC) {
+       if (old_state == IEEE80211_STA_NOTEXIST &&
+           new_state == IEEE80211_STA_NONE) {
                ret = ath9k_sta_add(hw, vif, sta);
                ath_dbg(common, CONFIG,
                        "Add station: %pM\n", sta->addr);
-       } else if (old_state == IEEE80211_STA_ASSOC &&
-                  new_state == IEEE80211_STA_AUTH) {
+       } else if (old_state == IEEE80211_STA_NONE &&
+                  new_state == IEEE80211_STA_NOTEXIST) {
                ret = ath9k_sta_remove(hw, vif, sta);
                ath_dbg(common, CONFIG,
                        "Remove station: %pM\n", sta->addr);
index 410a6645d316ec1c2cf5d09b54847e918dde0045..59cef6c69fe86a99623b8dc490d7c38c34bb581f 100644 (file)
@@ -726,8 +726,10 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
                        return -ENOMEM;
                err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
                                         glom_skb);
-               if (err)
+               if (err) {
+                       brcmu_pkt_buf_free_skb(glom_skb);
                        goto done;
+               }
 
                skb_queue_walk(pktq, skb) {
                        memcpy(skb->data, glom_skb->data, skb->len);
index deb5f78dcacc0d9ef188360d300a7b4f1bcfba19..70a6985334d5b518f517848b5f969cec80b3c5f2 100644 (file)
@@ -2408,7 +2408,7 @@ static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
                                     WL_BSS_INFO_MAX);
        if (err) {
                brcmf_err("Failed to get bss info (%d)\n", err);
-               return;
+               goto out_kfree;
        }
        si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
        si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
@@ -2420,6 +2420,9 @@ static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si)
                si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
        if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+
+out_kfree:
+       kfree(buf);
 }
 
 static s32
@@ -4099,7 +4102,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                                (u8 *)&settings->beacon.head[ie_offset],
                                settings->beacon.head_len - ie_offset,
                                WLAN_EID_SSID);
-               if (!ssid_ie)
+               if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
                        return -EINVAL;
 
                memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
index 7e74ac3ad81519491ac01460cd3b578e6fb3cc80..bcf29bf6f727be6b16a52da24f1213b5e73d2fb4 100644 (file)
@@ -3401,10 +3401,6 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
                goto err;
        }
 
-       /* Allow full data communication using DPC from now on. */
-       brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
-       bcmerror = 0;
-
 err:
        brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
        sdio_release_host(bus->sdiodev->func[1]);
@@ -4112,6 +4108,9 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
        }
 
        if (err == 0) {
+               /* Allow full data communication using DPC from now on. */
+               brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
+
                err = brcmf_sdiod_intr_register(sdiodev);
                if (err != 0)
                        brcmf_err("intr register failed:%d\n", err);
index 796f5f9d5d5a45bc621b0fd7e880a112aee1067a..b7df576bb84d9bfe5f4134bad4323ab48b8c9ed8 100644 (file)
@@ -1079,8 +1079,10 @@ bool dma_rxfill(struct dma_pub *pub)
 
                pa = dma_map_single(di->dmadev, p->data, di->rxbufsize,
                                    DMA_FROM_DEVICE);
-               if (dma_mapping_error(di->dmadev, pa))
+               if (dma_mapping_error(di->dmadev, pa)) {
+                       brcmu_pkt_buf_free_skb(p);
                        return false;
+               }
 
                /* save the free packet pointer */
                di->rxp[rxout] = p;
index dd9162722495333df13296c80d89c20ea9058d74..0ab865de14918cfd8939133eabf790d765ff5b07 100644 (file)
@@ -87,7 +87,7 @@ void
 brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
                            u16 chanspec)
 {
-       struct tx_power power;
+       struct tx_power power = { };
        u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
 
        /* Clear previous settings */
index 93bdf684babe36392daa84eca81e7d52a529d8a5..ae047ab7a4dfa225908430a14255e2285d0dd888 100644 (file)
@@ -1019,12 +1019,13 @@ il3945_hw_txq_ctx_free(struct il_priv *il)
        int txq_id;
 
        /* Tx queues */
-       if (il->txq)
+       if (il->txq) {
                for (txq_id = 0; txq_id < il->hw_params.max_txq_num; txq_id++)
                        if (txq_id == IL39_CMD_QUEUE_NUM)
                                il_cmd_queue_free(il);
                        else
                                il_tx_queue_free(il, txq_id);
+       }
 
        /* free tx queue structure */
        il_free_txq_mem(il);
index 20e6aa9107009ccc33246190534cbc7674c54d03..c148085742a00caf29fcb0c007d9521c6c96ba3c 100644 (file)
@@ -901,7 +901,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
                /* bound gain by 2 bits value max, 3rd bit is sign */
                data->delta_gain_code[i] =
                        min(abs(delta_g),
-                       (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+                       (s32) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
 
                if (delta_g < 0)
                        /*
index 610c442c7ab2f8194f4c4777c44070eacab322a4..9584f950fd2f819a5add840fb74a33388ef83ee8 100644 (file)
@@ -935,7 +935,8 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
        }
 
        mvm->fw_dbg_conf = conf_id;
-       return ret;
+
+       return 0;
 }
 
 static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
index f96ab2f4b90ebc2b3522764705f30fd816413c1b..ce12717e656ad771350c8b50a5e820e9d4da63a0 100644 (file)
@@ -3992,8 +3992,8 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
        if (idx != 0)
                return -ENOENT;
 
-       if (fw_has_capa(&mvm->fw->ucode_capa,
-                       IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+       if (!fw_has_capa(&mvm->fw->ucode_capa,
+                        IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
                return -ENOENT;
 
        mutex_lock(&mvm->mutex);
@@ -4039,8 +4039,8 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 
-       if (fw_has_capa(&mvm->fw->ucode_capa,
-                       IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
+       if (!fw_has_capa(&mvm->fw->ucode_capa,
+                        IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
                return;
 
        /* if beacon filtering isn't on mac80211 does it anyway */
index b0f59fdd287c787cbb0f65ca319aebfadb850d31..d7d72adb6343d4cdddf61fbc40d000a4a075e069 100644 (file)
@@ -215,7 +215,7 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
                             enum iwl_sf_state new_state)
 {
        struct iwl_sf_cfg_cmd sf_cmd = {
-               .state = cpu_to_le32(SF_FULL_ON),
+               .state = cpu_to_le32(new_state),
        };
        struct ieee80211_sta *sta;
        int ret = 0;
index a8c8a4a7420b53d02a798bcc261f408f77440ace..8dfe6b2bc703186080ccb510a03b40135346053c 100644 (file)
@@ -1508,9 +1508,9 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
 
        /* start the TFD with the scratchbuf */
        scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE);
-       memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size);
+       memcpy(&txq->scratchbufs[idx], &out_cmd->hdr, scratch_size);
        iwl_pcie_txq_build_tfd(trans, txq,
-                              iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr),
+                              iwl_pcie_get_scratchbuf_dma(txq, idx),
                               scratch_size, true);
 
        /* map first command fragment, if any remains */
index 3cda1f956f0b1654ec438291e22f416ada279e17..6378dfd3b4e864da8b347d4e308defe989129db9 100644 (file)
@@ -661,9 +661,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
        priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
                                   sizeof(priv->assoc_rsp_buf));
 
-       memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
-
        assoc_rsp->a_id = cpu_to_le16(aid);
+       memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
 
        if (status_code) {
                priv->adapter->dbg.num_cmd_assoc_failure++;
index 5be34118e0af22b69392f5caf07f9eef5672c7fe..f67e7e5b13e192189c3f649a3aceb9ac50d6d57f 100644 (file)
@@ -345,9 +345,9 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
                return &rtl_regdom_no_midband;
        case COUNTRY_CODE_IC:
                return &rtl_regdom_11;
-       case COUNTRY_CODE_ETSI:
        case COUNTRY_CODE_TELEC_NETGEAR:
                return &rtl_regdom_60_64;
+       case COUNTRY_CODE_ETSI:
        case COUNTRY_CODE_SPAIN:
        case COUNTRY_CODE_FRANCE:
        case COUNTRY_CODE_ISRAEL:
@@ -406,6 +406,8 @@ static u8 channel_plan_to_country_code(u8 channelplan)
                return COUNTRY_CODE_WORLD_WIDE_13;
        case 0x22:
                return COUNTRY_CODE_IC;
+       case 0x25:
+               return COUNTRY_CODE_ETSI;
        case 0x32:
                return COUNTRY_CODE_TELEC_NETGEAR;
        case 0x41:
index ccb07a1b153db27f5cadb57d1152d3fdd4b4e8b8..23e53780728beb766b77ddb4313722fd4b13753c 100644 (file)
@@ -352,7 +352,7 @@ static int fdp_nci_patch_otp(struct nci_dev *ndev)
 {
        struct fdp_nci_info *info = nci_get_drvdata(ndev);
        struct device *dev = &info->phy->i2c_dev->dev;
-       u8 conn_id;
+       int conn_id;
        int r = 0;
 
        if (info->otp_version >= info->otp_patch_version)
@@ -423,7 +423,7 @@ static int fdp_nci_patch_ram(struct nci_dev *ndev)
 {
        struct fdp_nci_info *info = nci_get_drvdata(ndev);
        struct device *dev = &info->phy->i2c_dev->dev;
-       u8 conn_id;
+       int conn_id;
        int r = 0;
 
        if (info->ram_version >= info->ram_patch_version)
index 0c67b57be83c4630a89c670acbbd150b65ec667f..c851bc53831c1267c0cccab074e5cd141b1d5825 100644 (file)
@@ -2672,10 +2672,10 @@ static int nvme_dev_add(struct nvme_dev *dev)
        return 0;
 }
 
-static int nvme_dev_map(struct nvme_dev *dev)
+static int nvme_pci_enable(struct nvme_dev *dev)
 {
        u64 cap;
-       int bars, result = -ENOMEM;
+       int result = -ENOMEM;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        if (pci_enable_device_mem(pdev))
@@ -2683,24 +2683,14 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        dev->entry[0].vector = pdev->irq;
        pci_set_master(pdev);
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       if (!bars)
-               goto disable_pci;
-
-       if (pci_request_selected_regions(pdev, bars, "nvme"))
-               goto disable_pci;
 
        if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
            dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
                goto disable;
 
-       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
-       if (!dev->bar)
-               goto disable;
-
        if (readl(&dev->bar->csts) == -1) {
                result = -ENODEV;
-               goto unmap;
+               goto disable;
        }
 
        /*
@@ -2710,7 +2700,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
        if (!pdev->irq) {
                result = pci_enable_msix(pdev, dev->entry, 1);
                if (result < 0)
-                       goto unmap;
+                       goto disable;
        }
 
        cap = lo_hi_readq(&dev->bar->cap);
@@ -2734,17 +2724,20 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        return 0;
 
- unmap:
-       iounmap(dev->bar);
-       dev->bar = NULL;
  disable:
-       pci_release_regions(pdev);
- disable_pci:
        pci_disable_device(pdev);
+
        return result;
 }
 
 static void nvme_dev_unmap(struct nvme_dev *dev)
+{
+       if (dev->bar)
+               iounmap(dev->bar);
+       pci_release_regions(to_pci_dev(dev->dev));
+}
+
+static void nvme_pci_disable(struct nvme_dev *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
@@ -2753,12 +2746,6 @@ static void nvme_dev_unmap(struct nvme_dev *dev)
        else if (pdev->msix_enabled)
                pci_disable_msix(pdev);
 
-       if (dev->bar) {
-               iounmap(dev->bar);
-               dev->bar = NULL;
-               pci_release_regions(pdev);
-       }
-
        if (pci_is_enabled(pdev))
                pci_disable_device(pdev);
 }
@@ -2962,7 +2949,7 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
 
        nvme_dev_list_remove(dev);
 
-       if (dev->bar) {
+       if (pci_is_enabled(to_pci_dev(dev->dev))) {
                nvme_freeze_queues(dev);
                csts = readl(&dev->bar->csts);
        }
@@ -2976,7 +2963,7 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
                nvme_shutdown_ctrl(dev);
                nvme_disable_queue(dev, 0);
        }
-       nvme_dev_unmap(dev);
+       nvme_pci_disable(dev);
 
        for (i = dev->queue_count - 1; i >= 0; i--)
                nvme_clear_queue(dev->queues[i]);
@@ -3136,7 +3123,7 @@ static void nvme_probe_work(struct work_struct *work)
        bool start_thread = false;
        int result;
 
-       result = nvme_dev_map(dev);
+       result = nvme_pci_enable(dev);
        if (result)
                goto out;
 
@@ -3292,6 +3279,27 @@ static ssize_t nvme_sysfs_reset(struct device *dev,
 }
 static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset);
 
+static int nvme_dev_map(struct nvme_dev *dev)
+{
+       int bars;
+       struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (!bars)
+               return -ENODEV;
+       if (pci_request_selected_regions(pdev, bars, "nvme"))
+               return -ENODEV;
+
+       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+       if (!dev->bar)
+               goto release;
+
+       return 0;
+release:
+       pci_release_regions(pdev);
+       return -ENODEV;
+}
+
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int node, result = -ENOMEM;
@@ -3317,6 +3325,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        INIT_WORK(&dev->reset_work, nvme_reset_work);
        dev->dev = get_device(&pdev->dev);
        pci_set_drvdata(pdev, dev);
+
+       result = nvme_dev_map(dev);
+       if (result)
+               goto free;
+
        result = nvme_set_instance(dev);
        if (result)
                goto put_pci;
@@ -3355,6 +3368,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        nvme_release_instance(dev);
  put_pci:
        put_device(dev->dev);
+       nvme_dev_unmap(dev);
  free:
        kfree(dev->queues);
        kfree(dev->entry);
@@ -3398,6 +3412,7 @@ static void nvme_remove(struct pci_dev *pdev)
        nvme_free_queues(dev, 0);
        nvme_release_cmb(dev);
        nvme_release_prp_pools(dev);
+       nvme_dev_unmap(dev);
        kref_put(&dev->kref, nvme_free_dev);
 }
 
index 017dd94f16ea3dd8ebbc37b81188f2d47933e878..31341290cd9136ab0b2830c67422eb334ed32f4e 100644 (file)
@@ -112,6 +112,7 @@ static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj,
        return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);
 }
 
+/* always return newly allocated name, caller must free after use */
 static const char *safe_name(struct kobject *kobj, const char *orig_name)
 {
        const char *name = orig_name;
@@ -126,9 +127,12 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name)
                name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i);
        }
 
-       if (name != orig_name)
+       if (name == orig_name) {
+               name = kstrdup(orig_name, GFP_KERNEL);
+       } else {
                pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",
                        kobject_name(kobj), name);
+       }
        return name;
 }
 
@@ -159,6 +163,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp)
 int __of_attach_node_sysfs(struct device_node *np)
 {
        const char *name;
+       struct kobject *parent;
        struct property *pp;
        int rc;
 
@@ -171,15 +176,16 @@ int __of_attach_node_sysfs(struct device_node *np)
        np->kobj.kset = of_kset;
        if (!np->parent) {
                /* Nodes without parents are new top level trees */
-               rc = kobject_add(&np->kobj, NULL, "%s",
-                                safe_name(&of_kset->kobj, "base"));
+               name = safe_name(&of_kset->kobj, "base");
+               parent = NULL;
        } else {
                name = safe_name(&np->parent->kobj, kbasename(np->full_name));
-               if (!name || !name[0])
-                       return -EINVAL;
-
-               rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);
+               parent = &np->parent->kobj;
        }
+       if (!name)
+               return -ENOMEM;
+       rc = kobject_add(&np->kobj, parent, "%s", name);
+       kfree(name);
        if (rc)
                return rc;
 
@@ -1753,6 +1759,12 @@ int __of_remove_property(struct device_node *np, struct property *prop)
        return 0;
 }
 
+void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop)
+{
+       sysfs_remove_bin_file(&np->kobj, &prop->attr);
+       kfree(prop->attr.attr.name);
+}
+
 void __of_remove_property_sysfs(struct device_node *np, struct property *prop)
 {
        if (!IS_ENABLED(CONFIG_SYSFS))
@@ -1760,7 +1772,7 @@ void __of_remove_property_sysfs(struct device_node *np, struct property *prop)
 
        /* at early boot, bail here and defer setup to of_init() */
        if (of_kset && of_node_is_attached(np))
-               sysfs_remove_bin_file(&np->kobj, &prop->attr);
+               __of_sysfs_remove_bin_file(np, prop);
 }
 
 /**
@@ -1830,7 +1842,7 @@ void __of_update_property_sysfs(struct device_node *np, struct property *newprop
                return;
 
        if (oldprop)
-               sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+               __of_sysfs_remove_bin_file(np, oldprop);
        __of_add_property_sysfs(np, newprop);
 }
 
@@ -2241,20 +2253,13 @@ struct device_node *of_graph_get_endpoint_by_regs(
        const struct device_node *parent, int port_reg, int reg)
 {
        struct of_endpoint endpoint;
-       struct device_node *node, *prev_node = NULL;
-
-       while (1) {
-               node = of_graph_get_next_endpoint(parent, prev_node);
-               of_node_put(prev_node);
-               if (!node)
-                       break;
+       struct device_node *node = NULL;
 
+       for_each_endpoint_of_node(parent, node) {
                of_graph_parse_endpoint(node, &endpoint);
                if (((port_reg == -1) || (endpoint.port == port_reg)) &&
                        ((reg == -1) || (endpoint.id == reg)))
                        return node;
-
-               prev_node = node;
        }
 
        return NULL;
index 53826b84e0ec6d46d3699705f46216070a471867..2d72ddcf534f02699c1ea3b2ed2471670e5a85e9 100644 (file)
@@ -55,7 +55,7 @@ void __of_detach_node_sysfs(struct device_node *np)
        /* only remove properties if on sysfs */
        if (of_node_is_attached(np)) {
                for_each_property_of_node(np, pp)
-                       sysfs_remove_bin_file(&np->kobj, &pp->attr);
+                       __of_sysfs_remove_bin_file(np, pp);
                kobject_del(&np->kobj);
        }
 
index 8e882e706cd8c6b4edc61f577d7808e0e6e74df7..46ddbee22ce3b8dc5fd08ffd710736f265ee118e 100644 (file)
@@ -81,6 +81,9 @@ extern int __of_attach_node_sysfs(struct device_node *np);
 extern void __of_detach_node(struct device_node *np);
 extern void __of_detach_node_sysfs(struct device_node *np);
 
+extern void __of_sysfs_remove_bin_file(struct device_node *np,
+                                      struct property *prop);
+
 /* iterators for transactions, used for overlays */
 /* forward iterator */
 #define for_each_transaction_entry(_oft, _te) \
index 7eaa4c87fec71c8dd792ccffc919b322711d91dd..10a6a8e5db887bbeb67b7c6adb5e0233ac0d724f 100644 (file)
@@ -1278,6 +1278,8 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
        if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
                pci_msi_domain_update_chip_ops(info);
 
+       info->flags |= MSI_FLAG_ACTIVATE_EARLY;
+
        domain = msi_create_irq_domain(fwnode, info, parent);
        if (!domain)
                return NULL;
index eead54cd01b2bfad6a5514f53067429e616db6b7..d7508704c992f2f252411bb20034a16599398c50 100644 (file)
@@ -1372,10 +1372,10 @@ int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
        if (!sysfs_initialized)
                return -EACCES;
 
-       if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
-               retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
-       else
+       if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
                retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+       else
+               retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
        if (retval)
                goto err;
 
@@ -1427,10 +1427,10 @@ err_rom_file:
 err_resource_files:
        pci_remove_resource_files(pdev);
 err_config_file:
-       if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
-               sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
-       else
+       if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
                sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+       else
+               sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
 err:
        return retval;
 }
@@ -1464,10 +1464,10 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
 
        pci_remove_capabilities_sysfs(pdev);
 
-       if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
-               sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
-       else
+       if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
                sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+       else
+               sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
 
        pci_remove_resource_files(pdev);
 
index 7e327309cf69f612b05cdb1544ff5c4deba9f68e..254192b5dad1a7afece5731806e85e844398827d 100644 (file)
@@ -287,6 +287,18 @@ static void quirk_citrine(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CITRINE,      quirk_citrine);
 
+/*
+ * This chip can cause bus lockups if config addresses above 0x600
+ * are read or written.
+ */
+static void quirk_nfp6000(struct pci_dev *dev)
+{
+       dev->cfg_size = 0x600;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME,      PCI_DEVICE_ID_NETRONOME_NFP4000,        quirk_nfp6000);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME,      PCI_DEVICE_ID_NETRONOME_NFP6000,        quirk_nfp6000);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETRONOME,      PCI_DEVICE_ID_NETRONOME_NFP6000_VF,     quirk_nfp6000);
+
 /*  On IBM Crocodile ipr SAS adapters, expand BAR to system page size */
 static void quirk_extend_bar_to_page(struct pci_dev *dev)
 {
@@ -3115,13 +3127,16 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
 }
 
 /*
- * Atheros AR93xx chips do not behave after a bus reset.  The device will
- * throw a Link Down error on AER-capable systems and regardless of AER,
- * config space of the device is never accessible again and typically
- * causes the system to hang or reset when access is attempted.
+ * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
+ * The device will throw a Link Down error on AER-capable systems and
+ * regardless of AER, config space of the device is never accessible again
+ * and typically causes the system to hang or reset when access is attempted.
  * http://www.spinics.net/lists/linux-pci/msg34797.html
  */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
 
 static void quirk_no_pm_reset(struct pci_dev *dev)
 {
index 0c569065dcbbbc0b25767d85570be0c8d0d9f361..3ad5326d72e4b8deec73d8742a8817ad6578a322 100644 (file)
@@ -818,6 +818,7 @@ static int of_pmu_irq_cfg(struct arm_pmu *pmu)
                        if (i > 0 && spi != using_spi) {
                                pr_err("PPI/SPI IRQ type mismatch for %s!\n",
                                        dn->name);
+                               of_node_put(dn);
                                kfree(irqs);
                                return -EINVAL;
                        }
index 1029aa7889b55233fd0b5e3cf5d31ea245f9e2c7..398ec45aadef9fcf335b9604c0ce641dff9fa3c7 100644 (file)
@@ -207,9 +207,9 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
                pin_reg = &info->pin_regs[pin_id];
 
                if (pin_reg->mux_reg == -1) {
-                       dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
+                       dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n",
                                info->pins[pin_id].name);
-                       return -EINVAL;
+                       continue;
                }
 
                if (info->flags & SHARE_MUX_CONF_REG) {
index 84936bae6e5ee07f741477cd185509f86bb816a7..4e377599d26622f25025119849ed7b76b78be594 100644 (file)
@@ -160,7 +160,6 @@ struct chv_pin_context {
  * @pctldev: Pointer to the pin controller device
  * @chip: GPIO chip in this pin controller
  * @regs: MMIO registers
- * @lock: Lock to serialize register accesses
  * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
  *             offset (in GPIO number space)
  * @community: Community this pinctrl instance represents
@@ -174,7 +173,6 @@ struct chv_pinctrl {
        struct pinctrl_dev *pctldev;
        struct gpio_chip chip;
        void __iomem *regs;
-       raw_spinlock_t lock;
        unsigned intr_lines[16];
        const struct chv_community *community;
        u32 saved_intmask;
@@ -659,6 +657,17 @@ static const struct chv_community *chv_communities[] = {
        &southeast_community,
 };
 
+/*
+ * Lock to serialize register accesses
+ *
+ * Due to a silicon issue, a shared lock must be used to prevent
+ * concurrent accesses across the 4 GPIO controllers.
+ *
+ * See Intel Atom Z8000 Processor Series Specification Update (Rev. 005),
+ * errata #CHT34, for further information.
+ */
+static DEFINE_RAW_SPINLOCK(chv_lock);
+
 static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset,
                                unsigned reg)
 {
@@ -720,13 +729,13 @@ static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
        u32 ctrl0, ctrl1;
        bool locked;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
        ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1));
        locked = chv_pad_locked(pctrl, offset);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        if (ctrl0 & CHV_PADCTRL0_GPIOEN) {
                seq_puts(s, "GPIO ");
@@ -789,14 +798,14 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
 
        grp = &pctrl->community->groups[group];
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        /* Check first that the pad is not locked */
        for (i = 0; i < grp->npins; i++) {
                if (chv_pad_locked(pctrl, grp->pins[i])) {
                        dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
                                 grp->pins[i]);
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EBUSY;
                }
        }
@@ -839,7 +848,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
                        pin, altfunc->mode, altfunc->invert_oe ? "" : "not ");
        }
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -853,13 +862,13 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        if (chv_pad_locked(pctrl, offset)) {
                value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
                if (!(value & CHV_PADCTRL0_GPIOEN)) {
                        /* Locked so cannot enable */
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EBUSY;
                }
        } else {
@@ -899,7 +908,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
                chv_writel(value, reg);
        }
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -913,13 +922,13 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
        value = readl(reg) & ~CHV_PADCTRL0_GPIOEN;
        chv_writel(value, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -931,7 +940,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
        unsigned long flags;
        u32 ctrl0;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK;
        if (input)
@@ -940,7 +949,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
                ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT;
        chv_writel(ctrl0, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -965,10 +974,10 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
        u16 arg = 0;
        u32 term;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT;
 
@@ -1042,7 +1051,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
        unsigned long flags;
        u32 ctrl0, pull;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(reg);
 
        switch (param) {
@@ -1065,7 +1074,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                        pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
                        break;
                default:
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EINVAL;
                }
 
@@ -1083,7 +1092,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                        pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
                        break;
                default:
-                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&chv_lock, flags);
                        return -EINVAL;
                }
 
@@ -1091,12 +1100,12 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
                break;
 
        default:
-               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&chv_lock, flags);
                return -EINVAL;
        }
 
        chv_writel(ctrl0, reg);
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -1162,9 +1171,9 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
        unsigned long flags;
        u32 ctrl0, cfg;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
        cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1182,7 +1191,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        void __iomem *reg;
        u32 ctrl0;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
        ctrl0 = readl(reg);
@@ -1194,7 +1203,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
        chv_writel(ctrl0, reg);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -1204,9 +1213,9 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
        u32 ctrl0, direction;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
        ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
        direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
@@ -1244,14 +1253,14 @@ static void chv_gpio_irq_ack(struct irq_data *d)
        int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
        u32 intr_line;
 
-       raw_spin_lock(&pctrl->lock);
+       raw_spin_lock(&chv_lock);
 
        intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        intr_line &= CHV_PADCTRL0_INTSEL_MASK;
        intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT;
        chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT);
 
-       raw_spin_unlock(&pctrl->lock);
+       raw_spin_unlock(&chv_lock);
 }
 
 static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
@@ -1262,7 +1271,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
        u32 value, intr_line;
        unsigned long flags;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
        intr_line &= CHV_PADCTRL0_INTSEL_MASK;
@@ -1275,7 +1284,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
                value |= BIT(intr_line);
        chv_writel(value, pctrl->regs + CHV_INTMASK);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 }
 
 static void chv_gpio_irq_mask(struct irq_data *d)
@@ -1309,7 +1318,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
                unsigned long flags;
                u32 intsel, value;
 
-               raw_spin_lock_irqsave(&pctrl->lock, flags);
+               raw_spin_lock_irqsave(&chv_lock, flags);
                intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
                intsel &= CHV_PADCTRL0_INTSEL_MASK;
                intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
@@ -1324,7 +1333,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d)
                        irq_set_handler_locked(d, handler);
                        pctrl->intr_lines[intsel] = offset;
                }
-               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&chv_lock, flags);
        }
 
        chv_gpio_irq_unmask(d);
@@ -1340,7 +1349,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
        unsigned long flags;
        u32 value;
 
-       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&chv_lock, flags);
 
        /*
         * Pins which can be used as shared interrupt are configured in
@@ -1389,7 +1398,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
        else if (type & IRQ_TYPE_LEVEL_MASK)
                irq_set_handler_locked(d, handle_level_irq);
 
-       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&chv_lock, flags);
 
        return 0;
 }
@@ -1501,7 +1510,6 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
        if (i == ARRAY_SIZE(chv_communities))
                return -ENODEV;
 
-       raw_spin_lock_init(&pctrl->lock);
        pctrl->dev = &pdev->dev;
 
 #ifdef CONFIG_PM_SLEEP
index 3318f1d6193c8a49f1ca8f4348dd25010fe18758..7340ff78839a340ef260836b3094ae0f8e4e2e32 100644 (file)
@@ -48,17 +48,6 @@ static int amd_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 
        spin_lock_irqsave(&gpio_dev->lock, flags);
        pin_reg = readl(gpio_dev->base + offset * 4);
-       /*
-        * Suppose BIOS or Bootloader sets specific debounce for the
-        * GPIO. if not, set debounce to be  2.75ms and remove glitch.
-       */
-       if ((pin_reg & DB_TMR_OUT_MASK) == 0) {
-               pin_reg |= 0xf;
-               pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF);
-               pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF;
-               pin_reg &= ~BIT(DB_TMR_LARGE_OFF);
-       }
-
        pin_reg &= ~BIT(OUTPUT_ENABLE_OFF);
        writel(pin_reg, gpio_dev->base + offset * 4);
        spin_unlock_irqrestore(&gpio_dev->lock, flags);
@@ -331,15 +320,6 @@ static void amd_gpio_irq_enable(struct irq_data *d)
 
        spin_lock_irqsave(&gpio_dev->lock, flags);
        pin_reg = readl(gpio_dev->base + (d->hwirq)*4);
-       /*
-               Suppose BIOS or Bootloader sets specific debounce for the
-               GPIO. if not, set debounce to be  2.75ms.
-       */
-       if ((pin_reg & DB_TMR_OUT_MASK) == 0) {
-               pin_reg |= 0xf;
-               pin_reg |= BIT(DB_TMR_OUT_UNIT_OFF);
-               pin_reg &= ~BIT(DB_TMR_LARGE_OFF);
-       }
        pin_reg |= BIT(INTERRUPT_ENABLE_OFF);
        pin_reg |= BIT(INTERRUPT_MASK_OFF);
        writel(pin_reg, gpio_dev->base + (d->hwirq)*4);
index b3235fd2950c6624a12477e452331e41dd95e92c..271cca63e9bd237f96a878f4dfe7c69b3f07f3aa 100644 (file)
@@ -1002,7 +1002,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
                atmel_pioctrl->irqs[i] = res->start;
                irq_set_chained_handler(res->start, atmel_gpio_irq_handler);
                irq_set_handler_data(res->start, atmel_pioctrl);
-               dev_dbg(dev, "bank %i: hwirq=%u\n", i, res->start);
+               dev_dbg(dev, "bank %i: irq=%pr\n", i, res);
        }
 
        atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node,
index 6b1a47f8c0969208406d1dcc662f21389a0a2027..98a459b1c095a68fe526ff04309e9138bfe7aa34 100644 (file)
@@ -809,17 +809,17 @@ static const struct pistachio_pin_group pistachio_groups[] = {
                           PADS_FUNCTION_SELECT2, 12, 0x3),
        MFIO_MUX_PIN_GROUP(83, MIPS_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
                           PADS_FUNCTION_SELECT2, 14, 0x3),
-       MFIO_MUX_PIN_GROUP(84, SYS_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
+       MFIO_MUX_PIN_GROUP(84, AUDIO_PLL_LOCK, MIPS_TRACE_DATA, USB_DEBUG,
                           PADS_FUNCTION_SELECT2, 16, 0x3),
-       MFIO_MUX_PIN_GROUP(85, WIFI_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
+       MFIO_MUX_PIN_GROUP(85, RPU_V_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
                           PADS_FUNCTION_SELECT2, 18, 0x3),
-       MFIO_MUX_PIN_GROUP(86, BT_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
+       MFIO_MUX_PIN_GROUP(86, RPU_L_PLL_LOCK, MIPS_TRACE_DATA, SDHOST_DEBUG,
                           PADS_FUNCTION_SELECT2, 20, 0x3),
-       MFIO_MUX_PIN_GROUP(87, RPU_V_PLL_LOCK, DREQ2, SOCIF_DEBUG,
+       MFIO_MUX_PIN_GROUP(87, SYS_PLL_LOCK, DREQ2, SOCIF_DEBUG,
                           PADS_FUNCTION_SELECT2, 22, 0x3),
-       MFIO_MUX_PIN_GROUP(88, RPU_L_PLL_LOCK, DREQ3, SOCIF_DEBUG,
+       MFIO_MUX_PIN_GROUP(88, WIFI_PLL_LOCK, DREQ3, SOCIF_DEBUG,
                           PADS_FUNCTION_SELECT2, 24, 0x3),
-       MFIO_MUX_PIN_GROUP(89, AUDIO_PLL_LOCK, DREQ4, DREQ5,
+       MFIO_MUX_PIN_GROUP(89, BT_PLL_LOCK, DREQ4, DREQ5,
                           PADS_FUNCTION_SELECT2, 26, 0x3),
        PIN_GROUP(TCK, "tck"),
        PIN_GROUP(TRSTN, "trstn"),
index 23b6b8c29a99eb9a65b7c2bd11e02da7356afc97..73d8d47ea465a93902fb5702fbf84d6f7afaca5e 100644 (file)
@@ -1576,6 +1576,9 @@ static inline void pcs_irq_set(struct pcs_soc_data *pcs_soc,
                else
                        mask &= ~soc_mask;
                pcs->write(mask, pcswi->reg);
+
+               /* flush posted write */
+               mask = pcs->read(pcswi->reg);
                raw_spin_unlock(&pcs->lock);
        }
 
index 55083d278bb1eb36e38772fc36206f41a1460138..51fbf85301be61277c1410a309d5515655a20288 100644 (file)
@@ -485,12 +485,12 @@ static const struct sunxi_desc_pin sun8i_a23_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* RTS */
                  SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 8)),  /* PG_EINT8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* CTS */
                  SUNXI_FUNCTION_IRQ_BANK(0x4, 2, 9)),  /* PG_EINT9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 8b381d69df8632c806f45bde5a5d1e6645b35d40..584cdedea7a42eb213d23397fc68ee909447b710 100644 (file)
@@ -407,12 +407,12 @@ static const struct sunxi_desc_pin sun8i_a33_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* RTS */
                  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 8)),  /* PG_EINT8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* CTS */
                  SUNXI_FUNCTION_IRQ_BANK(0x4, 1, 9)),  /* PG_EINT9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 589872cc8adbbd93bfd94a4b32c58f461b12b890..a19c29c79b0adc1756888bcd0751111aaee522be 100644 (file)
@@ -73,6 +73,12 @@ static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
        case UNIPHIER_PIN_PULL_DOWN:
                pull_dir = "DOWN";
                break;
+       case UNIPHIER_PIN_PULL_UP_FIXED:
+               pull_dir = "UP(FIXED)";
+               break;
+       case UNIPHIER_PIN_PULL_DOWN_FIXED:
+               pull_dir = "DOWN(FIXED)";
+               break;
        case UNIPHIER_PIN_PULL_NONE:
                pull_dir = "NONE";
                break;
index 74979362fd3d42636d912c10c5220ebd0458278f..5b9c8e9ace32de4363fd1e91bbcf015d02031e3b 100644 (file)
@@ -147,13 +147,19 @@ static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
                goto exit;
        }
 
+       if (u_cmd.outsize != s_cmd->outsize ||
+           u_cmd.insize != s_cmd->insize) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
        s_cmd->command += ec->cmd_offset;
        ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
        /* Only copy data to userland if data was received. */
        if (ret < 0)
                goto exit;
 
-       if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + u_cmd.insize))
+       if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))
                ret = -EFAULT;
 exit:
        kfree(s_cmd);
index 990308ca384fdcba7c9c37f49ea94768203ff7ad..92430f781eb710d9e35b6e9a7bad0c6af8d03c9e 100644 (file)
@@ -380,3 +380,20 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
        return ret;
 }
 EXPORT_SYMBOL(cros_ec_cmd_xfer);
+
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+                           struct cros_ec_command *msg)
+{
+       int ret;
+
+       ret = cros_ec_cmd_xfer(ec_dev, msg);
+       if (ret < 0) {
+               dev_err(ec_dev->dev, "Command xfer error (err:%d)\n", ret);
+       } else if (msg->result != EC_RES_SUCCESS) {
+               dev_dbg(ec_dev->dev, "Command result (err: %d)\n", msg->result);
+               return -EPROTO;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
index fb4dd7b3ee711f9ba9b42b4384331c1df9e32fc0..af2046c87806561b351a21201a63753c601c192d 100644 (file)
@@ -723,6 +723,11 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device)
        if (err)
                return err;
 
+       err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless,
+                                  sizeof(wireless), 0);
+       if (err)
+               return err;
+
        if (wireless & 0x1) {
                wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
                                           RFKILL_TYPE_WLAN,
@@ -910,7 +915,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
        gps_rfkill = NULL;
        rfkill2_count = 0;
 
-       if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device))
+       if (hp_wmi_rfkill_setup(device))
                hp_wmi_rfkill2_setup(device);
 
        err = device_create_file(&device->dev, &dev_attr_display);
index 943c1cb9566c803b168aac842aa00187a4627720..d28e3ab9479c64e41fe014714c08721fc503faf3 100644 (file)
@@ -342,7 +342,9 @@ static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
 /* Device IDs of parts that have 32KB MCH space */
 static const unsigned int mch_quirk_devices[] = {
        0x0154, /* Ivy Bridge */
+       0x0a04, /* Haswell-ULT */
        0x0c00, /* Haswell */
+       0x1604, /* Broadwell */
 };
 
 static struct pci_dev *get_intel_host(void)
index 1fea2c7ef97feda56cfc71f9b1ab82e7d3d35351..6fc31bdc639bc54ac0fbd9008740d19912391330 100644 (file)
@@ -1068,6 +1068,12 @@ static int bq24257_probe(struct i2c_client *client,
                return ret;
        }
 
+       ret = bq24257_power_supply_init(bq);
+       if (ret < 0) {
+               dev_err(dev, "Failed to register power supply\n");
+               return ret;
+       }
+
        ret = devm_request_threaded_irq(dev, client->irq, NULL,
                                        bq24257_irq_handler_thread,
                                        IRQF_TRIGGER_FALLING |
@@ -1078,12 +1084,6 @@ static int bq24257_probe(struct i2c_client *client,
                return ret;
        }
 
-       ret = bq24257_power_supply_init(bq);
-       if (ret < 0) {
-               dev_err(dev, "Failed to register power supply\n");
-               return ret;
-       }
-
        ret = sysfs_create_group(&bq->charger->dev.kobj, &bq24257_attr_group);
        if (ret < 0) {
                dev_err(dev, "Can't create sysfs entries\n");
index 9c65f134d4474d843ffa907051191e2d8c484a24..da7a75f824891200f9db4c9dd4d274c5125d3dd8 100644 (file)
@@ -457,13 +457,16 @@ static inline void max17042_write_model_data(struct max17042_chip *chip,
 }
 
 static inline void max17042_read_model_data(struct max17042_chip *chip,
-                                       u8 addr, u32 *data, int size)
+                                       u8 addr, u16 *data, int size)
 {
        struct regmap *map = chip->regmap;
        int i;
+       u32 tmp;
 
-       for (i = 0; i < size; i++)
-               regmap_read(map, addr + i, &data[i]);
+       for (i = 0; i < size; i++) {
+               regmap_read(map, addr + i, &tmp);
+               data[i] = (u16)tmp;
+       }
 }
 
 static inline int max17042_model_data_compare(struct max17042_chip *chip,
@@ -486,7 +489,7 @@ static int max17042_init_model(struct max17042_chip *chip)
 {
        int ret;
        int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
-       u32 *temp_data;
+       u16 *temp_data;
 
        temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
        if (!temp_data)
@@ -501,7 +504,7 @@ static int max17042_init_model(struct max17042_chip *chip)
        ret = max17042_model_data_compare(
                chip,
                chip->pdata->config_data->cell_char_tbl,
-               (u16 *)temp_data,
+               temp_data,
                table_size);
 
        max10742_lock_model(chip);
@@ -514,7 +517,7 @@ static int max17042_verify_model_lock(struct max17042_chip *chip)
 {
        int i;
        int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl);
-       u32 *temp_data;
+       u16 *temp_data;
        int ret = 0;
 
        temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL);
index 456987c88baab9f4b8a0d2b7224b10d659b8bddc..b13cd074c52afc90c086bc16cc011b7adb0ac91f 100644 (file)
@@ -565,11 +565,12 @@ static int power_supply_read_temp(struct thermal_zone_device *tzd,
 
        WARN_ON(tzd == NULL);
        psy = tzd->devdata;
-       ret = psy->desc->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+       ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+       if (ret)
+               return ret;
 
        /* Convert tenths of degree Celsius to milli degree Celsius. */
-       if (!ret)
-               *temp = val.intval * 100;
+       *temp = val.intval * 100;
 
        return ret;
 }
@@ -612,10 +613,12 @@ static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
        int ret;
 
        psy = tcd->devdata;
-       ret = psy->desc->get_property(psy,
-               POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
-       if (!ret)
-               *state = val.intval;
+       ret = power_supply_get_property(psy,
+                       POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
+       if (ret)
+               return ret;
+
+       *state = val.intval;
 
        return ret;
 }
@@ -628,10 +631,12 @@ static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd,
        int ret;
 
        psy = tcd->devdata;
-       ret = psy->desc->get_property(psy,
-               POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
-       if (!ret)
-               *state = val.intval;
+       ret = power_supply_get_property(psy,
+                       POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
+       if (ret)
+               return ret;
+
+       *state = val.intval;
 
        return ret;
 }
index 9ab7f562a83ba6538054e1e39a8b758489a4f8d7..f69387e12c1e545a3cedcb126247050401c8996a 100644 (file)
@@ -53,13 +53,16 @@ static int hisi_reboot_probe(struct platform_device *pdev)
 
        if (of_property_read_u32(np, "reboot-offset", &reboot_offset) < 0) {
                pr_err("failed to find reboot-offset property\n");
+               iounmap(base);
                return -EINVAL;
        }
 
        err = register_restart_handler(&hisi_restart_nb);
-       if (err)
+       if (err) {
                dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n",
                        err);
+               iounmap(base);
+       }
 
        return err;
 }
index d9f56730c735819010e9efff4f8499814c7fbe58..040a40b4b173b214fcc89d1760434ed2a2f3f853 100644 (file)
@@ -205,6 +205,7 @@ static int tps65217_charger_probe(struct platform_device *pdev)
        if (!charger)
                return -ENOMEM;
 
+       platform_set_drvdata(pdev, charger);
        charger->tps = tps;
        charger->dev = &pdev->dev;
 
index 38a8bbe7481008232e7336777850d683afb765be..83797d89c30fe88665c5d7214c391a0a571cfe88 100644 (file)
@@ -195,7 +195,7 @@ static void parport_detach(struct parport *port)
        struct pps_client_pp *device;
 
        /* FIXME: oooh, this is ugly! */
-       if (strcmp(pardev->name, KBUILD_MODNAME))
+       if (!pardev || strcmp(pardev->name, KBUILD_MODNAME))
                /* not our port */
                return;
 
index d24ca5f281b4bbd98e5ce86e8f454c270d86fe10..7831bc6b51dddb66960f8ef97fde2da1ce33572a 100644 (file)
@@ -889,7 +889,7 @@ EXPORT_SYMBOL_GPL(devm_pwm_put);
   */
 bool pwm_can_sleep(struct pwm_device *pwm)
 {
-       return pwm->chip->can_sleep;
+       return true;
 }
 EXPORT_SYMBOL_GPL(pwm_can_sleep);
 
index f9dfc8b6407a7b2d72ec5f3cf6b9a1c4c989153b..7225ac6b3df5be2faa7382662bbb708286813b8a 100644 (file)
@@ -80,7 +80,6 @@ struct fsl_pwm_chip {
 
        struct mutex lock;
 
-       unsigned int use_count;
        unsigned int cnt_select;
        unsigned int clk_ps;
 
@@ -300,9 +299,6 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
 {
        int ret;
 
-       if (fpc->use_count++ != 0)
-               return 0;
-
        /* select counter clock source */
        regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
                           FTM_SC_CLK(fpc->cnt_select));
@@ -334,25 +330,6 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
        return ret;
 }
 
-static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc)
-{
-       /*
-        * already disabled, do nothing
-        */
-       if (fpc->use_count == 0)
-               return;
-
-       /* there are still users, so can't disable yet */
-       if (--fpc->use_count > 0)
-               return;
-
-       /* no users left, disable PWM counter clock */
-       regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0);
-
-       clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
-       clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
-}
-
 static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
@@ -362,7 +339,8 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
                           BIT(pwm->hwpwm));
 
-       fsl_counter_clock_disable(fpc);
+       clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
+       clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
 
        regmap_read(fpc->regmap, FTM_OUTMASK, &val);
        if ((val & 0xFF) == 0xFF)
@@ -492,17 +470,24 @@ static int fsl_pwm_remove(struct platform_device *pdev)
 static int fsl_pwm_suspend(struct device *dev)
 {
        struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
-       u32 val;
+       int i;
 
        regcache_cache_only(fpc->regmap, true);
        regcache_mark_dirty(fpc->regmap);
 
-       /* read from cache */
-       regmap_read(fpc->regmap, FTM_OUTMASK, &val);
-       if ((val & 0xFF) != 0xFF) {
+       for (i = 0; i < fpc->chip.npwm; i++) {
+               struct pwm_device *pwm = &fpc->chip.pwms[i];
+
+               if (!test_bit(PWMF_REQUESTED, &pwm->flags))
+                       continue;
+
+               clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+
+               if (!pwm_is_enabled(pwm))
+                       continue;
+
                clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
                clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
-               clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
        }
 
        return 0;
@@ -511,12 +496,19 @@ static int fsl_pwm_suspend(struct device *dev)
 static int fsl_pwm_resume(struct device *dev)
 {
        struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
-       u32 val;
+       int i;
+
+       for (i = 0; i < fpc->chip.npwm; i++) {
+               struct pwm_device *pwm = &fpc->chip.pwms[i];
+
+               if (!test_bit(PWMF_REQUESTED, &pwm->flags))
+                       continue;
 
-       /* read from cache */
-       regmap_read(fpc->regmap, FTM_OUTMASK, &val);
-       if ((val & 0xFF) != 0xFF) {
                clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+
+               if (!pwm_is_enabled(pwm))
+                       continue;
+
                clk_prepare_enable(fpc->clk[fpc->cnt_select]);
                clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
        }
index 9fde60ce8e7bf2d5932caa74564a93a6b638ceb6..6e203a65effb35d82f34c4f5d148d61bc276b798 100644 (file)
@@ -24,9 +24,7 @@ struct lpc32xx_pwm_chip {
        void __iomem *base;
 };
 
-#define PWM_ENABLE     (1 << 31)
-#define PWM_RELOADV(x) (((x) & 0xFF) << 8)
-#define PWM_DUTY(x)    ((x) & 0xFF)
+#define PWM_ENABLE     BIT(31)
 
 #define to_lpc32xx_pwm_chip(_chip) \
        container_of(_chip, struct lpc32xx_pwm_chip, chip)
@@ -38,40 +36,27 @@ static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        unsigned long long c;
        int period_cycles, duty_cycles;
        u32 val;
-
-       c = clk_get_rate(lpc32xx->clk) / 256;
-       c = c * period_ns;
-       do_div(c, NSEC_PER_SEC);
-
-       /* Handle high and low extremes */
-       if (c == 0)
-               c = 1;
-       if (c > 255)
-               c = 0; /* 0 set division by 256 */
-       period_cycles = c;
-
-       /* The duty-cycle value is as follows:
-        *
-        *  DUTY-CYCLE     HIGH LEVEL
-        *      1            99.9%
-        *      25           90.0%
-        *      128          50.0%
-        *      220          10.0%
-        *      255           0.1%
-        *      0             0.0%
-        *
-        * In other words, the register value is duty-cycle % 256 with
-        * duty-cycle in the range 1-256.
-        */
-       c = 256 * duty_ns;
-       do_div(c, period_ns);
-       if (c > 255)
-               c = 255;
-       duty_cycles = 256 - c;
+       c = clk_get_rate(lpc32xx->clk);
+
+       /* The highest acceptable divisor is 256, which is represented by 0 */
+       period_cycles = div64_u64(c * period_ns,
+                              (unsigned long long)NSEC_PER_SEC * 256);
+       if (!period_cycles)
+               period_cycles = 1;
+       if (period_cycles > 255)
+               period_cycles = 0;
+
+       /* Compute 256 x #duty/period value and care for corner cases */
+       duty_cycles = div64_u64((unsigned long long)(period_ns - duty_ns) * 256,
+                               period_ns);
+       if (!duty_cycles)
+               duty_cycles = 1;
+       if (duty_cycles > 255)
+               duty_cycles = 255;
 
        val = readl(lpc32xx->base + (pwm->hwpwm << 2));
        val &= ~0xFFFF;
-       val |= PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles);
+       val |= (period_cycles << 8) | duty_cycles;
        writel(val, lpc32xx->base + (pwm->hwpwm << 2));
 
        return 0;
@@ -134,7 +119,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
 
        lpc32xx->chip.dev = &pdev->dev;
        lpc32xx->chip.ops = &lpc32xx_pwm_ops;
-       lpc32xx->chip.npwm = 2;
+       lpc32xx->chip.npwm = 1;
        lpc32xx->chip.base = -1;
 
        ret = pwmchip_add(&lpc32xx->chip);
index 63cd5e68c86494724eae44502bed2d7f590cbf78..3a6d0290c54c0fbd0f1c82ffcd5329c2facc56ae 100644 (file)
@@ -296,7 +296,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
                if (!sreg->sel && !strcmp(sreg->name, "vddpu"))
                        sreg->sel = 22;
 
-               if (!sreg->sel) {
+               if (!sreg->bypass && !sreg->sel) {
                        dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n");
                        return -EINVAL;
                }
index 6fa0c7d13290981d254b38538d6bb62103df1e27..4bda998afdeff184e094aaa6d4e53c1dedf04c86 100644 (file)
@@ -166,29 +166,30 @@ static const struct regulator_desc pm8x41_hfsmps = {
 static const struct regulator_desc pm8841_ftsmps = {
        .linear_ranges = (struct regulator_linear_range[]) {
                REGULATOR_LINEAR_RANGE(350000,  0, 184, 5000),
-               REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
+               REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000),
        },
        .n_linear_ranges = 2,
-       .n_voltages = 340,
+       .n_voltages = 262,
        .ops = &rpm_smps_ldo_ops,
 };
 
 static const struct regulator_desc pm8941_boost = {
        .linear_ranges = (struct regulator_linear_range[]) {
-               REGULATOR_LINEAR_RANGE(4000000, 0, 15, 100000),
+               REGULATOR_LINEAR_RANGE(4000000, 0, 30, 50000),
        },
        .n_linear_ranges = 1,
-       .n_voltages = 16,
+       .n_voltages = 31,
        .ops = &rpm_smps_ldo_ops,
 };
 
 static const struct regulator_desc pm8941_pldo = {
        .linear_ranges = (struct regulator_linear_range[]) {
-               REGULATOR_LINEAR_RANGE( 750000,  0,  30, 25000),
-               REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
+               REGULATOR_LINEAR_RANGE( 750000,  0,  63, 12500),
+               REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000),
+               REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
        },
-       .n_linear_ranges = 2,
-       .n_voltages = 100,
+       .n_linear_ranges = 3,
+       .n_voltages = 164,
        .ops = &rpm_smps_ldo_ops,
 };
 
index 88a5dc88badc7e0c72b1deb770dd1128a8cfa661..fee6457e3111f9fb4e0ede3c670aba43902fa6d9 100644 (file)
@@ -1050,6 +1050,8 @@ static struct regulator_ops spmi_vs_ops = {
        .set_pull_down          = spmi_regulator_common_set_pull_down,
        .set_soft_start         = spmi_regulator_common_set_soft_start,
        .set_over_current_protection = spmi_regulator_vs_ocp,
+       .set_mode               = spmi_regulator_common_set_mode,
+       .get_mode               = spmi_regulator_common_get_mode,
 };
 
 static struct regulator_ops spmi_boost_ops = {
@@ -1440,6 +1442,7 @@ static const struct spmi_regulator_data pm8941_regulators[] = {
        { "s1", 0x1400, "vdd_s1", },
        { "s2", 0x1700, "vdd_s2", },
        { "s3", 0x1a00, "vdd_s3", },
+       { "s4", 0xa000, },
        { "l1", 0x4000, "vdd_l1_l3", },
        { "l2", 0x4100, "vdd_l2_lvs_1_2_3", },
        { "l3", 0x4200, "vdd_l1_l3", },
@@ -1467,8 +1470,8 @@ static const struct spmi_regulator_data pm8941_regulators[] = {
        { "lvs1", 0x8000, "vdd_l2_lvs_1_2_3", },
        { "lvs2", 0x8100, "vdd_l2_lvs_1_2_3", },
        { "lvs3", 0x8200, "vdd_l2_lvs_1_2_3", },
-       { "mvs1", 0x8300, "vin_5vs", },
-       { "mvs2", 0x8400, "vin_5vs", },
+       { "5vs1", 0x8300, "vin_5vs", "ocp-5vs1", },
+       { "5vs2", 0x8400, "vin_5vs", "ocp-5vs2", },
        { }
 };
 
index fb991ec764235d55443a9f99414efc3511cad7a2..696116ebdf50a5b853ba847b9ef55604ed3423ae 100644 (file)
@@ -1111,6 +1111,12 @@ static int tps65910_probe(struct platform_device *pdev)
                pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
                pmic->ext_sleep_control = tps65910_ext_sleep_control;
                info = tps65910_regs;
+               /* Work around silicon erratum SWCZ010: output programmed
+                * voltage level can go higher than expected or crash
+                * Workaround: use no synchronization of DCDC clocks
+                */
+               tps65910_reg_clear_bits(pmic->mfd, TPS65910_DCDCCTRL,
+                                       DCDCCTRL_DCDCCKSYNC_MASK);
                break;
        case TPS65911:
                pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
index 9e03d158f4119133f09b0979d8b5b70e1ae63c06..4f7ce0097191d5ae0c4b351ddb25c179b19231ee 100644 (file)
@@ -1239,11 +1239,6 @@ int rproc_add(struct rproc *rproc)
        if (ret < 0)
                return ret;
 
-       /* expose to rproc_get_by_phandle users */
-       mutex_lock(&rproc_list_mutex);
-       list_add(&rproc->node, &rproc_list);
-       mutex_unlock(&rproc_list_mutex);
-
        dev_info(dev, "%s is available\n", rproc->name);
 
        dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
@@ -1251,8 +1246,16 @@ int rproc_add(struct rproc *rproc)
 
        /* create debugfs entries */
        rproc_create_debug_dir(rproc);
+       ret = rproc_add_virtio_devices(rproc);
+       if (ret < 0)
+               return ret;
 
-       return rproc_add_virtio_devices(rproc);
+       /* expose to rproc_get_by_phandle users */
+       mutex_lock(&rproc_list_mutex);
+       list_add(&rproc->node, &rproc_list);
+       mutex_unlock(&rproc_list_mutex);
+
+       return 0;
 }
 EXPORT_SYMBOL(rproc_add);
 
index ffb860d18701753bfaea2308fea9deb2a6ed6a9d..f92528822f06e3bdd50465770f4d335f7ddc4e46 100644 (file)
@@ -149,12 +149,14 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
        if (!is_power_of_2(freq))
                return -EINVAL;
 
+       s3c_rtc_enable_clk(info);
        spin_lock_irq(&info->pie_lock);
 
        if (info->data->set_freq)
                info->data->set_freq(info, freq);
 
        spin_unlock_irq(&info->pie_lock);
+       s3c_rtc_disable_clk(info);
 
        return 0;
 }
index 4abfbdb285ec3181d19cf80c7fe4588ee8081759..84c13dffa3a8f73f6d7cf668b61445ecdaa4d90a 100644 (file)
@@ -1584,9 +1584,18 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        unsigned long long now;
        int expires;
 
+       cqr = (struct dasd_ccw_req *) intparm;
        if (IS_ERR(irb)) {
                switch (PTR_ERR(irb)) {
                case -EIO:
+                       if (cqr && cqr->status == DASD_CQR_CLEAR_PENDING) {
+                               device = (struct dasd_device *) cqr->startdev;
+                               cqr->status = DASD_CQR_CLEARED;
+                               dasd_device_clear_timer(device);
+                               wake_up(&dasd_flush_wq);
+                               dasd_schedule_device_bh(device);
+                               return;
+                       }
                        break;
                case -ETIMEDOUT:
                        DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s: "
@@ -1602,7 +1611,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        }
 
        now = get_tod_clock();
-       cqr = (struct dasd_ccw_req *) intparm;
        /* check for conditions that should be handled immediately */
        if (!cqr ||
            !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
index 7c511add5aa7d884d8082398198b1aa92a61dc84..bae98521c808c5300a6683c0fe5f1563bfe7a59d 100644 (file)
@@ -124,7 +124,12 @@ con3270_create_status(struct con3270 *cp)
 static void
 con3270_update_string(struct con3270 *cp, struct string *s, int nr)
 {
-       if (s->len >= cp->view.cols - 5)
+       if (s->len < 4) {
+               /* This indicates a bug, but printing a warning would
+                * cause a deadlock. */
+               return;
+       }
+       if (s->string[s->len - 4] != TO_RA)
                return;
        raw3270_buffer_address(cp->view.dev, s->string + s->len - 3,
                               cp->view.cols * (nr + 1));
@@ -461,11 +466,11 @@ con3270_cline_end(struct con3270 *cp)
                cp->cline->len + 4 : cp->view.cols;
        s = con3270_alloc_string(cp, size);
        memcpy(s->string, cp->cline->string, cp->cline->len);
-       if (s->len < cp->view.cols - 5) {
+       if (cp->cline->len < cp->view.cols - 5) {
                s->string[s->len - 4] = TO_RA;
                s->string[s->len - 1] = 0;
        } else {
-               while (--size > cp->cline->len)
+               while (--size >= cp->cline->len)
                        s->string[size] = cp->view.ascebc[' '];
        }
        /* Replace cline with allocated line s and reset cline. */
index 648cb86afd427776abc0d109f0982284d094699a..ea607a4a1bddaf3e41165aebed1fd787b87d754e 100644 (file)
@@ -56,6 +56,7 @@ static int sclp_ctl_ioctl_sccb(void __user *user_area)
 {
        struct sclp_ctl_sccb ctl_sccb;
        struct sccb_header *sccb;
+       unsigned long copied;
        int rc;
 
        if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb)))
@@ -65,14 +66,15 @@ static int sclp_ctl_ioctl_sccb(void __user *user_area)
        sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!sccb)
                return -ENOMEM;
-       if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sizeof(*sccb))) {
+       copied = PAGE_SIZE -
+               copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), PAGE_SIZE);
+       if (offsetof(struct sccb_header, length) +
+           sizeof(sccb->length) > copied || sccb->length > copied) {
                rc = -EFAULT;
                goto out_free;
        }
-       if (sccb->length > PAGE_SIZE || sccb->length < 8)
-               return -EINVAL;
-       if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sccb->length)) {
-               rc = -EFAULT;
+       if (sccb->length < 8) {
+               rc = -EINVAL;
                goto out_free;
        }
        rc = sclp_sync_request(ctl_sccb.cmdw, sccb);
index c692dfebd0bab1c808f460349dff194b028f5c5c..50597f9522fe375ed764aab8842a400e56ef808d 100644 (file)
@@ -139,11 +139,11 @@ static ssize_t chp_measurement_chars_read(struct file *filp,
 
        device = container_of(kobj, struct device, kobj);
        chp = to_channelpath(device);
-       if (!chp->cmg_chars)
+       if (chp->cmg == -1)
                return 0;
 
-       return memory_read_from_buffer(buf, count, &off,
-                               chp->cmg_chars, sizeof(struct cmg_chars));
+       return memory_read_from_buffer(buf, count, &off, &chp->cmg_chars,
+                                      sizeof(chp->cmg_chars));
 }
 
 static struct bin_attribute chp_measurement_chars_attr = {
@@ -416,7 +416,8 @@ static void chp_release(struct device *dev)
  * chp_update_desc - update channel-path description
  * @chp - channel-path
  *
- * Update the channel-path description of the specified channel-path.
+ * Update the channel-path description of the specified channel-path
+ * including channel measurement related information.
  * Return zero on success, non-zero otherwise.
  */
 int chp_update_desc(struct channel_path *chp)
@@ -428,8 +429,10 @@ int chp_update_desc(struct channel_path *chp)
                return rc;
 
        rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1);
+       if (rc)
+               return rc;
 
-       return rc;
+       return chsc_get_channel_measurement_chars(chp);
 }
 
 /**
@@ -466,14 +469,6 @@ int chp_new(struct chp_id chpid)
                ret = -ENODEV;
                goto out_free;
        }
-       /* Get channel-measurement characteristics. */
-       if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) {
-               ret = chsc_get_channel_measurement_chars(chp);
-               if (ret)
-                       goto out_free;
-       } else {
-               chp->cmg = -1;
-       }
        dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id);
 
        /* make it known to the system */
index 4efd5b867cc390780a18c2f983a2215ed05dcd72..af0232290dc4c7c183a65e3fe13d6683bb48cf1e 100644 (file)
@@ -48,7 +48,7 @@ struct channel_path {
        /* Channel-measurement related stuff: */
        int cmg;
        int shared;
-       void *cmg_chars;
+       struct cmg_chars cmg_chars;
 };
 
 /* Return channel_path struct for given chpid. */
index a831d18596a5ef592f88ec5af031f639606c8c0b..1e16331891a9426fdca1d99f5c4ae8a043f34742 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 
 #include <asm/cio.h>
@@ -94,12 +95,13 @@ struct chsc_ssd_area {
 int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
 {
        struct chsc_ssd_area *ssd_area;
+       unsigned long flags;
        int ccode;
        int ret;
        int i;
        int mask;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        ssd_area = chsc_page;
        ssd_area->request.length = 0x0010;
@@ -143,7 +145,7 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
                        ssd->fla[i] = ssd_area->fla[i];
        }
 out:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -224,8 +226,9 @@ out_unreg:
 
 void chsc_chp_offline(struct chp_id chpid)
 {
-       char dbf_txt[15];
+       struct channel_path *chp = chpid_to_chp(chpid);
        struct chp_link link;
+       char dbf_txt[15];
 
        sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
        CIO_TRACE_EVENT(2, dbf_txt);
@@ -236,6 +239,11 @@ void chsc_chp_offline(struct chp_id chpid)
        link.chpid = chpid;
        /* Wait until previous actions have settled. */
        css_wait_for_slow_path();
+
+       mutex_lock(&chp->lock);
+       chp_update_desc(chp);
+       mutex_unlock(&chp->lock);
+
        for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);
 }
 
@@ -690,8 +698,9 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
 
 void chsc_chp_online(struct chp_id chpid)
 {
-       char dbf_txt[15];
+       struct channel_path *chp = chpid_to_chp(chpid);
        struct chp_link link;
+       char dbf_txt[15];
 
        sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
        CIO_TRACE_EVENT(2, dbf_txt);
@@ -701,6 +710,11 @@ void chsc_chp_online(struct chp_id chpid)
                link.chpid = chpid;
                /* Wait until previous actions have settled. */
                css_wait_for_slow_path();
+
+               mutex_lock(&chp->lock);
+               chp_update_desc(chp);
+               mutex_unlock(&chp->lock);
+
                for_each_subchannel_staged(__s390_process_res_acc, NULL,
                                           &link);
                css_schedule_reprobe();
@@ -819,9 +833,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
                u32 fmt : 4;
                u32 : 16;
        } __attribute__ ((packed)) *secm_area;
+       unsigned long flags;
        int ret, ccode;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        secm_area = chsc_page;
        secm_area->request.length = 0x0050;
@@ -851,7 +866,7 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
                CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
                              secm_area->response.code);
 out:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -967,22 +982,20 @@ static void
 chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
                          struct cmg_chars *chars)
 {
-       struct cmg_chars *cmg_chars;
        int i, mask;
 
-       cmg_chars = chp->cmg_chars;
        for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
                mask = 0x80 >> (i + 3);
                if (cmcv & mask)
-                       cmg_chars->values[i] = chars->values[i];
+                       chp->cmg_chars.values[i] = chars->values[i];
                else
-                       cmg_chars->values[i] = 0;
+                       chp->cmg_chars.values[i] = 0;
        }
 }
 
 int chsc_get_channel_measurement_chars(struct channel_path *chp)
 {
-       struct cmg_chars *cmg_chars;
+       unsigned long flags;
        int ccode, ret;
 
        struct {
@@ -1006,12 +1019,13 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                u32 data[NR_MEASUREMENT_CHARS];
        } __attribute__ ((packed)) *scmc_area;
 
-       chp->cmg_chars = NULL;
-       cmg_chars = kmalloc(sizeof(*cmg_chars), GFP_KERNEL);
-       if (!cmg_chars)
-               return -ENOMEM;
+       chp->shared = -1;
+       chp->cmg = -1;
+
+       if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm)
+               return 0;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        scmc_area = chsc_page;
        scmc_area->request.length = 0x0010;
@@ -1031,25 +1045,19 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                              scmc_area->response.code);
                goto out;
        }
-       if (scmc_area->not_valid) {
-               chp->cmg = -1;
-               chp->shared = -1;
+       if (scmc_area->not_valid)
                goto out;
-       }
+
        chp->cmg = scmc_area->cmg;
        chp->shared = scmc_area->shared;
        if (chp->cmg != 2 && chp->cmg != 3) {
                /* No cmg-dependent data. */
                goto out;
        }
-       chp->cmg_chars = cmg_chars;
        chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
                                  (struct cmg_chars *) &scmc_area->data);
 out:
-       spin_unlock_irq(&chsc_page_lock);
-       if (!chp->cmg_chars)
-               kfree(cmg_chars);
-
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return ret;
 }
 
@@ -1130,6 +1138,7 @@ struct css_chsc_char css_chsc_characteristics;
 int __init
 chsc_determine_css_characteristics(void)
 {
+       unsigned long flags;
        int result;
        struct {
                struct chsc_header request;
@@ -1142,7 +1151,7 @@ chsc_determine_css_characteristics(void)
                u32 chsc_char[508];
        } __attribute__ ((packed)) *scsc_area;
 
-       spin_lock_irq(&chsc_page_lock);
+       spin_lock_irqsave(&chsc_page_lock, flags);
        memset(chsc_page, 0, PAGE_SIZE);
        scsc_area = chsc_page;
        scsc_area->request.length = 0x0010;
@@ -1164,7 +1173,7 @@ chsc_determine_css_characteristics(void)
                CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
                              scsc_area->response.code);
 exit:
-       spin_unlock_irq(&chsc_page_lock);
+       spin_unlock_irqrestore(&chsc_page_lock, flags);
        return result;
 }
 
index b2afad5a5682b128fd665442fb987638aa7873c0..2a34eb5f6161031d6a902f386c7ec32fc6febdcd 100644 (file)
@@ -753,6 +753,17 @@ static void reset_cmb(struct ccw_device *cdev)
        cmf_generic_reset(cdev);
 }
 
+static int cmf_enabled(struct ccw_device *cdev)
+{
+       int enabled;
+
+       spin_lock_irq(cdev->ccwlock);
+       enabled = !!cdev->private->cmb;
+       spin_unlock_irq(cdev->ccwlock);
+
+       return enabled;
+}
+
 static struct attribute_group cmf_attr_group;
 
 static struct cmb_operations cmbops_basic = {
@@ -1153,13 +1164,8 @@ static ssize_t cmb_enable_show(struct device *dev,
                               char *buf)
 {
        struct ccw_device *cdev = to_ccwdev(dev);
-       int enabled;
 
-       spin_lock_irq(cdev->ccwlock);
-       enabled = !!cdev->private->cmb;
-       spin_unlock_irq(cdev->ccwlock);
-
-       return sprintf(buf, "%d\n", enabled);
+       return sprintf(buf, "%d\n", cmf_enabled(cdev));
 }
 
 static ssize_t cmb_enable_store(struct device *dev,
@@ -1199,15 +1205,20 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable)
  *  @cdev:     The ccw device to be enabled
  *
  *  Returns %0 for success or a negative error value.
- *
+ *  Note: If this is called on a device for which channel measurement is already
+ *       enabled a reset of the measurement data is triggered.
  *  Context:
  *    non-atomic
  */
 int enable_cmf(struct ccw_device *cdev)
 {
-       int ret;
+       int ret = 0;
 
        device_lock(&cdev->dev);
+       if (cmf_enabled(cdev)) {
+               cmbops->reset(cdev);
+               goto out_unlock;
+       }
        get_device(&cdev->dev);
        ret = cmbops->alloc(cdev);
        if (ret)
@@ -1226,7 +1237,7 @@ int enable_cmf(struct ccw_device *cdev)
 out:
        if (ret)
                put_device(&cdev->dev);
-
+out_unlock:
        device_unlock(&cdev->dev);
        return ret;
 }
index 8f1b091e173277a718c232bdbf707fb03db21945..df036b872b050b835d0fea6f620726dc8876225b 100644 (file)
@@ -1051,6 +1051,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
                qeth_l2_set_offline(cgdev);
 
        if (card->dev) {
+               netif_napi_del(&card->napi);
                unregister_netdev(card->dev);
                card->dev = NULL;
        }
@@ -1126,6 +1127,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
        qeth_l2_request_initial_mac(card);
        SET_NETDEV_DEV(card->dev, &card->gdev->dev);
        netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
+       netif_carrier_off(card->dev);
        return register_netdev(card->dev);
 }
 
index 543960e96b42b362af6ee7d68bafba057042cc32..cc4d3c3d8cc546dbf6d7004aa81067e1867a83a0 100644 (file)
@@ -3220,6 +3220,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
 
        SET_NETDEV_DEV(card->dev, &card->gdev->dev);
        netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT);
+       netif_carrier_off(card->dev);
        return register_netdev(card->dev);
 }
 
@@ -3246,6 +3247,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
                qeth_l3_set_offline(cgdev);
 
        if (card->dev) {
+               netif_napi_del(&card->napi);
                unregister_netdev(card->dev);
                card->dev = NULL;
        }
index 5d7fbe4e907e37e464c63e8f3278c78edcb838cf..581001989937ce1e0aaab11c26136d5e11b4fa4d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Debug traces for zfcp.
  *
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2016
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -65,7 +65,7 @@ void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
  * @tag: tag indicating which kind of unsolicited status has been received
  * @req: request for which a response was received
  */
-void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
+void zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req)
 {
        struct zfcp_dbf *dbf = req->adapter->dbf;
        struct fsf_qtcb_prefix *q_pref = &req->qtcb->prefix;
@@ -85,6 +85,8 @@ void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
        rec->u.res.req_issued = req->issued;
        rec->u.res.prot_status = q_pref->prot_status;
        rec->u.res.fsf_status = q_head->fsf_status;
+       rec->u.res.port_handle = q_head->port_handle;
+       rec->u.res.lun_handle = q_head->lun_handle;
 
        memcpy(rec->u.res.prot_status_qual, &q_pref->prot_status_qual,
               FSF_PROT_STATUS_QUAL_SIZE);
@@ -97,7 +99,7 @@ void zfcp_dbf_hba_fsf_res(char *tag, struct zfcp_fsf_req *req)
                                  rec->pl_len, "fsf_res", req->req_id);
        }
 
-       debug_event(dbf->hba, 1, rec, sizeof(*rec));
+       debug_event(dbf->hba, level, rec, sizeof(*rec));
        spin_unlock_irqrestore(&dbf->hba_lock, flags);
 }
 
@@ -241,7 +243,8 @@ static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
        if (sdev) {
                rec->lun_status = atomic_read(&sdev_to_zfcp(sdev)->status);
                rec->lun = zfcp_scsi_dev_lun(sdev);
-       }
+       } else
+               rec->lun = ZFCP_DBF_INVALID_LUN;
 }
 
 /**
@@ -320,13 +323,48 @@ void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
        spin_unlock_irqrestore(&dbf->rec_lock, flags);
 }
 
+/**
+ * zfcp_dbf_rec_run_wka - trace wka port event with info like running recovery
+ * @tag: identifier for event
+ * @wka_port: well known address port
+ * @req_id: request ID to correlate with potential HBA trace record
+ */
+void zfcp_dbf_rec_run_wka(char *tag, struct zfcp_fc_wka_port *wka_port,
+                         u64 req_id)
+{
+       struct zfcp_dbf *dbf = wka_port->adapter->dbf;
+       struct zfcp_dbf_rec *rec = &dbf->rec_buf;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dbf->rec_lock, flags);
+       memset(rec, 0, sizeof(*rec));
+
+       rec->id = ZFCP_DBF_REC_RUN;
+       memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+       rec->port_status = wka_port->status;
+       rec->d_id = wka_port->d_id;
+       rec->lun = ZFCP_DBF_INVALID_LUN;
+
+       rec->u.run.fsf_req_id = req_id;
+       rec->u.run.rec_status = ~0;
+       rec->u.run.rec_step = ~0;
+       rec->u.run.rec_action = ~0;
+       rec->u.run.rec_count = ~0;
+
+       debug_event(dbf->rec, 1, rec, sizeof(*rec));
+       spin_unlock_irqrestore(&dbf->rec_lock, flags);
+}
+
 static inline
-void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
-                 u64 req_id, u32 d_id)
+void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf,
+                 char *paytag, struct scatterlist *sg, u8 id, u16 len,
+                 u64 req_id, u32 d_id, u16 cap_len)
 {
        struct zfcp_dbf_san *rec = &dbf->san_buf;
        u16 rec_len;
        unsigned long flags;
+       struct zfcp_dbf_pay *payload = &dbf->pay_buf;
+       u16 pay_sum = 0;
 
        spin_lock_irqsave(&dbf->san_lock, flags);
        memset(rec, 0, sizeof(*rec));
@@ -334,10 +372,41 @@ void zfcp_dbf_san(char *tag, struct zfcp_dbf *dbf, void *data, u8 id, u16 len,
        rec->id = id;
        rec->fsf_req_id = req_id;
        rec->d_id = d_id;
-       rec_len = min(len, (u16)ZFCP_DBF_SAN_MAX_PAYLOAD);
-       memcpy(rec->payload, data, rec_len);
        memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
+       rec->pl_len = len; /* full length even if we cap pay below */
+       if (!sg)
+               goto out;
+       rec_len = min_t(unsigned int, sg->length, ZFCP_DBF_SAN_MAX_PAYLOAD);
+       memcpy(rec->payload, sg_virt(sg), rec_len); /* part of 1st sg entry */
+       if (len <= rec_len)
+               goto out; /* skip pay record if full content in rec->payload */
+
+       /* if (len > rec_len):
+        * dump data up to cap_len ignoring small duplicate in rec->payload
+        */
+       spin_lock(&dbf->pay_lock);
+       memset(payload, 0, sizeof(*payload));
+       memcpy(payload->area, paytag, ZFCP_DBF_TAG_LEN);
+       payload->fsf_req_id = req_id;
+       payload->counter = 0;
+       for (; sg && pay_sum < cap_len; sg = sg_next(sg)) {
+               u16 pay_len, offset = 0;
+
+               while (offset < sg->length && pay_sum < cap_len) {
+                       pay_len = min((u16)ZFCP_DBF_PAY_MAX_REC,
+                                     (u16)(sg->length - offset));
+                       /* cap_len <= pay_sum < cap_len+ZFCP_DBF_PAY_MAX_REC */
+                       memcpy(payload->data, sg_virt(sg) + offset, pay_len);
+                       debug_event(dbf->pay, 1, payload,
+                                   zfcp_dbf_plen(pay_len));
+                       payload->counter++;
+                       offset += pay_len;
+                       pay_sum += pay_len;
+               }
+       }
+       spin_unlock(&dbf->pay_lock);
 
+out:
        debug_event(dbf->san, 1, rec, sizeof(*rec));
        spin_unlock_irqrestore(&dbf->san_lock, flags);
 }
@@ -354,9 +423,62 @@ void zfcp_dbf_san_req(char *tag, struct zfcp_fsf_req *fsf, u32 d_id)
        struct zfcp_fsf_ct_els *ct_els = fsf->data;
        u16 length;
 
-       length = (u16)(ct_els->req->length + FC_CT_HDR_LEN);
-       zfcp_dbf_san(tag, dbf, sg_virt(ct_els->req), ZFCP_DBF_SAN_REQ, length,
-                    fsf->req_id, d_id);
+       length = (u16)zfcp_qdio_real_bytes(ct_els->req);
+       zfcp_dbf_san(tag, dbf, "san_req", ct_els->req, ZFCP_DBF_SAN_REQ,
+                    length, fsf->req_id, d_id, length);
+}
+
+static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
+                                             struct zfcp_fsf_req *fsf,
+                                             u16 len)
+{
+       struct zfcp_fsf_ct_els *ct_els = fsf->data;
+       struct fc_ct_hdr *reqh = sg_virt(ct_els->req);
+       struct fc_ns_gid_ft *reqn = (struct fc_ns_gid_ft *)(reqh + 1);
+       struct scatterlist *resp_entry = ct_els->resp;
+       struct fc_gpn_ft_resp *acc;
+       int max_entries, x, last = 0;
+
+       if (!(memcmp(tag, "fsscth2", 7) == 0
+             && ct_els->d_id == FC_FID_DIR_SERV
+             && reqh->ct_rev == FC_CT_REV
+             && reqh->ct_in_id[0] == 0
+             && reqh->ct_in_id[1] == 0
+             && reqh->ct_in_id[2] == 0
+             && reqh->ct_fs_type == FC_FST_DIR
+             && reqh->ct_fs_subtype == FC_NS_SUBTYPE
+             && reqh->ct_options == 0
+             && reqh->_ct_resvd1 == 0
+             && reqh->ct_cmd == FC_NS_GPN_FT
+             /* reqh->ct_mr_size can vary so do not match but read below */
+             && reqh->_ct_resvd2 == 0
+             && reqh->ct_reason == 0
+             && reqh->ct_explan == 0
+             && reqh->ct_vendor == 0
+             && reqn->fn_resvd == 0
+             && reqn->fn_domain_id_scope == 0
+             && reqn->fn_area_id_scope == 0
+             && reqn->fn_fc4_type == FC_TYPE_FCP))
+               return len; /* not GPN_FT response so do not cap */
+
+       acc = sg_virt(resp_entry);
+       max_entries = (reqh->ct_mr_size * 4 / sizeof(struct fc_gpn_ft_resp))
+               + 1 /* zfcp_fc_scan_ports: bytes correct, entries off-by-one
+                    * to account for header as 1st pseudo "entry" */;
+
+       /* the basic CT_IU preamble is the same size as one entry in the GPN_FT
+        * response, allowing us to skip special handling for it - just skip it
+        */
+       for (x = 1; x < max_entries && !last; x++) {
+               if (x % (ZFCP_FC_GPN_FT_ENT_PAGE + 1))
+                       acc++;
+               else
+                       acc = sg_virt(++resp_entry);
+
+               last = acc->fp_flags & FC_NS_FID_LAST;
+       }
+       len = min(len, (u16)(x * sizeof(struct fc_gpn_ft_resp)));
+       return len; /* cap after last entry */
 }
 
 /**
@@ -370,9 +492,10 @@ void zfcp_dbf_san_res(char *tag, struct zfcp_fsf_req *fsf)
        struct zfcp_fsf_ct_els *ct_els = fsf->data;
        u16 length;
 
-       length = (u16)(ct_els->resp->length + FC_CT_HDR_LEN);
-       zfcp_dbf_san(tag, dbf, sg_virt(ct_els->resp), ZFCP_DBF_SAN_RES, length,
-                    fsf->req_id, 0);
+       length = (u16)zfcp_qdio_real_bytes(ct_els->resp);
+       zfcp_dbf_san(tag, dbf, "san_res", ct_els->resp, ZFCP_DBF_SAN_RES,
+                    length, fsf->req_id, ct_els->d_id,
+                    zfcp_dbf_san_res_cap_len_if_gpn_ft(tag, fsf, length));
 }
 
 /**
@@ -386,11 +509,13 @@ void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
        struct fsf_status_read_buffer *srb =
                (struct fsf_status_read_buffer *) fsf->data;
        u16 length;
+       struct scatterlist sg;
 
        length = (u16)(srb->length -
                        offsetof(struct fsf_status_read_buffer, payload));
-       zfcp_dbf_san(tag, dbf, srb->payload.data, ZFCP_DBF_SAN_ELS, length,
-                    fsf->req_id, ntoh24(srb->d_id));
+       sg_init_one(&sg, srb->payload.data, length);
+       zfcp_dbf_san(tag, dbf, "san_els", &sg, ZFCP_DBF_SAN_ELS, length,
+                    fsf->req_id, ntoh24(srb->d_id), length);
 }
 
 /**
@@ -399,7 +524,8 @@ void zfcp_dbf_san_in_els(char *tag, struct zfcp_fsf_req *fsf)
  * @sc: pointer to struct scsi_cmnd
  * @fsf: pointer to struct zfcp_fsf_req
  */
-void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
+void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc,
+                  struct zfcp_fsf_req *fsf)
 {
        struct zfcp_adapter *adapter =
                (struct zfcp_adapter *) sc->device->host->hostdata[0];
@@ -442,7 +568,7 @@ void zfcp_dbf_scsi(char *tag, struct scsi_cmnd *sc, struct zfcp_fsf_req *fsf)
                }
        }
 
-       debug_event(dbf->scsi, 1, rec, sizeof(*rec));
+       debug_event(dbf->scsi, level, rec, sizeof(*rec));
        spin_unlock_irqrestore(&dbf->scsi_lock, flags);
 }
 
index 0be3d48681aead94466a71ab7b34c6ae7ca098ff..36d07584271d569d27ec2eeb3706235d6459e026 100644 (file)
@@ -2,7 +2,7 @@
  * zfcp device driver
  * debug feature declarations
  *
- * Copyright IBM Corp. 2008, 2010
+ * Copyright IBM Corp. 2008, 2015
  */
 
 #ifndef ZFCP_DBF_H
 
 #define ZFCP_DBF_INVALID_LUN   0xFFFFFFFFFFFFFFFFull
 
+enum zfcp_dbf_pseudo_erp_act_type {
+       ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD = 0xff,
+       ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL = 0xfe,
+};
+
 /**
  * struct zfcp_dbf_rec_trigger - trace record for triggered recovery action
  * @ready: number of ready recovery actions
@@ -110,6 +115,7 @@ struct zfcp_dbf_san {
        u32 d_id;
 #define ZFCP_DBF_SAN_MAX_PAYLOAD (FC_CT_HDR_LEN + 32)
        char payload[ZFCP_DBF_SAN_MAX_PAYLOAD];
+       u16 pl_len;
 } __packed;
 
 /**
@@ -126,6 +132,8 @@ struct zfcp_dbf_hba_res {
        u8  prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
        u32 fsf_status;
        u8  fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
+       u32 port_handle;
+       u32 lun_handle;
 } __packed;
 
 /**
@@ -279,7 +287,7 @@ static inline
 void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)
 {
        if (debug_level_enabled(req->adapter->dbf->hba, level))
-               zfcp_dbf_hba_fsf_res(tag, req);
+               zfcp_dbf_hba_fsf_res(tag, level, req);
 }
 
 /**
@@ -318,7 +326,7 @@ void _zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *scmd,
                                        scmd->device->host->hostdata[0];
 
        if (debug_level_enabled(adapter->dbf->scsi, level))
-               zfcp_dbf_scsi(tag, scmd, req);
+               zfcp_dbf_scsi(tag, level, scmd, req);
 }
 
 /**
index 3fb410977014f81821e5dd16f65eebcd7f43c4d7..a59d678125bd0e0ad0bd1ca74b0d42985abb25d8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Error Recovery Procedures (ERP).
  *
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2015
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -1217,8 +1217,14 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
                break;
 
        case ZFCP_ERP_ACTION_REOPEN_PORT:
-               if (result == ZFCP_ERP_SUCCEEDED)
-                       zfcp_scsi_schedule_rport_register(port);
+               /* This switch case might also happen after a forced reopen
+                * was successfully done and thus overwritten with a new
+                * non-forced reopen at `ersfs_2'. In this case, we must not
+                * do the clean-up of the non-forced version.
+                */
+               if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
+                       if (result == ZFCP_ERP_SUCCEEDED)
+                               zfcp_scsi_schedule_rport_register(port);
                /* fall through */
        case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
                put_device(&port->dev);
index 5b500652572b7c1395cc801c146f41535d310f31..c8fed9fa1cca3680015913162ce3ddfee50c85b1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * External function declarations.
  *
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2015
  */
 
 #ifndef ZFCP_EXT_H
@@ -35,8 +35,9 @@ extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *);
 extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *,
                              struct zfcp_port *, struct scsi_device *, u8, u8);
 extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *);
+extern void zfcp_dbf_rec_run_wka(char *, struct zfcp_fc_wka_port *, u64);
 extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_hba_fsf_res(char *, int, struct zfcp_fsf_req *);
 extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
 extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
 extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
@@ -44,7 +45,8 @@ extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *);
 extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
 extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
 extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
-extern void zfcp_dbf_scsi(char *, struct scsi_cmnd *, struct zfcp_fsf_req *);
+extern void zfcp_dbf_scsi(char *, int, struct scsi_cmnd *,
+                         struct zfcp_fsf_req *);
 
 /* zfcp_erp.c */
 extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32);
index 522a633c866a8b1e464ec857f179365e68bb6530..75f820ca17b79b0574e3afd91df18998a3438c30 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Implementation of FSF commands.
  *
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2015
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -508,7 +508,10 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
                fc_host_port_type(shost) = FC_PORTTYPE_PTP;
                break;
        case FSF_TOPO_FABRIC:
-               fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+               if (bottom->connection_features & FSF_FEATURE_NPIV_MODE)
+                       fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+               else
+                       fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
                break;
        case FSF_TOPO_AL:
                fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
@@ -613,7 +616,6 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
 
        if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
                fc_host_permanent_port_name(shost) = bottom->wwpn;
-               fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
        } else
                fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
        fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
@@ -982,8 +984,12 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
        if (zfcp_adapter_multi_buffer_active(adapter)) {
                if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
                        return -EIO;
+               qtcb->bottom.support.req_buf_length =
+                       zfcp_qdio_real_bytes(sg_req);
                if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
                        return -EIO;
+               qtcb->bottom.support.resp_buf_length =
+                       zfcp_qdio_real_bytes(sg_resp);
 
                zfcp_qdio_set_data_div(qdio, &req->qdio_req,
                                        zfcp_qdio_sbale_count(sg_req));
@@ -1073,6 +1079,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
 
        req->handler = zfcp_fsf_send_ct_handler;
        req->qtcb->header.port_handle = wka_port->handle;
+       ct->d_id = wka_port->d_id;
        req->data = ct;
 
        zfcp_dbf_san_req("fssct_1", req, wka_port->d_id);
@@ -1169,6 +1176,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
 
        hton24(req->qtcb->bottom.support.d_id, d_id);
        req->handler = zfcp_fsf_send_els_handler;
+       els->d_id = d_id;
        req->data = els;
 
        zfcp_dbf_san_req("fssels1", req, d_id);
@@ -1575,7 +1583,7 @@ out:
 int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
        struct zfcp_qdio *qdio = wka_port->adapter->qdio;
-       struct zfcp_fsf_req *req;
+       struct zfcp_fsf_req *req = NULL;
        int retval = -EIO;
 
        spin_lock_irq(&qdio->req_q_lock);
@@ -1604,6 +1612,8 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
                zfcp_fsf_req_free(req);
 out:
        spin_unlock_irq(&qdio->req_q_lock);
+       if (req && !IS_ERR(req))
+               zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id);
        return retval;
 }
 
@@ -1628,7 +1638,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
 int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
        struct zfcp_qdio *qdio = wka_port->adapter->qdio;
-       struct zfcp_fsf_req *req;
+       struct zfcp_fsf_req *req = NULL;
        int retval = -EIO;
 
        spin_lock_irq(&qdio->req_q_lock);
@@ -1657,6 +1667,8 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
                zfcp_fsf_req_free(req);
 out:
        spin_unlock_irq(&qdio->req_q_lock);
+       if (req && !IS_ERR(req))
+               zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id);
        return retval;
 }
 
index 57ae3ae1046d126d6dfe6769e2885bc8f210a7a9..be1c04b334c51f678d643e4c488173f8fd6be0ee 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Interface to the FSF support functions.
  *
- * Copyright IBM Corp. 2002, 2010
+ * Copyright IBM Corp. 2002, 2015
  */
 
 #ifndef FSF_H
@@ -436,6 +436,7 @@ struct zfcp_blk_drv_data {
  * @handler_data: data passed to handler function
  * @port: Optional pointer to port for zfcp internal ELS (only test link ADISC)
  * @status: used to pass error status to calling function
+ * @d_id: Destination ID of either open WKA port for CT or of D_ID for ELS
  */
 struct zfcp_fsf_ct_els {
        struct scatterlist *req;
@@ -444,6 +445,7 @@ struct zfcp_fsf_ct_els {
        void *handler_data;
        struct zfcp_port *port;
        int status;
+       u32 d_id;
 };
 
 #endif                         /* FSF_H */
index b3c6ff49103b851f6467da7ff1fcb361865e2698..9069f98a18172e754c943010654de65e91c2fb7c 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Interface to Linux SCSI midlayer.
  *
- * Copyright IBM Corp. 2002, 2013
+ * Copyright IBM Corp. 2002, 2015
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -556,6 +556,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
        ids.port_id = port->d_id;
        ids.roles = FC_RPORT_ROLE_FCP_TARGET;
 
+       zfcp_dbf_rec_trig("scpaddy", port->adapter, port, NULL,
+                         ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD,
+                         ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD);
        rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
        if (!rport) {
                dev_err(&port->adapter->ccw_device->dev,
@@ -577,6 +580,9 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port)
        struct fc_rport *rport = port->rport;
 
        if (rport) {
+               zfcp_dbf_rec_trig("scpdely", port->adapter, port, NULL,
+                                 ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL,
+                                 ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL);
                fc_remote_port_delete(rport);
                port->rport = NULL;
        }
index 54195a117f72e1f29241b1d079eb8de96e0df056..f78cc943d230eb251c88e275f939cbd5fd6943f2 100644 (file)
@@ -63,7 +63,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
        struct fib *fibptr;
        struct hw_fib * hw_fib = (struct hw_fib *)0;
        dma_addr_t hw_fib_pa = (dma_addr_t)0LL;
-       unsigned size;
+       unsigned int size, osize;
        int retval;
 
        if (dev->in_reset) {
@@ -87,7 +87,8 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
         *      will not overrun the buffer when we copy the memory. Return
         *      an error if we would.
         */
-       size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr);
+       osize = size = le16_to_cpu(kfib->header.Size) +
+               sizeof(struct aac_fibhdr);
        if (size < le16_to_cpu(kfib->header.SenderSize))
                size = le16_to_cpu(kfib->header.SenderSize);
        if (size > dev->max_fib_size) {
@@ -118,6 +119,14 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
                goto cleanup;
        }
 
+       /* Sanity check the second copy */
+       if ((osize != le16_to_cpu(kfib->header.Size) +
+               sizeof(struct aac_fibhdr))
+               || (size < le16_to_cpu(kfib->header.SenderSize))) {
+               retval = -EINVAL;
+               goto cleanup;
+       }
+
        if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
                aac_adapter_interrupt(dev);
                /*
index 333db5953607e49b284f780f1b4532c81fe5ea01..8db9f3a5844d3948e3528570299f323db265f86d 100644 (file)
@@ -2297,15 +2297,23 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
        }
        case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
                unsigned char *ver_addr;
-               int32_t user_len, cnt2end;
+               uint32_t user_len;
+               int32_t cnt2end;
                uint8_t *pQbuffer, *ptmpuserbuffer;
+
+               user_len = pcmdmessagefld->cmdmessage.Length;
+               if (user_len > ARCMSR_API_DATA_BUFLEN) {
+                       retvalue = ARCMSR_MESSAGE_FAIL;
+                       goto message_out;
+               }
+
                ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC);
                if (!ver_addr) {
                        retvalue = ARCMSR_MESSAGE_FAIL;
                        goto message_out;
                }
                ptmpuserbuffer = ver_addr;
-               user_len = pcmdmessagefld->cmdmessage.Length;
+
                memcpy(ptmpuserbuffer,
                        pcmdmessagefld->messagedatabuffer, user_len);
                spin_lock_irqsave(&acb->wqbuffer_lock, flags);
@@ -2664,7 +2672,7 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
        if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
                        miscellaneous data' timeout \n", acb->host->host_no);
-               return false;
+               goto err_free_dma;
        }
        count = 8;
        while (count){
@@ -2694,19 +2702,23 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
                acb->firm_model,
                acb->firm_version);
 
-       acb->signature = readl(&reg->message_rwbuffer[1]);
+       acb->signature = readl(&reg->message_rwbuffer[0]);
        /*firm_signature,1,00-03*/
-       acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+       acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
        /*firm_request_len,1,04-07*/
-       acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+       acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
        /*firm_numbers_queue,2,08-11*/
-       acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+       acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
        /*firm_sdram_size,3,12-15*/
-       acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+       acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
        /*firm_ide_channels,4,16-19*/
        acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
        /*firm_ide_channels,4,16-19*/
        return true;
+err_free_dma:
+       dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
+                       acb->dma_coherent2, acb->dma_coherent_handle2);
+       return false;
 }
 
 static bool arcmsr_hbaC_get_config(struct AdapterControlBlock *pACB)
@@ -2880,15 +2892,15 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
                iop_device_map++;
                count--;
        }
-       acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+       acb->signature = readl(&reg->msgcode_rwbuffer[0]);
        /*firm_signature,1,00-03*/
-       acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+       acb->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
        /*firm_request_len,1,04-07*/
-       acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+       acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
        /*firm_numbers_queue,2,08-11*/
-       acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+       acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
        /*firm_sdram_size,3,12-15*/
-       acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+       acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
        /*firm_hd_channels,4,16-19*/
        acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
        pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
index fa09d4be2b5341436dba4e61c733543de7da57e9..2b456ca69d5c5dbafc2394074ad51e325d9f933d 100644 (file)
@@ -1181,8 +1181,9 @@ static const char * const snstext[] = {
 
 /* Get sense key string or NULL if not available */
 const char *
-scsi_sense_key_string(unsigned char key) {
-       if (key <= 0xE)
+scsi_sense_key_string(unsigned char key)
+{
+       if (key < ARRAY_SIZE(snstext))
                return snstext[key];
        return NULL;
 }
index c11cd193f8964ff1741453e309a85a0f6d5d4402..5ada9268a450db224663f2fa28e43fc79701c886 100644 (file)
@@ -165,6 +165,8 @@ struct afu {
        struct sisl_host_map __iomem *host_map;         /* MC host map */
        struct sisl_ctrl_map __iomem *ctrl_map;         /* MC control map */
 
+       struct kref mapcount;
+
        ctx_hndl_t ctx_hndl;    /* master's context handle */
        u64 *hrrq_start;
        u64 *hrrq_end;
index 1e5bf0ca81da1043a3be9d752271baf9c0a85836..c86847c6844824ef1105286dba94b73af6fde998 100644 (file)
@@ -289,7 +289,7 @@ static void context_reset(struct afu_cmd *cmd)
                atomic64_set(&afu->room, room);
                if (room)
                        goto write_rrin;
-               udelay(nretry);
+               udelay(1 << nretry);
        } while (nretry++ < MC_ROOM_RETRY_CNT);
 
        pr_err("%s: no cmd_room to send reset\n", __func__);
@@ -303,7 +303,7 @@ write_rrin:
                if (rrin != 0x1)
                        break;
                /* Double delay each time */
-               udelay(2 << nretry);
+               udelay(1 << nretry);
        } while (nretry++ < MC_ROOM_RETRY_CNT);
 }
 
@@ -338,7 +338,7 @@ retry:
                        atomic64_set(&afu->room, room);
                        if (room)
                                goto write_ioarrin;
-                       udelay(nretry);
+                       udelay(1 << nretry);
                } while (nretry++ < MC_ROOM_RETRY_CNT);
 
                dev_err(dev, "%s: no cmd_room to send 0x%X\n",
@@ -352,7 +352,7 @@ retry:
                 * afu->room.
                 */
                if (nretry++ < MC_ROOM_RETRY_CNT) {
-                       udelay(nretry);
+                       udelay(1 << nretry);
                        goto retry;
                }
 
@@ -368,6 +368,7 @@ out:
 
 no_room:
        afu->read_room = true;
+       kref_get(&cfg->afu->mapcount);
        schedule_work(&cfg->work_q);
        rc = SCSI_MLQUEUE_HOST_BUSY;
        goto out;
@@ -473,6 +474,16 @@ out:
        return rc;
 }
 
+static void afu_unmap(struct kref *ref)
+{
+       struct afu *afu = container_of(ref, struct afu, mapcount);
+
+       if (likely(afu->afu_map)) {
+               cxl_psa_unmap((void __iomem *)afu->afu_map);
+               afu->afu_map = NULL;
+       }
+}
+
 /**
  * cxlflash_driver_info() - information handler for this host driver
  * @host:      SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        ulong lock_flags;
        short lflag = 0;
        int rc = 0;
+       int kref_got = 0;
 
        dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
                            "cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
                goto out;
        }
 
+       kref_get(&cfg->afu->mapcount);
+       kref_got = 1;
+
        cmd->rcb.ctx_id = afu->ctx_hndl;
        cmd->rcb.port_sel = port_sel;
        cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        }
 
 out:
+       if (kref_got)
+               kref_put(&afu->mapcount, afu_unmap);
        pr_devel("%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
@@ -632,20 +649,36 @@ static void free_mem(struct cxlflash_cfg *cfg)
  * @cfg:       Internal structure associated with the host.
  *
  * Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ *  - complete() will take care of commands we initiated (they'll be checked
+ *  in as part of the cleanup that occurs after the completion)
+ *
+ *  - cmd_checkin() will take care of entries that we did not initiate and that
+ *  have not (and will not) complete because they are sitting on a [now stale]
+ *  hardware queue
  */
 static void stop_afu(struct cxlflash_cfg *cfg)
 {
        int i;
        struct afu *afu = cfg->afu;
+       struct afu_cmd *cmd;
 
        if (likely(afu)) {
-               for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
-                       complete(&afu->cmd[i].cevent);
+               for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+                       cmd = &afu->cmd[i];
+                       complete(&cmd->cevent);
+                       if (!atomic_read(&cmd->free))
+                               cmd_checkin(cmd);
+               }
 
                if (likely(afu->afu_map)) {
                        cxl_psa_unmap((void __iomem *)afu->afu_map);
                        afu->afu_map = NULL;
                }
+               kref_put(&afu->mapcount, afu_unmap);
        }
 }
 
@@ -731,8 +764,8 @@ static void cxlflash_remove(struct pci_dev *pdev)
                scsi_remove_host(cfg->host);
                /* fall through */
        case INIT_STATE_AFU:
-               term_afu(cfg);
                cancel_work_sync(&cfg->work_q);
+               term_afu(cfg);
        case INIT_STATE_PCI:
                pci_release_regions(cfg->dev);
                pci_disable_device(pdev);
@@ -1108,7 +1141,7 @@ static const struct asyc_intr_info ainfo[] = {
        {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
        {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
        {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
-       {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+       {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
        {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
        {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
        {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
@@ -1316,6 +1349,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
                                __func__, port);
                        cfg->lr_state = LINK_RESET_REQUIRED;
                        cfg->lr_port = port;
+                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
 
@@ -1336,6 +1370,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
 
                if (info->action & SCAN_HOST) {
                        atomic_inc(&cfg->scan_host_needed);
+                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
        }
@@ -1731,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
                rc = -ENOMEM;
                goto err1;
        }
+       kref_init(&afu->mapcount);
 
        /* No byte reverse on reading afu_version or string will be backwards */
        reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,8 +1801,7 @@ out:
        return rc;
 
 err2:
-       cxl_psa_unmap((void __iomem *)afu->afu_map);
-       afu->afu_map = NULL;
+       kref_put(&afu->mapcount, afu_unmap);
 err1:
        term_mc(cfg, UNDO_START);
        goto out;
@@ -2114,6 +2149,16 @@ static ssize_t lun_mode_store(struct device *dev,
        rc = kstrtouint(buf, 10, &lun_mode);
        if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
                afu->internal_lun = lun_mode;
+
+               /*
+                * When configured for internal LUN, there is only one channel,
+                * channel number 0, else there will be 2 (default).
+                */
+               if (afu->internal_lun)
+                       shost->max_channel = 0;
+               else
+                       shost->max_channel = NUM_FC_PORTS - 1;
+
                afu_reset(cfg);
                scsi_scan_host(cfg->host);
        }
@@ -2274,6 +2319,7 @@ static struct scsi_host_template driver_template = {
  * Device dependent values
  */
 static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS };
 
 /*
  * PCI device binding table
@@ -2281,6 +2327,8 @@ static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
 static struct pci_device_id cxlflash_pci_table[] = {
        {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+       {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
        {}
 };
 
@@ -2339,6 +2387,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
 
        if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
                scsi_scan_host(cfg->host);
+       kref_put(&afu->mapcount, afu_unmap);
 }
 
 /**
index 60324566c14f4f85a5178581d39648e5c5115e00..3d2d606fafb3754a0ce6a77ba76025b3f66b8fd3 100644 (file)
@@ -24,8 +24,8 @@
 #define CXLFLASH_ADAPTER_NAME  "IBM POWER CXL Flash Adapter"
 #define CXLFLASH_DRIVER_DATE   "(August 13, 2015)"
 
-#define PCI_DEVICE_ID_IBM_CORSA        0x04F0
-#define CXLFLASH_SUBS_DEV_ID   0x04F0
+#define PCI_DEVICE_ID_IBM_CORSA                0x04F0
+#define PCI_DEVICE_ID_IBM_FLASH_GT     0x0600
 
 /* Since there is only one target, make it 0 */
 #define CXLFLASH_TARGET                0
index cac2e6a50efd83ab001bdb84cf56fb2d8d1d35b2..babe7ccc177788bd414f0f1941337a193d0678b6 100644 (file)
@@ -1380,7 +1380,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
        }
 
        ctxid = cxl_process_element(ctx);
-       if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+       if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
                dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
                rc = -EPERM;
                goto err2;
@@ -1508,7 +1508,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
        }
 
        ctxid = cxl_process_element(ctx);
-       if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+       if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
                dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
                rc = -EPERM;
                goto err1;
@@ -1590,6 +1590,13 @@ err1:
  * place at the same time and the failure was due to CXL services being
  * unable to keep up.
  *
+ * As this routine is called on ioctl context, it holds the ioctl r/w
+ * semaphore that is used to drain ioctls in recovery scenarios. The
+ * implementation to achieve the pacing described above (a local mutex)
+ * requires that the ioctl r/w semaphore be dropped and reacquired to
+ * avoid a 3-way deadlock when multiple process recoveries operate in
+ * parallel.
+ *
  * Because a user can detect an error condition before the kernel, it is
  * quite possible for this routine to act as the kernel's EEH detection
  * source (MMIO read of mbox_r). Because of this, there is a window of
@@ -1617,9 +1624,17 @@ static int cxlflash_afu_recover(struct scsi_device *sdev,
        int rc = 0;
 
        atomic_inc(&cfg->recovery_threads);
+       up_read(&cfg->ioctl_rwsem);
        rc = mutex_lock_interruptible(mutex);
+       down_read(&cfg->ioctl_rwsem);
        if (rc)
                goto out;
+       rc = check_state(cfg);
+       if (rc) {
+               dev_err(dev, "%s: Failed state! rc=%d\n", __func__, rc);
+               rc = -ENODEV;
+               goto out;
+       }
 
        dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n",
                __func__, recover->reason, rctxid);
index a53f583e2d7b1ea5b58e817e66715a35567698da..50f8e93007704667fb0c1311834c0a5f0d50ff52 100644 (file)
@@ -1008,6 +1008,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
        virt->last_lba = last_lba;
        virt->rsrc_handle = rsrc_handle;
 
+       if (lli->port_sel == BOTH_PORTS)
+               virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
 out:
        if (likely(ctxi))
                put_context(ctxi);
index 67669a9e73c1c94c7c9deeff3b5c3bc0723cada2..f3a33312a9a682e26148e9e6cebe4a8094288ab6 100644 (file)
@@ -954,8 +954,8 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq)
        skb_put(skb, len);
        pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE);
 
-       r = pci_dma_mapping_error(fnic->pdev, pa);
-       if (r) {
+       if (pci_dma_mapping_error(fnic->pdev, pa)) {
+               r = -ENOMEM;
                printk(KERN_ERR "PCI mapping failed with error %d\n", r);
                goto free_skb;
        }
@@ -1093,8 +1093,8 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
 
        pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE);
 
-       ret = pci_dma_mapping_error(fnic->pdev, pa);
-       if (ret) {
+       if (pci_dma_mapping_error(fnic->pdev, pa)) {
+               ret = -ENOMEM;
                printk(KERN_ERR "DMA map failed with error %d\n", ret);
                goto free_skb_on_err;
        }
index a3860367b568aa06adf4290bf84717458c241e77..e9ce74afd13f4672e941d620f16ab602c647d33e 100644 (file)
@@ -3930,6 +3930,70 @@ static int hpsa_set_local_logical_count(struct ctlr_info *h,
        return rc;
 }
 
+static bool hpsa_is_disk_spare(struct ctlr_info *h, u8 *lunaddrbytes)
+{
+       struct bmic_identify_physical_device *id_phys;
+       bool is_spare = false;
+       int rc;
+
+       id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+       if (!id_phys)
+               return false;
+
+       rc = hpsa_bmic_id_physical_device(h,
+                                       lunaddrbytes,
+                                       GET_BMIC_DRIVE_NUMBER(lunaddrbytes),
+                                       id_phys, sizeof(*id_phys));
+       if (rc == 0)
+               is_spare = (id_phys->more_flags >> 6) & 0x01;
+
+       kfree(id_phys);
+       return is_spare;
+}
+
+#define RPL_DEV_FLAG_NON_DISK                           0x1
+#define RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED  0x2
+#define RPL_DEV_FLAG_UNCONFIG_DISK                      0x4
+
+#define BMIC_DEVICE_TYPE_ENCLOSURE  6
+
+static bool hpsa_skip_device(struct ctlr_info *h, u8 *lunaddrbytes,
+                               struct ext_report_lun_entry *rle)
+{
+       u8 device_flags;
+       u8 device_type;
+
+       if (!MASKED_DEVICE(lunaddrbytes))
+               return false;
+
+       device_flags = rle->device_flags;
+       device_type = rle->device_type;
+
+       if (device_flags & RPL_DEV_FLAG_NON_DISK) {
+               if (device_type == BMIC_DEVICE_TYPE_ENCLOSURE)
+                       return false;
+               return true;
+       }
+
+       if (!(device_flags & RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED))
+               return false;
+
+       if (device_flags & RPL_DEV_FLAG_UNCONFIG_DISK)
+               return false;
+
+       /*
+        * Spares may be spun down, we do not want to
+        * do an Inquiry to a RAID set spare drive as
+        * that would have them spun up, that is a
+        * performance hit because I/O to the RAID device
+        * stops while the spin up occurs which can take
+        * over 50 seconds.
+        */
+       if (hpsa_is_disk_spare(h, lunaddrbytes))
+               return true;
+
+       return false;
+}
 
 static void hpsa_update_scsi_devices(struct ctlr_info *h)
 {
@@ -4023,6 +4087,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
                u8 *lunaddrbytes, is_OBDR = 0;
                int rc = 0;
                int phys_dev_index = i - (raid_ctlr_position == 0);
+               bool skip_device = false;
 
                physical_device = i < nphysicals + (raid_ctlr_position == 0);
 
@@ -4030,10 +4095,15 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
                lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
                        i, nphysicals, nlogicals, physdev_list, logdev_list);
 
-               /* skip masked non-disk devices */
-               if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
-                       (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
-                       continue;
+               /*
+                * Skip over some devices such as a spare.
+                */
+               if (!tmpdevice->external && physical_device) {
+                       skip_device = hpsa_skip_device(h, lunaddrbytes,
+                                       &physdev_list->LUN[phys_dev_index]);
+                       if (skip_device)
+                               continue;
+               }
 
                /* Get device type, vendor, model, device id */
                rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
index 6aa317c303e2dced686c76cc1102e563b4f058b1..1f9f9e5af2072ec2e5467e4a0203cfe0c815916b 100644 (file)
@@ -717,7 +717,6 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
        spin_lock_irqsave(vhost->host->host_lock, flags);
        vhost->state = IBMVFC_NO_CRQ;
        vhost->logged_in = 0;
-       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
 
        /* Clean out the queue */
        memset(crq->msgs, 0, PAGE_SIZE);
index 43ac62623bf266578c575875e5802fc3613aed54..7a58128a00000449cac04ceab12a3302c3d7d816 100644 (file)
@@ -10095,6 +10095,7 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
                ioa_cfg->intr_flag = IPR_USE_MSI;
        else {
                ioa_cfg->intr_flag = IPR_USE_LSI;
+               ioa_cfg->clear_isr = 1;
                ioa_cfg->nvectors = 1;
                dev_info(&pdev->dev, "Cannot enable MSI.\n");
        }
index b0e6fe46448d000f13efc41bdeffd509ee8395de..80d3c740a8a84d9dd4d330b6bc6db4ae928c5cdb 100644 (file)
@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
 void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 
+void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
index b6fa257ea3e0ba802e65f57d46c45944318bef7b..59ced8864b2f383b8c0d84e9c1d7af286596206e 100644 (file)
@@ -455,9 +455,9 @@ int
 lpfc_issue_reg_vfi(struct lpfc_vport *vport)
 {
        struct lpfc_hba  *phba = vport->phba;
-       LPFC_MBOXQ_t *mboxq;
+       LPFC_MBOXQ_t *mboxq = NULL;
        struct lpfc_nodelist *ndlp;
-       struct lpfc_dmabuf *dmabuf;
+       struct lpfc_dmabuf *dmabuf = NULL;
        int rc = 0;
 
        /* move forward in case of SLI4 FC port loopback test and pt2pt mode */
@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
                }
        }
 
-       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-       if (!dmabuf) {
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
                rc = -ENOMEM;
                goto fail;
        }
-       dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
-       if (!dmabuf->virt) {
-               rc = -ENOMEM;
-               goto fail_free_dmabuf;
-       }
 
-       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mboxq) {
-               rc = -ENOMEM;
-               goto fail_free_coherent;
+       /* Supply CSP's only if we are fabric connect or pt-to-pt connect */
+       if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
+               dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+               if (!dmabuf) {
+                       rc = -ENOMEM;
+                       goto fail;
+               }
+               dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+               if (!dmabuf->virt) {
+                       rc = -ENOMEM;
+                       goto fail;
+               }
+               memcpy(dmabuf->virt, &phba->fc_fabparam,
+                      sizeof(struct serv_parm));
        }
+
        vport->port_state = LPFC_FABRIC_CFG_LINK;
-       memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
-       lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+       if (dmabuf)
+               lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+       else
+               lpfc_reg_vfi(mboxq, vport, 0);
 
        mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
        mboxq->vport = vport;
@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED) {
                rc = -ENXIO;
-               goto fail_free_mbox;
+               goto fail;
        }
        return 0;
 
-fail_free_mbox:
-       mempool_free(mboxq, phba->mbox_mem_pool);
-fail_free_coherent:
-       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-fail_free_dmabuf:
-       kfree(dmabuf);
 fail:
+       if (mboxq)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       if (dmabuf) {
+               if (dmabuf->virt)
+                       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
+
        lpfc_vport_set_state(vport, FC_VPORT_FAILED);
        lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
                "0289 Issue Register VFI failed: Err %d\n", rc);
@@ -711,9 +721,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
         * For FC we need to do some special processing because of the SLI
         * Port's default settings of the Common Service Parameters.
         */
-       if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+       if ((phba->sli_rev == LPFC_SLI_REV4) &&
+           (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
                /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
-               if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+               if (fabric_param_changed)
                        lpfc_unregister_fcf_prep(phba);
 
                /* This should just update the VFI CSPs*/
@@ -824,13 +835,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+       vport->fc_flag |= FC_PT2PT;
        spin_unlock_irq(shost->host_lock);
 
-       phba->fc_edtov = FF_DEF_EDTOV;
-       phba->fc_ratov = FF_DEF_RATOV;
+       /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+       if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
+               lpfc_unregister_fcf_prep(phba);
+
+               spin_lock_irq(shost->host_lock);
+               vport->fc_flag &= ~FC_VFI_REGISTERED;
+               spin_unlock_irq(shost->host_lock);
+               phba->fc_topology_changed = 0;
+       }
+
        rc = memcmp(&vport->fc_portname, &sp->portName,
                    sizeof(vport->fc_portname));
-       memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
 
        if (rc >= 0) {
                /* This side will initiate the PLOGI */
@@ -839,38 +858,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                spin_unlock_irq(shost->host_lock);
 
                /*
-                * N_Port ID cannot be 0, set our to LocalID the other
-                * side will be RemoteID.
+                * N_Port ID cannot be 0, set our Id to LocalID
+                * the other side will be RemoteID.
                 */
 
                /* not equal */
                if (rc)
                        vport->fc_myDID = PT2PT_LocalID;
 
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (!mbox)
-                       goto fail;
-
-               lpfc_config_link(phba, mbox);
-
-               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(mbox, phba->mbox_mem_pool);
-                       goto fail;
-               }
-
-               /*
-                * For SLI4, the VFI/VPI are registered AFTER the
-                * Nport with the higher WWPN sends the PLOGI with
-                * an assigned NPortId.
-                */
-
-               /* not equal */
-               if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
-                       lpfc_issue_reg_vfi(vport);
-
                /* Decrement ndlp reference count indicating that ndlp can be
                 * safely released when other references to it are done.
                 */
@@ -912,29 +907,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* If we are pt2pt with another NPort, force NPIV off! */
        phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
 
-       spin_lock_irq(shost->host_lock);
-       vport->fc_flag |= FC_PT2PT;
-       spin_unlock_irq(shost->host_lock);
-       /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
-       if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
-               lpfc_unregister_fcf_prep(phba);
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               goto fail;
 
-               /* The FC_VFI_REGISTERED flag will get clear in the cmpl
-                * handler for unreg_vfi, but if we don't force the
-                * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be
-                * built with the update bit set instead of just the vp bit to
-                * change the Nport ID.  We need to have the vp set and the
-                * Upd cleared on topology changes.
-                */
-               spin_lock_irq(shost->host_lock);
-               vport->fc_flag &= ~FC_VFI_REGISTERED;
-               spin_unlock_irq(shost->host_lock);
-               phba->fc_topology_changed = 0;
-               lpfc_issue_reg_vfi(vport);
+       lpfc_config_link(phba, mbox);
+
+       mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+       mbox->vport = vport;
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               mempool_free(mbox, phba->mbox_mem_pool);
+               goto fail;
        }
 
-       /* Start discovery - this should just do CLEAR_LA */
-       lpfc_disc_start(vport);
        return 0;
 fail:
        return -ENXIO;
@@ -1157,6 +1143,7 @@ flogifail:
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
        spin_unlock_irq(&phba->hbalock);
+
        lpfc_nlp_put(ndlp);
 
        if (!lpfc_error_lost_link(irsp)) {
@@ -3792,14 +3779,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                lpfc_nlp_set_state(vport, ndlp,
                                           NLP_STE_REG_LOGIN_ISSUE);
                        }
+
+                       ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
                        if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
                            != MBX_NOT_FINISHED)
                                goto out;
-                       else
-                               /* Decrement the ndlp reference count we
-                                * set for this failed mailbox command.
-                                */
-                               lpfc_nlp_put(ndlp);
+
+                       /* Decrement the ndlp reference count we
+                        * set for this failed mailbox command.
+                        */
+                       lpfc_nlp_put(ndlp);
+                       ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
 
                        /* ELS rsp: Cannot issue reg_login for <NPortid> */
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -3856,6 +3846,7 @@ out:
                                 * the routine lpfc_els_free_iocb.
                                 */
                                cmdiocb->context1 = NULL;
+
        }
 
        lpfc_els_free_iocb(phba, cmdiocb);
@@ -3898,6 +3889,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
        IOCB_t *oldcmd;
        struct lpfc_iocbq *elsiocb;
        uint8_t *pcmd;
+       struct serv_parm *sp;
        uint16_t cmdsize;
        int rc;
        ELS_PKT *els_pkt_ptr;
@@ -3927,6 +3919,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                        "Issue ACC:       did:x%x flg:x%x",
                        ndlp->nlp_DID, ndlp->nlp_flag, 0);
                break;
+       case ELS_CMD_FLOGI:
        case ELS_CMD_PLOGI:
                cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
                elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
@@ -3944,10 +3937,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
 
                *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
                pcmd += sizeof(uint32_t);
-               memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+               sp = (struct serv_parm *)pcmd;
+
+               if (flag == ELS_CMD_FLOGI) {
+                       /* Copy the received service parameters back */
+                       memcpy(sp, &phba->fc_fabparam,
+                              sizeof(struct serv_parm));
+
+                       /* Clear the F_Port bit */
+                       sp->cmn.fPort = 0;
+
+                       /* Mark all class service parameters as invalid */
+                       sp->cls1.classValid = 0;
+                       sp->cls2.classValid = 0;
+                       sp->cls3.classValid = 0;
+                       sp->cls4.classValid = 0;
+
+                       /* Copy our worldwide names */
+                       memcpy(&sp->portName, &vport->fc_sparam.portName,
+                              sizeof(struct lpfc_name));
+                       memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
+                              sizeof(struct lpfc_name));
+               } else {
+                       memcpy(pcmd, &vport->fc_sparam,
+                              sizeof(struct serv_parm));
+               }
 
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
-                       "Issue ACC PLOGI: did:x%x flg:x%x",
+                       "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
                        ndlp->nlp_DID, ndlp->nlp_flag, 0);
                break;
        case ELS_CMD_PRLO:
@@ -4681,28 +4698,25 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 
        desc->tag = cpu_to_be32(RDP_PORT_SPEED_DESC_TAG);
 
-       switch (phba->sli4_hba.link_state.speed) {
-       case LPFC_FC_LA_SPEED_1G:
+       switch (phba->fc_linkspeed) {
+       case LPFC_LINK_SPEED_1GHZ:
                rdp_speed = RDP_PS_1GB;
                break;
-       case LPFC_FC_LA_SPEED_2G:
+       case LPFC_LINK_SPEED_2GHZ:
                rdp_speed = RDP_PS_2GB;
                break;
-       case LPFC_FC_LA_SPEED_4G:
+       case LPFC_LINK_SPEED_4GHZ:
                rdp_speed = RDP_PS_4GB;
                break;
-       case LPFC_FC_LA_SPEED_8G:
+       case LPFC_LINK_SPEED_8GHZ:
                rdp_speed = RDP_PS_8GB;
                break;
-       case LPFC_FC_LA_SPEED_10G:
+       case LPFC_LINK_SPEED_10GHZ:
                rdp_speed = RDP_PS_10GB;
                break;
-       case LPFC_FC_LA_SPEED_16G:
+       case LPFC_LINK_SPEED_16GHZ:
                rdp_speed = RDP_PS_16GB;
                break;
-       case LPFC_FC_LA_SPEED_32G:
-               rdp_speed = RDP_PS_32GB;
-               break;
        default:
                rdp_speed = RDP_PS_UNKNOWN;
                break;
@@ -5739,7 +5753,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        IOCB_t *icmd = &cmdiocb->iocb;
        struct serv_parm *sp;
        LPFC_MBOXQ_t *mbox;
-       struct ls_rjt stat;
        uint32_t cmd, did;
        int rc;
        uint32_t fc_flag = 0;
@@ -5765,135 +5778,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                return 1;
        }
 
-       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
-               /* For a FLOGI we accept, then if our portname is greater
-                * then the remote portname we initiate Nport login.
-                */
+       (void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1);
 
-               rc = memcmp(&vport->fc_portname, &sp->portName,
-                           sizeof(struct lpfc_name));
 
-               if (!rc) {
-                       if (phba->sli_rev < LPFC_SLI_REV4) {
-                               mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                    GFP_KERNEL);
-                               if (!mbox)
-                                       return 1;
-                               lpfc_linkdown(phba);
-                               lpfc_init_link(phba, mbox,
-                                              phba->cfg_topology,
-                                              phba->cfg_link_speed);
-                               mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
-                               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-                               mbox->vport = vport;
-                               rc = lpfc_sli_issue_mbox(phba, mbox,
-                                                        MBX_NOWAIT);
-                               lpfc_set_loopback_flag(phba);
-                               if (rc == MBX_NOT_FINISHED)
-                                       mempool_free(mbox, phba->mbox_mem_pool);
-                               return 1;
-                       } else {
-                               /* abort the flogi coming back to ourselves
-                                * due to external loopback on the port.
-                                */
-                               lpfc_els_abort_flogi(phba);
-                               return 0;
-                       }
-               } else if (rc > 0) {    /* greater than */
-                       spin_lock_irq(shost->host_lock);
-                       vport->fc_flag |= FC_PT2PT_PLOGI;
-                       spin_unlock_irq(shost->host_lock);
+       /*
+        * If our portname is greater than the remote portname,
+        * then we initiate Nport login.
+        */
 
-                       /* If we have the high WWPN we can assign our own
-                        * myDID; otherwise, we have to WAIT for a PLOGI
-                        * from the remote NPort to find out what it
-                        * will be.
-                        */
-                       vport->fc_myDID = PT2PT_LocalID;
-               } else
-                       vport->fc_myDID = PT2PT_RemoteID;
+       rc = memcmp(&vport->fc_portname, &sp->portName,
+                   sizeof(struct lpfc_name));
 
-               /*
-                * The vport state should go to LPFC_FLOGI only
-                * AFTER we issue a FLOGI, not receive one.
+       if (!rc) {
+               if (phba->sli_rev < LPFC_SLI_REV4) {
+                       mbox = mempool_alloc(phba->mbox_mem_pool,
+                                            GFP_KERNEL);
+                       if (!mbox)
+                               return 1;
+                       lpfc_linkdown(phba);
+                       lpfc_init_link(phba, mbox,
+                                      phba->cfg_topology,
+                                      phba->cfg_link_speed);
+                       mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       mbox->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, mbox,
+                                                MBX_NOWAIT);
+                       lpfc_set_loopback_flag(phba);
+                       if (rc == MBX_NOT_FINISHED)
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                       return 1;
+               }
+
+               /* abort the flogi coming back to ourselves
+                * due to external loopback on the port.
                 */
+               lpfc_els_abort_flogi(phba);
+               return 0;
+
+       } else if (rc > 0) {    /* greater than */
                spin_lock_irq(shost->host_lock);
-               fc_flag = vport->fc_flag;
-               port_state = vport->port_state;
-               vport->fc_flag |= FC_PT2PT;
-               vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+               vport->fc_flag |= FC_PT2PT_PLOGI;
                spin_unlock_irq(shost->host_lock);
-               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-                                "3311 Rcv Flogi PS x%x new PS x%x "
-                                "fc_flag x%x new fc_flag x%x\n",
-                                port_state, vport->port_state,
-                                fc_flag, vport->fc_flag);
 
-               /*
-                * We temporarily set fc_myDID to make it look like we are
-                * a Fabric. This is done just so we end up with the right
-                * did / sid on the FLOGI ACC rsp.
+               /* If we have the high WWPN we can assign our own
+                * myDID; otherwise, we have to WAIT for a PLOGI
+                * from the remote NPort to find out what it
+                * will be.
                 */
-               did = vport->fc_myDID;
-               vport->fc_myDID = Fabric_DID;
-
+               vport->fc_myDID = PT2PT_LocalID;
        } else {
-               /* Reject this request because invalid parameters */
-               stat.un.b.lsRjtRsvd0 = 0;
-               stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-               stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
-               stat.un.b.vendorUnique = 0;
-
-               /*
-                * We temporarily set fc_myDID to make it look like we are
-                * a Fabric. This is done just so we end up with the right
-                * did / sid on the FLOGI LS_RJT rsp.
-                */
-               did = vport->fc_myDID;
-               vport->fc_myDID = Fabric_DID;
-
-               lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
-                       NULL);
+               vport->fc_myDID = PT2PT_RemoteID;
+       }
 
-               /* Now lets put fc_myDID back to what its supposed to be */
-               vport->fc_myDID = did;
+       /*
+        * The vport state should go to LPFC_FLOGI only
+        * AFTER we issue a FLOGI, not receive one.
+        */
+       spin_lock_irq(shost->host_lock);
+       fc_flag = vport->fc_flag;
+       port_state = vport->port_state;
+       vport->fc_flag |= FC_PT2PT;
+       vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+       spin_unlock_irq(shost->host_lock);
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                        "3311 Rcv Flogi PS x%x new PS x%x "
+                        "fc_flag x%x new fc_flag x%x\n",
+                        port_state, vport->port_state,
+                        fc_flag, vport->fc_flag);
 
-               return 1;
-       }
+       /*
+        * We temporarily set fc_myDID to make it look like we are
+        * a Fabric. This is done just so we end up with the right
+        * did / sid on the FLOGI ACC rsp.
+        */
+       did = vport->fc_myDID;
+       vport->fc_myDID = Fabric_DID;
 
-       /* send our FLOGI first */
-       if (vport->port_state < LPFC_FLOGI) {
-               vport->fc_myDID = 0;
-               lpfc_initial_flogi(vport);
-               vport->fc_myDID = Fabric_DID;
-       }
+       memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
 
        /* Send back ACC */
-       lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+       lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
 
        /* Now lets put fc_myDID back to what its supposed to be */
        vport->fc_myDID = did;
 
-       if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (!mbox)
-                       goto fail;
-
-               lpfc_config_link(phba, mbox);
-
-               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(mbox, phba->mbox_mem_pool);
-                       goto fail;
-               }
-       }
-
        return 0;
-fail:
-       return 1;
 }
 
 /**
@@ -7345,7 +7315,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        /* reject till our FLOGI completes */
        if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
-               (cmd != ELS_CMD_FLOGI)) {
+           (cmd != ELS_CMD_FLOGI)) {
                rjt_err = LSRJT_UNABLE_TPC;
                rjt_exp = LSEXP_NOTHING_MORE;
                goto lsrjt;
@@ -7381,6 +7351,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        rjt_exp = LSEXP_NOTHING_MORE;
                        break;
                }
+
                if (vport->port_state < LPFC_DISC_AUTH) {
                        if (!(phba->pport->fc_flag & FC_PT2PT) ||
                                (phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
index bfc2442dd74a5738283b32f78506af70f85bb327..d3668aa555d53ab5fdf3d42ff66ae69eb4bc05ae 100644 (file)
@@ -1083,7 +1083,7 @@ out:
 }
 
 
-static void
+void
 lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
@@ -1113,8 +1113,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        /* Start discovery by sending a FLOGI. port_state is identically
         * LPFC_FLOGI while waiting for FLOGI cmpl
         */
-       if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
+       if (vport->port_state != LPFC_FLOGI)
                lpfc_initial_flogi(vport);
+       else if (vport->fc_flag & FC_PT2PT)
+               lpfc_disc_start(vport);
        return;
 
 out:
@@ -2963,8 +2965,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 
 out_free_mem:
        mempool_free(mboxq, phba->mbox_mem_pool);
-       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-       kfree(dmabuf);
+       if (dmabuf) {
+               lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
        return;
 }
 
@@ -3448,10 +3452,10 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
                spin_unlock_irq(shost->host_lock);
-       } else
-               /* Good status, call state machine */
-               lpfc_disc_state_machine(vport, ndlp, pmb,
-                               NLP_EVT_CMPL_REG_LOGIN);
+       }
+
+       /* Call state machine */
+       lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
 
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
index b0d92b84bcdc201b2d0ccec4338197ed6409c5e8..c14ab6c3ae40a3d074b01ffa482bf5ce5b8304ba 100644 (file)
@@ -8834,9 +8834,12 @@ found:
                                 * already mapped to this phys_id.
                                 */
                                if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) {
-                                       chann[saved_chann] =
-                                               cpup->channel_id;
-                                       saved_chann++;
+                                       if (saved_chann <=
+                                           LPFC_FCP_IO_CHAN_MAX) {
+                                               chann[saved_chann] =
+                                                       cpup->channel_id;
+                                               saved_chann++;
+                                       }
                                        goto out;
                                }
 
index f87f90e9b7dfa2346891585174938012e0f7c794..1e34b5408a293a2cf4238fdb31d7ba87604b01b7 100644 (file)
@@ -2145,10 +2145,12 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
        reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
        reg_vfi->e_d_tov = phba->fc_edtov;
        reg_vfi->r_a_tov = phba->fc_ratov;
-       reg_vfi->bde.addrHigh = putPaddrHigh(phys);
-       reg_vfi->bde.addrLow = putPaddrLow(phys);
-       reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
-       reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+       if (phys) {
+               reg_vfi->bde.addrHigh = putPaddrHigh(phys);
+               reg_vfi->bde.addrLow = putPaddrLow(phys);
+               reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
+               reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+       }
        bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID);
 
        /* Only FC supports upd bit */
index ed9a2c80c4aad4324de640367ca2dbd76d7c15ea..193733e8c8235ac23469493b312f31a6c128e11e 100644 (file)
@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        uint32_t *lp;
        IOCB_t *icmd;
        struct serv_parm *sp;
+       uint32_t ed_tov;
        LPFC_MBOXQ_t *mbox;
        struct ls_rjt stat;
        int rc;
 
        memset(&stat, 0, sizeof (struct ls_rjt));
-       if (vport->port_state <= LPFC_FDISC) {
-               /* Before responding to PLOGI, check for pt2pt mode.
-                * If we are pt2pt, with an outstanding FLOGI, abort
-                * the FLOGI and resend it first.
-                */
-               if (vport->fc_flag & FC_PT2PT) {
-                        lpfc_els_abort_flogi(phba);
-                       if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-                               /* If the other side is supposed to initiate
-                                * the PLOGI anyway, just ACC it now and
-                                * move on with discovery.
-                                */
-                               phba->fc_edtov = FF_DEF_EDTOV;
-                               phba->fc_ratov = FF_DEF_RATOV;
-                               /* Start discovery - this should just do
-                                  CLEAR_LA */
-                               lpfc_disc_start(vport);
-                       } else
-                               lpfc_initial_flogi(vport);
-               } else {
-                       stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
-                       stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-                       lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
-                                           ndlp, NULL);
-                       return 0;
-               }
-       }
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* Check for Nport to NPort pt2pt protocol */
        if ((vport->fc_flag & FC_PT2PT) &&
            !(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
                /* rcv'ed PLOGI decides what our NPortId will be */
                vport->fc_myDID = icmd->un.rcvels.parmRo;
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (mbox == NULL)
-                       goto out;
-               lpfc_config_link(phba, mbox);
-               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(mbox, phba->mbox_mem_pool);
-                       goto out;
+
+               ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+               if (sp->cmn.edtovResolution) {
+                       /* E_D_TOV ticks are in nanoseconds */
+                       ed_tov = (phba->fc_edtov + 999999) / 1000000;
                }
+
                /*
-                * For SLI4, the VFI/VPI are registered AFTER the
-                * Nport with the higher WWPN sends us a PLOGI with
-                * our assigned NPortId.
+                * For pt-to-pt, use the larger EDTOV
+                * RATOV = 2 * EDTOV
                 */
+               if (ed_tov > phba->fc_edtov)
+                       phba->fc_edtov = ed_tov;
+               phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+               memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+               /* Issue config_link / reg_vfi to account for updated TOV's */
+
                if (phba->sli_rev == LPFC_SLI_REV4)
                        lpfc_issue_reg_vfi(vport);
+               else {
+                       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+                       if (mbox == NULL)
+                               goto out;
+                       lpfc_config_link(phba, mbox);
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       mbox->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+                       if (rc == MBX_NOT_FINISHED) {
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                               goto out;
+                       }
+               }
 
                lpfc_can_disctmo(vport);
        }
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox)
                goto out;
@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
        uint32_t *lp;
        IOCB_t *irsp;
        struct serv_parm *sp;
+       uint32_t ed_tov;
        LPFC_MBOXQ_t *mbox;
+       int rc;
 
        cmdiocb = (struct lpfc_iocbq *) arg;
        rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1094,18 +1086,63 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
        ndlp->nlp_maxframe =
                ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
 
+       if ((vport->fc_flag & FC_PT2PT) &&
+           (vport->fc_flag & FC_PT2PT_PLOGI)) {
+               ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+               if (sp->cmn.edtovResolution) {
+                       /* E_D_TOV ticks are in nanoseconds */
+                       ed_tov = (phba->fc_edtov + 999999) / 1000000;
+               }
+
+               /*
+                * Use the larger EDTOV
+                * RATOV = 2 * EDTOV for pt-to-pt
+                */
+               if (ed_tov > phba->fc_edtov)
+                       phba->fc_edtov = ed_tov;
+               phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+               memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+               /* Issue config_link / reg_vfi to account for updated TOV's */
+               if (phba->sli_rev == LPFC_SLI_REV4) {
+                       lpfc_issue_reg_vfi(vport);
+               } else {
+                       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+                       if (!mbox) {
+                               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                                "0133 PLOGI: no memory "
+                                                "for config_link "
+                                                "Data: x%x x%x x%x x%x\n",
+                                                ndlp->nlp_DID, ndlp->nlp_state,
+                                                ndlp->nlp_flag, ndlp->nlp_rpi);
+                               goto out;
+                       }
+
+                       lpfc_config_link(phba, mbox);
+
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       mbox->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+                       if (rc == MBX_NOT_FINISHED) {
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                               goto out;
+                       }
+               }
+       }
+
+       lpfc_unreg_rpi(vport, ndlp);
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-                       "0133 PLOGI: no memory for reg_login "
-                       "Data: x%x x%x x%x x%x\n",
-                       ndlp->nlp_DID, ndlp->nlp_state,
-                       ndlp->nlp_flag, ndlp->nlp_rpi);
+                                "0018 PLOGI: no memory for reg_login "
+                                "Data: x%x x%x x%x x%x\n",
+                                ndlp->nlp_DID, ndlp->nlp_state,
+                                ndlp->nlp_flag, ndlp->nlp_rpi);
                goto out;
        }
 
-       lpfc_unreg_rpi(vport, ndlp);
-
        if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
                         (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
                switch (ndlp->nlp_DID) {
@@ -2299,6 +2336,9 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
                if (vport->phba->sli_rev < LPFC_SLI_REV4)
                        ndlp->nlp_rpi = mb->un.varWords[0];
                ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+               if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+                       lpfc_unreg_rpi(vport, ndlp);
+               }
        } else {
                if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
                        lpfc_drop_node(vport, ndlp);
index 4679ed4444a737e906342473031397b2137443ff..bae36cc3740b69033be7a056e8e88ea456600510 100644 (file)
@@ -3859,7 +3859,7 @@ int lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba,
        uint32_t tag;
        uint16_t hwq;
 
-       if (shost_use_blk_mq(cmnd->device->host)) {
+       if (cmnd && shost_use_blk_mq(cmnd->device->host)) {
                tag = blk_mq_unique_tag(cmnd->request);
                hwq = blk_mq_unique_tag_to_hwq(tag);
 
@@ -3908,9 +3908,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        uint32_t logit = LOG_FCP;
 
        /* Sanity check on return of outstanding command */
-       if (!(lpfc_cmd->pCmd))
-               return;
        cmd = lpfc_cmd->pCmd;
+       if (!cmd)
+               return;
        shost = cmd->device->host;
 
        lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
index f9585cdd89333cf342b92297af61752ab3e63cdf..92dfd6a5178cef9e6826ad9159261765335c264b 100644 (file)
@@ -14842,10 +14842,12 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
        struct lpfc_dmabuf *h_buf;
        struct hbq_dmabuf *seq_dmabuf = NULL;
        struct hbq_dmabuf *temp_dmabuf = NULL;
+       uint8_t found = 0;
 
        INIT_LIST_HEAD(&dmabuf->dbuf.list);
        dmabuf->time_stamp = jiffies;
        new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+
        /* Use the hdr_buf to find the sequence that this frame belongs to */
        list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
                temp_hdr = (struct fc_frame_header *)h_buf->virt;
@@ -14885,7 +14887,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
                return seq_dmabuf;
        }
        /* find the correct place in the sequence to insert this frame */
-       list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+       d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
+       while (!found) {
                temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
                temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
                /*
@@ -14895,9 +14898,17 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
                if (be16_to_cpu(new_hdr->fh_seq_cnt) >
                        be16_to_cpu(temp_hdr->fh_seq_cnt)) {
                        list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
-                       return seq_dmabuf;
+                       found = 1;
+                       break;
                }
+
+               if (&d_buf->list == &seq_dmabuf->dbuf.list)
+                       break;
+               d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
        }
+
+       if (found)
+               return seq_dmabuf;
        return NULL;
 }
 
@@ -16173,7 +16184,7 @@ fail_fcf_read:
 }
 
 /**
- * lpfc_check_next_fcf_pri
+ * lpfc_check_next_fcf_pri_level
  * phba pointer to the lpfc_hba struct for this port.
  * This routine is called from the lpfc_sli4_fcf_rr_next_index_get
  * routine when the rr_bmask is empty. The FCF indecies are put into the
@@ -16329,8 +16340,12 @@ next_priority:
 
        if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
                phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
-               LPFC_FCF_FLOGI_FAILED)
+               LPFC_FCF_FLOGI_FAILED) {
+               if (list_is_singular(&phba->fcf.fcf_pri_list))
+                       return LPFC_FCOE_FCF_NEXT_NONE;
+
                goto next_priority;
+       }
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
                        "2845 Get next roundrobin failover FCF (x%x)\n",
index c0f7c8ce54aa08b668694b4b70e19076ec72dbff..ef4ff03242ea13d825a3ba1993eb9489911d8af4 100644 (file)
@@ -1083,6 +1083,8 @@ struct megasas_ctrl_info {
 
 #define VD_EXT_DEBUG 0
 
+#define SCAN_PD_CHANNEL        0x1
+#define SCAN_VD_CHANNEL        0x2
 
 enum MR_SCSI_CMD_TYPE {
        READ_WRITE_LDIO = 0,
index 00ce3e269a437389232ee3ffb43ee2e1ccbe53b3..278e10cd771f65eca88a87d500924e82f856de7c 100644 (file)
@@ -735,6 +735,7 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
               &(regs)->inbound_high_queue_port);
        writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
               &(regs)->inbound_low_queue_port);
+       mmiowb();
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 }
 
@@ -4669,7 +4670,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
        /* Find first memory bar */
        bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
        instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
-       if (pci_request_selected_regions(instance->pdev, instance->bar,
+       if (pci_request_selected_regions(instance->pdev, 1<<instance->bar,
                                         "megasas: LSI")) {
                dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n");
                return -EBUSY;
@@ -4960,7 +4961,7 @@ fail_ready_state:
        iounmap(instance->reg_set);
 
       fail_ioremap:
-       pci_release_selected_regions(instance->pdev, instance->bar);
+       pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 
        return -EINVAL;
 }
@@ -4981,7 +4982,7 @@ static void megasas_release_mfi(struct megasas_instance *instance)
 
        iounmap(instance->reg_set);
 
-       pci_release_selected_regions(instance->pdev, instance->bar);
+       pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 }
 
 /**
@@ -5476,7 +5477,6 @@ static int megasas_probe_one(struct pci_dev *pdev,
        spin_lock_init(&instance->hba_lock);
        spin_lock_init(&instance->completion_lock);
 
-       mutex_init(&instance->aen_mutex);
        mutex_init(&instance->reset_mutex);
 
        /*
@@ -5941,11 +5941,11 @@ static void megasas_detach_one(struct pci_dev *pdev)
                        if (fusion->ld_drv_map[i])
                                free_pages((ulong)fusion->ld_drv_map[i],
                                        fusion->drv_map_pages);
-                               if (fusion->pd_seq_sync)
-                                       dma_free_coherent(&instance->pdev->dev,
-                                               pd_seq_map_sz,
-                                               fusion->pd_seq_sync[i],
-                                               fusion->pd_seq_phys[i]);
+                       if (fusion->pd_seq_sync[i])
+                               dma_free_coherent(&instance->pdev->dev,
+                                       pd_seq_map_sz,
+                                       fusion->pd_seq_sync[i],
+                                       fusion->pd_seq_phys[i]);
                }
                free_pages((ulong)instance->ctrl_context,
                        instance->ctrl_context_pages);
@@ -6443,10 +6443,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
        }
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 
-       mutex_lock(&instance->aen_mutex);
+       mutex_lock(&instance->reset_mutex);
        error = megasas_register_aen(instance, aen.seq_num,
                                     aen.class_locale_word);
-       mutex_unlock(&instance->aen_mutex);
+       mutex_unlock(&instance->reset_mutex);
        return error;
 }
 
@@ -6477,9 +6477,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
        int i;
        int error = 0;
        compat_uptr_t ptr;
-       unsigned long local_raw_ptr;
        u32 local_sense_off;
        u32 local_sense_len;
+       u32 user_sense_off;
 
        if (clear_user(ioc, sizeof(*ioc)))
                return -EFAULT;
@@ -6497,17 +6497,16 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
         * sense_len is not null, so prepare the 64bit value under
         * the same condition.
         */
-       if (get_user(local_raw_ptr, ioc->frame.raw) ||
-               get_user(local_sense_off, &ioc->sense_off) ||
-               get_user(local_sense_len, &ioc->sense_len))
+       if (get_user(local_sense_off, &ioc->sense_off) ||
+               get_user(local_sense_len, &ioc->sense_len) ||
+               get_user(user_sense_off, &cioc->sense_off))
                return -EFAULT;
 
-
        if (local_sense_len) {
                void __user **sense_ioc_ptr =
-                       (void __user **)((u8*)local_raw_ptr + local_sense_off);
+                       (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
                compat_uptr_t *sense_cioc_ptr =
-                       (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+                       (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off);
                if (get_user(ptr, sense_cioc_ptr) ||
                    put_user(compat_ptr(ptr), sense_ioc_ptr))
                        return -EFAULT;
@@ -6648,6 +6647,7 @@ megasas_aen_polling(struct work_struct *work)
        int     i, j, doscan = 0;
        u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
        int error;
+       u8  dcmd_ret = 0;
 
        if (!instance) {
                printk(KERN_ERR "invalid instance!\n");
@@ -6660,16 +6660,7 @@ megasas_aen_polling(struct work_struct *work)
                wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
 
        /* Don't run the event workqueue thread if OCR is running */
-       for (i = 0; i < wait_time; i++) {
-               if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
-                       break;
-               if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
-                       dev_notice(&instance->pdev->dev, "%s waiting for "
-                              "controller reset to finish for scsi%d\n",
-                              __func__, instance->host->host_no);
-               }
-               msleep(1000);
-       }
+       mutex_lock(&instance->reset_mutex);
 
        instance->ev = NULL;
        host = instance->host;
@@ -6677,212 +6668,127 @@ megasas_aen_polling(struct work_struct *work)
                megasas_decode_evt(instance);
 
                switch (le32_to_cpu(instance->evt_detail->code)) {
-               case MR_EVT_PD_INSERTED:
-                       if (megasas_get_pd_list(instance) == 0) {
-                       for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-                               for (j = 0;
-                               j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                               j++) {
-
-                               pd_index =
-                               (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                               sdev1 = scsi_device_lookup(host, i, j, 0);
-
-                               if (instance->pd_list[pd_index].driveState
-                                               == MR_PD_STATE_SYSTEM) {
-                                       if (!sdev1)
-                                               scsi_add_device(host, i, j, 0);
-
-                                       if (sdev1)
-                                               scsi_device_put(sdev1);
-                                       }
-                               }
-                       }
-                       }
-                       doscan = 0;
-                       break;
 
+               case MR_EVT_PD_INSERTED:
                case MR_EVT_PD_REMOVED:
-                       if (megasas_get_pd_list(instance) == 0) {
-                       for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-                               for (j = 0;
-                               j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                               j++) {
-
-                               pd_index =
-                               (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                               sdev1 = scsi_device_lookup(host, i, j, 0);
-
-                               if (instance->pd_list[pd_index].driveState
-                                       == MR_PD_STATE_SYSTEM) {
-                                       if (sdev1)
-                                               scsi_device_put(sdev1);
-                               } else {
-                                       if (sdev1) {
-                                               scsi_remove_device(sdev1);
-                                               scsi_device_put(sdev1);
-                                       }
-                               }
-                               }
-                       }
-                       }
-                       doscan = 0;
+                       dcmd_ret = megasas_get_pd_list(instance);
+                       if (dcmd_ret == 0)
+                               doscan = SCAN_PD_CHANNEL;
                        break;
 
                case MR_EVT_LD_OFFLINE:
                case MR_EVT_CFG_CLEARED:
                case MR_EVT_LD_DELETED:
-                       if (!instance->requestorId ||
-                           megasas_get_ld_vf_affiliation(instance, 0)) {
-                               if (megasas_ld_list_query(instance,
-                                                         MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-                                       megasas_get_ld_list(instance);
-                               for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-                                       for (j = 0;
-                                            j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                                            j++) {
-
-                                               ld_index =
-                                                       (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                                               sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
-                                               if (instance->ld_ids[ld_index]
-                                                   != 0xff) {
-                                                       if (sdev1)
-                                                               scsi_device_put(sdev1);
-                                               } else {
-                                                       if (sdev1) {
-                                                               scsi_remove_device(sdev1);
-                                                               scsi_device_put(sdev1);
-                                                       }
-                                               }
-                                       }
-                               }
-                               doscan = 0;
-                       }
-                       break;
                case MR_EVT_LD_CREATED:
                        if (!instance->requestorId ||
-                           megasas_get_ld_vf_affiliation(instance, 0)) {
-                               if (megasas_ld_list_query(instance,
-                                                         MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-                                       megasas_get_ld_list(instance);
-                               for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-                                       for (j = 0;
-                                            j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                                            j++) {
-                                               ld_index =
-                                                       (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                                               sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-
-                                               if (instance->ld_ids[ld_index]
-                                                   != 0xff) {
-                                                       if (!sdev1)
-                                                               scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-                                               }
-                                               if (sdev1)
-                                                       scsi_device_put(sdev1);
-                                       }
-                               }
-                               doscan = 0;
-                       }
+                               (instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+                               dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+                       if (dcmd_ret == 0)
+                               doscan = SCAN_VD_CHANNEL;
+
                        break;
+
                case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
                case MR_EVT_FOREIGN_CFG_IMPORTED:
                case MR_EVT_LD_STATE_CHANGE:
-                       doscan = 1;
+                       dcmd_ret = megasas_get_pd_list(instance);
+
+                       if (dcmd_ret != 0)
+                               break;
+
+                       if (!instance->requestorId ||
+                               (instance->requestorId && megasas_get_ld_vf_affiliation(instance, 0)))
+                               dcmd_ret = megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST);
+
+                       if (dcmd_ret != 0)
+                               break;
+
+                       doscan = SCAN_VD_CHANNEL | SCAN_PD_CHANNEL;
+                       dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
+                               instance->host->host_no);
                        break;
+
                case MR_EVT_CTRL_PROP_CHANGED:
-                       megasas_get_ctrl_info(instance);
-                       break;
+                               dcmd_ret = megasas_get_ctrl_info(instance);
+                               break;
                default:
                        doscan = 0;
                        break;
                }
        } else {
                dev_err(&instance->pdev->dev, "invalid evt_detail!\n");
+               mutex_unlock(&instance->reset_mutex);
                kfree(ev);
                return;
        }
 
-       if (doscan) {
-               dev_info(&instance->pdev->dev, "scanning for scsi%d...\n",
-                      instance->host->host_no);
-               if (megasas_get_pd_list(instance) == 0) {
-                       for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
-                               for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
-                                       pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
-                                       sdev1 = scsi_device_lookup(host, i, j, 0);
-                                       if (instance->pd_list[pd_index].driveState ==
-                                           MR_PD_STATE_SYSTEM) {
-                                               if (!sdev1) {
-                                                       scsi_add_device(host, i, j, 0);
-                                               }
-                                               if (sdev1)
-                                                       scsi_device_put(sdev1);
-                                       } else {
-                                               if (sdev1) {
-                                                       scsi_remove_device(sdev1);
-                                                       scsi_device_put(sdev1);
-                                               }
+       mutex_unlock(&instance->reset_mutex);
+
+       if (doscan & SCAN_PD_CHANNEL) {
+               for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+                       for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+                               pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+                               sdev1 = scsi_device_lookup(host, i, j, 0);
+                               if (instance->pd_list[pd_index].driveState ==
+                                                       MR_PD_STATE_SYSTEM) {
+                                       if (!sdev1)
+                                               scsi_add_device(host, i, j, 0);
+                                       else
+                                               scsi_device_put(sdev1);
+                               } else {
+                                       if (sdev1) {
+                                               scsi_remove_device(sdev1);
+                                               scsi_device_put(sdev1);
                                        }
                                }
                        }
                }
+       }
 
-               if (!instance->requestorId ||
-                   megasas_get_ld_vf_affiliation(instance, 0)) {
-                       if (megasas_ld_list_query(instance,
-                                                 MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-                               megasas_get_ld_list(instance);
-                       for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-                               for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                                    j++) {
-                                       ld_index =
-                                               (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                                       sdev1 = scsi_device_lookup(host,
-                                                                  MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-                                       if (instance->ld_ids[ld_index]
-                                           != 0xff) {
-                                               if (!sdev1)
-                                                       scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-                                               else
-                                                       scsi_device_put(sdev1);
-                                       } else {
-                                               if (sdev1) {
-                                                       scsi_remove_device(sdev1);
-                                                       scsi_device_put(sdev1);
-                                               }
+       if (doscan & SCAN_VD_CHANNEL) {
+               for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+                       for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+                               ld_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+                               sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+                               if (instance->ld_ids[ld_index] != 0xff) {
+                                       if (!sdev1)
+                                               scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+                                       else
+                                               scsi_device_put(sdev1);
+                               } else {
+                                       if (sdev1) {
+                                               scsi_remove_device(sdev1);
+                                               scsi_device_put(sdev1);
                                        }
                                }
                        }
                }
        }
 
-       if (instance->aen_cmd != NULL) {
-               kfree(ev);
-               return ;
-       }
-
-       seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+       if (dcmd_ret == 0)
+               seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
+       else
+               seq_num = instance->last_seq_num;
 
        /* Register AEN with FW for latest sequence number plus 1 */
        class_locale.members.reserved = 0;
        class_locale.members.locale = MR_EVT_LOCALE_ALL;
        class_locale.members.class = MR_EVT_CLASS_DEBUG;
-       mutex_lock(&instance->aen_mutex);
+
+       if (instance->aen_cmd != NULL) {
+               kfree(ev);
+               return;
+       }
+
+       mutex_lock(&instance->reset_mutex);
        error = megasas_register_aen(instance, seq_num,
                                        class_locale.word);
-       mutex_unlock(&instance->aen_mutex);
-
        if (error)
-               dev_err(&instance->pdev->dev, "register aen failed error %x\n", error);
+               dev_err(&instance->pdev->dev,
+                       "register aen failed error %x\n", error);
 
+       mutex_unlock(&instance->reset_mutex);
        kfree(ev);
 }
 
index 8d630a552b078721c5c5eea640995046a9907565..021b994fdae8d08e95df2dac143125131aca32ff 100644 (file)
@@ -201,6 +201,7 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
                &instance->reg_set->inbound_low_queue_port);
        writel(le32_to_cpu(req_desc->u.high),
                &instance->reg_set->inbound_high_queue_port);
+       mmiowb();
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 #endif
 }
@@ -2437,7 +2438,7 @@ megasas_release_fusion(struct megasas_instance *instance)
 
        iounmap(instance->reg_set);
 
-       pci_release_selected_regions(instance->pdev, instance->bar);
+       pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 }
 
 /**
index 11393ebf1a68ef8f14a38d58f1321d7783a84d72..5b2c37f1e9080ab4c2dea4f919f13faf0d44b8f6 100644 (file)
@@ -2020,8 +2020,10 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
        _base_free_irq(ioc);
        _base_disable_msix(ioc);
 
-       if (ioc->msix96_vector)
+       if (ioc->msix96_vector) {
                kfree(ioc->replyPostRegisterIndex);
+               ioc->replyPostRegisterIndex = NULL;
+       }
 
        if (ioc->chip_phys) {
                iounmap(ioc->chip);
@@ -2155,6 +2157,17 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
        } else
                ioc->msix96_vector = 0;
 
+       if (ioc->is_warpdrive) {
+               ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
+                   &ioc->chip->ReplyPostHostIndex;
+
+               for (i = 1; i < ioc->cpu_msix_table_sz; i++)
+                       ioc->reply_post_host_index[i] =
+                       (resource_size_t __iomem *)
+                       ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
+                       * 4)));
+       }
+
        list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
                pr_info(MPT3SAS_FMT "%s: IRQ %d\n",
                    reply_q->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
@@ -2229,6 +2242,12 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
        return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
 }
 
+static inline u8
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+{
+       return ioc->cpu_msix_table[raw_smp_processor_id()];
+}
+
 /**
  * mpt3sas_base_get_smid - obtain a free smid from internal queue
  * @ioc: per adapter object
@@ -2289,6 +2308,7 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
        request->scmd = scmd;
        request->cb_idx = cb_idx;
        smid = request->smid;
+       request->msix_io = _base_get_msix_index(ioc);
        list_del(&request->tracker_list);
        spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
        return smid;
@@ -2411,12 +2431,6 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
 }
 #endif
 
-static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
-{
-       return ioc->cpu_msix_table[raw_smp_processor_id()];
-}
-
 /**
  * mpt3sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
  * @ioc: per adapter object
@@ -2470,18 +2484,19 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
  * mpt3sas_base_put_smid_hi_priority - send Task Managment request to firmware
  * @ioc: per adapter object
  * @smid: system request message index
- *
+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
  * Return nothing.
  */
 void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+       u16 msix_task)
 {
        Mpi2RequestDescriptorUnion_t descriptor;
        u64 *request = (u64 *)&descriptor;
 
        descriptor.HighPriority.RequestFlags =
            MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
-       descriptor.HighPriority.MSIxIndex =  0;
+       descriptor.HighPriority.MSIxIndex =  msix_task;
        descriptor.HighPriority.SMID = cpu_to_le16(smid);
        descriptor.HighPriority.LMID = 0;
        descriptor.HighPriority.Reserved1 = 0;
@@ -5201,17 +5216,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
        if (r)
                goto out_free_resources;
 
-       if (ioc->is_warpdrive) {
-               ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
-                   &ioc->chip->ReplyPostHostIndex;
-
-               for (i = 1; i < ioc->cpu_msix_table_sz; i++)
-                       ioc->reply_post_host_index[i] =
-                       (resource_size_t __iomem *)
-                       ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
-                       * 4)));
-       }
-
        pci_set_drvdata(ioc->pdev, ioc->shost);
        r = _base_get_ioc_facts(ioc, CAN_SLEEP);
        if (r)
index 5ad271efbd45e760eabd72d8218bd6cefc6a0e23..92648a5ea2d202f715759e2eeea0e252ba3929fd 100644 (file)
@@ -643,6 +643,7 @@ struct chain_tracker {
  * @cb_idx: callback index
  * @direct_io: To indicate whether I/O is direct (WARPDRIVE)
  * @tracker_list: list of free request (ioc->free_list)
+ * @msix_io: IO's msix
  */
 struct scsiio_tracker {
        u16     smid;
@@ -651,6 +652,7 @@ struct scsiio_tracker {
        u8      direct_io;
        struct list_head chain_list;
        struct list_head tracker_list;
+       u16     msix_io;
 };
 
 /**
@@ -1213,7 +1215,8 @@ void mpt3sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid,
        u16 handle);
 void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
        u16 handle);
-void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc,
+       u16 smid, u16 msix_task);
 void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 void mpt3sas_base_initialize_callback_handler(void);
 u8 mpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func);
index d8366b056b70f48c046b1fcb06637f70174914ee..4ccde5a05b7010cfef1f0b8f27124d45c49c4844 100644 (file)
@@ -817,7 +817,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                    tm_request->DevHandle));
                ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
                    data_in_dma, data_in_sz);
-               mpt3sas_base_put_smid_hi_priority(ioc, smid);
+               mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
                break;
        }
        case MPI2_FUNCTION_SMP_PASSTHROUGH:
index 9ab77b06434d19a61a92bb771aef0e70da0f31d8..0969cea1089aaf58ac623a85c3b82962793b965b 100644 (file)
@@ -2193,6 +2193,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
        unsigned long timeleft;
        struct scsiio_tracker *scsi_lookup = NULL;
        int rc;
+       u16 msix_task = 0;
 
        if (m_type == TM_MUTEX_ON)
                mutex_lock(&ioc->tm_cmds.mutex);
@@ -2256,7 +2257,12 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel,
        int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
        mpt3sas_scsih_set_tm_flag(ioc, handle);
        init_completion(&ioc->tm_cmds.done);
-       mpt3sas_base_put_smid_hi_priority(ioc, smid);
+       if ((type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) &&
+                       (scsi_lookup->msix_io < ioc->reply_queue_count))
+               msix_task = scsi_lookup->msix_io;
+       else
+               msix_task = 0;
+       mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
        timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
        if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
                pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -3151,7 +3157,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
        mpi_request->DevHandle = cpu_to_le16(handle);
        mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-       mpt3sas_base_put_smid_hi_priority(ioc, smid);
+       mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
        mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
 
 out:
@@ -3332,7 +3338,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
        mpi_request->DevHandle = cpu_to_le16(handle);
        mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-       mpt3sas_base_put_smid_hi_priority(ioc, smid);
+       mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 }
 
 /**
@@ -4504,7 +4510,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
                            le16_to_cpu(mpi_reply->DevHandle));
                mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq);
 
-               if (!(ioc->logging_level & MPT_DEBUG_REPLY) &&
+               if ((ioc->logging_level & MPT_DEBUG_REPLY) &&
                     ((scmd->sense_buffer[2] == UNIT_ATTENTION) ||
                     (scmd->sense_buffer[2] == MEDIUM_ERROR) ||
                     (scmd->sense_buffer[2] == HARDWARE_ERROR)))
index 75514a15bea03ebcf8929ff317f97aeb17b59ae5..f57d96984ae446029de39406d921f37f417d9f20 100644 (file)
@@ -1578,7 +1578,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
                qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy,
                    0, 0, 0, 0, 0, 0);
        else {
-               if (mcmd->se_cmd.se_tmr_req->function == TMR_ABORT_TASK)
+               if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
                        qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts,
                            mcmd->fc_tm_rsp, false);
                else
index 93cbefa75b26dbe91dd8e6a0d428e52f1b1061ce..11cdb172cfafd82c0ed3006f43da20cbd3b57d89 100644 (file)
@@ -426,7 +426,7 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
         * here, and we don't know what device it is
         * trying to work with, leave it as-is.
         */
-       vmax = 8;       /* max length of vendor */
+       vmax = sizeof(devinfo->vendor);
        vskip = vendor;
        while (vmax > 0 && *vskip == ' ') {
                vmax--;
@@ -436,7 +436,7 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
        while (vmax > 0 && vskip[vmax - 1] == ' ')
                --vmax;
 
-       mmax = 16;      /* max length of model */
+       mmax = sizeof(devinfo->model);
        mskip = model;
        while (mmax > 0 && *mskip == ' ') {
                mmax--;
@@ -452,10 +452,12 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
                         * Behave like the older version of get_device_flags.
                         */
                        if (memcmp(devinfo->vendor, vskip, vmax) ||
-                                       devinfo->vendor[vmax])
+                                       (vmax < sizeof(devinfo->vendor) &&
+                                               devinfo->vendor[vmax]))
                                continue;
                        if (memcmp(devinfo->model, mskip, mmax) ||
-                                       devinfo->model[mmax])
+                                       (mmax < sizeof(devinfo->model) &&
+                                               devinfo->model[mmax]))
                                continue;
                        return devinfo;
                } else {
index f0cfaacbfabd74df9f71c0d342f5f1fb50330016..692445bcca6fec4f9c2cbb71d112fe4c531f4c52 100644 (file)
@@ -1459,12 +1459,12 @@ retry:
  out_err:
        kfree(lun_data);
  out:
-       scsi_device_put(sdev);
        if (scsi_device_created(sdev))
                /*
                 * the sdev we used didn't appear in the report luns scan
                 */
                __scsi_remove_device(sdev);
+       scsi_device_put(sdev);
        return ret;
 }
 
index f7ae898833dd9941e80d4d5acb4b505396f5c329..7232d43e2207d36c0b8368c7c880352e82abe60e 100644 (file)
@@ -1058,11 +1058,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
        }
 
        error = scsi_dh_add_device(sdev);
-       if (error) {
+       if (error)
+               /*
+                * device_handler is optional, so any error can be ignored
+                */
                sdev_printk(KERN_INFO, sdev,
                                "failed to add device handler: %d\n", error);
-               return error;
-       }
 
        device_enable_async_suspend(&sdev->sdev_dev);
        error = device_add(&sdev->sdev_dev);
index 0d7c6e86f1492ebcce95d257f358969128db8154..6ee50742f6a5203fffd68aa06a04196f88ab4e7e 100644 (file)
@@ -2879,10 +2879,10 @@ static int sd_revalidate_disk(struct gendisk *disk)
        if (sdkp->opt_xfer_blocks &&
            sdkp->opt_xfer_blocks <= dev_max &&
            sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
-           sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE)
-               rw_max = q->limits.io_opt =
-                       sdkp->opt_xfer_blocks * sdp->sector_size;
-       else
+           logical_to_bytes(sdp, sdkp->opt_xfer_blocks) >= PAGE_CACHE_SIZE) {
+               q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
+               rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
+       else
                rw_max = BLK_DEF_MAX_SECTORS;
 
        /* Combine with controller limits */
index 654630bb7d0edeb48438654e47d8a60151d2c87b..765a6f1ac1b7320edc860b1eb6baa30e7e1beac4 100644 (file)
@@ -151,6 +151,11 @@ static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blo
        return blocks << (ilog2(sdev->sector_size) - 9);
 }
 
+static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t blocks)
+{
+       return blocks * sdev->sector_size;
+}
+
 /*
  * A DIF-capable target device can be formatted with different
  * protection schemes.  Currently 0 through 3 are defined:
index 85cd2564c15773f728e8bd6ae6fcde28867ab2bb..4167bdbf0ecf29a4e275824bf3aa36378845586a 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <linux/async.h>
 #include <linux/devfreq.h>
+#include <linux/blkdev.h>
 
 #include "ufshcd.h"
 #include "unipro.h"
@@ -1332,6 +1333,17 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                clear_bit_unlock(tag, &hba->lrb_in_use);
                goto out;
        }
+
+       /* IO svc time latency histogram */
+       if (hba != NULL && cmd->request != NULL) {
+               if (hba->latency_hist_enabled &&
+                   (cmd->request->cmd_type == REQ_TYPE_FS)) {
+                       cmd->request->lat_hist_io_start = ktime_get();
+                       cmd->request->lat_hist_enabled = 1;
+               } else
+                       cmd->request->lat_hist_enabled = 0;
+       }
+
        WARN_ON(hba->clk_gating.state != CLKS_ON);
 
        lrbp = &hba->lrb[tag];
@@ -3160,6 +3172,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
        u32 tr_doorbell;
        int result;
        int index;
+       struct request *req;
 
        /* Resetting interrupt aggregation counters first and reading the
         * DOOR_BELL afterward allows us to handle all the completed requests.
@@ -3184,6 +3197,22 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
                        /* Mark completed command as NULL in LRB */
                        lrbp->cmd = NULL;
                        clear_bit_unlock(index, &hba->lrb_in_use);
+                       req = cmd->request;
+                       if (req) {
+                               /* Update IO svc time latency histogram */
+                               if (req->lat_hist_enabled) {
+                                       ktime_t completion;
+                                       u_int64_t delta_us;
+
+                                       completion = ktime_get();
+                                       delta_us = ktime_us_delta(completion,
+                                                 req->lat_hist_io_start);
+                                       /* rq_data_dir() => true if WRITE */
+                                       blk_update_latency_hist(&hba->io_lat_s,
+                                               (rq_data_dir(req) == READ),
+                                               delta_us);
+                               }
+                       }
                        /* Do not touch lrbp after scsi done */
                        cmd->scsi_done(cmd);
                        __ufshcd_release(hba);
@@ -5327,6 +5356,54 @@ out:
 }
 EXPORT_SYMBOL(ufshcd_shutdown);
 
+/*
+ * Values permitted 0, 1, 2.
+ * 0 -> Disable IO latency histograms (default)
+ * 1 -> Enable IO latency histograms
+ * 2 -> Zero out IO latency histograms
+ */
+static ssize_t
+latency_hist_store(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       long value;
+
+       if (kstrtol(buf, 0, &value))
+               return -EINVAL;
+       if (value == BLK_IO_LAT_HIST_ZERO)
+               blk_zero_latency_hist(&hba->io_lat_s);
+       else if (value == BLK_IO_LAT_HIST_ENABLE ||
+                value == BLK_IO_LAT_HIST_DISABLE)
+               hba->latency_hist_enabled = value;
+       return count;
+}
+
+ssize_t
+latency_hist_show(struct device *dev, struct device_attribute *attr,
+                 char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return blk_latency_hist_show(&hba->io_lat_s, buf);
+}
+
+static DEVICE_ATTR(latency_hist, S_IRUGO | S_IWUSR,
+                  latency_hist_show, latency_hist_store);
+
+static void
+ufshcd_init_latency_hist(struct ufs_hba *hba)
+{
+       if (device_create_file(hba->dev, &dev_attr_latency_hist))
+               dev_err(hba->dev, "Failed to create latency_hist sysfs entry\n");
+}
+
+static void
+ufshcd_exit_latency_hist(struct ufs_hba *hba)
+{
+       device_create_file(hba->dev, &dev_attr_latency_hist);
+}
+
 /**
  * ufshcd_remove - de-allocate SCSI host and host memory space
  *             data structure memory
@@ -5342,6 +5419,7 @@ void ufshcd_remove(struct ufs_hba *hba)
        scsi_host_put(hba->host);
 
        ufshcd_exit_clk_gating(hba);
+       ufshcd_exit_latency_hist(hba);
        if (ufshcd_is_clkscaling_enabled(hba))
                devfreq_remove_device(hba->devfreq);
        ufshcd_hba_exit(hba);
@@ -5639,6 +5717,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        /* Hold auto suspend until async scan completes */
        pm_runtime_get_sync(dev);
 
+       ufshcd_init_latency_hist(hba);
+
        /*
         * The device-initialize-sequence hasn't been invoked yet.
         * Set the device to power-off state
@@ -5653,6 +5733,7 @@ out_remove_scsi_host:
        scsi_remove_host(hba->host);
 exit_gating:
        ufshcd_exit_clk_gating(hba);
+       ufshcd_exit_latency_hist(hba);
 out_disable:
        hba->is_irq_enabled = false;
        scsi_host_put(host);
index 2570d9477b3778c9505e616f72c22e0b30fad8be..f3780cf7d89520528efdfbab4561a27b1fde1a1d 100644 (file)
@@ -532,6 +532,9 @@ struct ufs_hba {
        struct devfreq *devfreq;
        struct ufs_clk_scaling clk_scaling;
        bool is_sys_suspended;
+
+       int                     latency_hist_enabled;
+       struct io_latency_state io_lat_s;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
index b04b05a0904eec086c49250c3dc4e27cb84a3927..65bce1eecaf868ddd60cca8324920f5d5fa57802 100644 (file)
@@ -288,7 +288,7 @@ static struct spm_driver_data *spm_get_drv(struct platform_device *pdev,
        struct spm_driver_data *drv = NULL;
        struct device_node *cpu_node, *saw_node;
        int cpu;
-       bool found;
+       bool found = 0;
 
        for_each_possible_cpu(cpu) {
                cpu_node = of_cpu_device_node_get(cpu);
index 39412c9097c6a240466c51c941ec890a4612542e..a3965cac1b3447ce6cf6c715e46269bbc301508f 100644 (file)
@@ -753,7 +753,6 @@ static int dspi_remove(struct platform_device *pdev)
        /* Disconnect from the SPI framework */
        clk_disable_unprepare(dspi->clk);
        spi_unregister_master(dspi->master);
-       spi_master_put(dspi->master);
 
        return 0;
 }
index 73c8ea0b136094b443c713ff4034f2b90dbaf115..3cac73e4c3e4ab4ee442ce219fefc2a9c12f02c6 100644 (file)
@@ -548,7 +548,14 @@ static void reset_sccr1(struct driver_data *drv_data)
        u32 sccr1_reg;
 
        sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1;
-       sccr1_reg &= ~SSCR1_RFT;
+       switch (drv_data->ssp_type) {
+       case QUARK_X1000_SSP:
+               sccr1_reg &= ~QUARK_X1000_SSCR1_RFT;
+               break;
+       default:
+               sccr1_reg &= ~SSCR1_RFT;
+               break;
+       }
        sccr1_reg |= chip->threshold;
        pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
 }
index a7934ab00b96505f3753fa38266238f3abcc6f64..d22de4c8c3995c87328f37fd140041833514a8bb 100644 (file)
@@ -263,6 +263,9 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
 
        for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) {
                brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div);
+               /* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */
+               if (sh_msiof_spi_div_table[k].div == 1 && brps > 2)
+                       continue;
                if (brps <= 32) /* max of brdv is 32 */
                        break;
        }
index fbb0a4d74e91c6716d6adc87c8c9bbae91487ed5..39d7c7c7011217f7cd415cbd6ee03e9f763370e5 100644 (file)
@@ -170,13 +170,17 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
 {
        struct sun4i_spi *sspi = spi_master_get_devdata(master);
        unsigned int mclk_rate, div, timeout;
+       unsigned int start, end, tx_time;
        unsigned int tx_len = 0;
        int ret = 0;
        u32 reg;
 
        /* We don't support transfer larger than the FIFO */
        if (tfr->len > SUN4I_FIFO_DEPTH)
-               return -EINVAL;
+               return -EMSGSIZE;
+
+       if (tfr->tx_buf && tfr->len >= SUN4I_FIFO_DEPTH)
+               return -EMSGSIZE;
 
        reinit_completion(&sspi->done);
        sspi->tx_buf = tfr->tx_buf;
@@ -269,8 +273,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
        sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
        sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
 
-       /* Fill the TX FIFO */
-       sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+       /*
+        * Fill the TX FIFO
+        * Filling the FIFO fully causes timeout for some reason
+        * at least on spi2 on A10s
+        */
+       sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
 
        /* Enable the interrupts */
        sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
@@ -279,9 +287,16 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
        reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
        sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
 
+       tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+       start = jiffies;
        timeout = wait_for_completion_timeout(&sspi->done,
-                                             msecs_to_jiffies(1000));
+                                             msecs_to_jiffies(tx_time));
+       end = jiffies;
        if (!timeout) {
+               dev_warn(&master->dev,
+                        "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+                        dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+                        jiffies_to_msecs(end - start), tx_time);
                ret = -ETIMEDOUT;
                goto out;
        }
index ac48f59705a87f3a5c48c22c896d4e2c04b03b50..e77add01b0e90abb2d30f78037d4935c4962e7d3 100644 (file)
@@ -160,6 +160,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 {
        struct sun6i_spi *sspi = spi_master_get_devdata(master);
        unsigned int mclk_rate, div, timeout;
+       unsigned int start, end, tx_time;
        unsigned int tx_len = 0;
        int ret = 0;
        u32 reg;
@@ -269,9 +270,16 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
        reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
        sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
 
+       tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+       start = jiffies;
        timeout = wait_for_completion_timeout(&sspi->done,
-                                             msecs_to_jiffies(1000));
+                                             msecs_to_jiffies(tx_time));
+       end = jiffies;
        if (!timeout) {
+               dev_warn(&master->dev,
+                        "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+                        dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+                        jiffies_to_msecs(end - start), tx_time);
                ret = -ETIMEDOUT;
                goto out;
        }
index c4fdafbce8883f2f7afad9e64917e51c01e9259a..5952c2b3cf5078f8ea0febcaa51d7fce995df083 100644 (file)
@@ -394,13 +394,22 @@ void ion_handle_get(struct ion_handle *handle)
        kref_get(&handle->ref);
 }
 
+static int ion_handle_put_nolock(struct ion_handle *handle)
+{
+       int ret;
+
+       ret = kref_put(&handle->ref, ion_handle_destroy);
+
+       return ret;
+}
+
 int ion_handle_put(struct ion_handle *handle)
 {
        struct ion_client *client = handle->client;
        int ret;
 
        mutex_lock(&client->lock);
-       ret = kref_put(&handle->ref, ion_handle_destroy);
+       ret = ion_handle_put_nolock(handle);
        mutex_unlock(&client->lock);
 
        return ret;
@@ -424,20 +433,30 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
        return ERR_PTR(-EINVAL);
 }
 
-struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
-                                       int id)
+static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
+                                               int id)
 {
        struct ion_handle *handle;
 
-       mutex_lock(&client->lock);
        handle = idr_find(&client->idr, id);
        if (handle)
                ion_handle_get(handle);
-       mutex_unlock(&client->lock);
 
        return handle ? handle : ERR_PTR(-EINVAL);
 }
 
+struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
+                                               int id)
+{
+       struct ion_handle *handle;
+
+       mutex_lock(&client->lock);
+       handle = ion_handle_get_by_id_nolock(client, id);
+       mutex_unlock(&client->lock);
+
+       return handle;
+}
+
 static bool ion_handle_validate(struct ion_client *client,
                                struct ion_handle *handle)
 {
@@ -539,22 +558,28 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
 }
 EXPORT_SYMBOL(ion_alloc);
 
-void ion_free(struct ion_client *client, struct ion_handle *handle)
+static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle)
 {
        bool valid_handle;
 
        BUG_ON(client != handle->client);
 
-       mutex_lock(&client->lock);
        valid_handle = ion_handle_validate(client, handle);
 
        if (!valid_handle) {
                WARN(1, "%s: invalid handle passed to free.\n", __func__);
-               mutex_unlock(&client->lock);
                return;
        }
+       ion_handle_put_nolock(handle);
+}
+
+void ion_free(struct ion_client *client, struct ion_handle *handle)
+{
+       BUG_ON(client != handle->client);
+
+       mutex_lock(&client->lock);
+       ion_free_nolock(client, handle);
        mutex_unlock(&client->lock);
-       ion_handle_put(handle);
 }
 EXPORT_SYMBOL(ion_free);
 
@@ -1552,11 +1577,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        {
                struct ion_handle *handle;
 
-               handle = ion_handle_get_by_id(client, data.handle.handle);
-               if (IS_ERR(handle))
+               mutex_lock(&client->lock);
+               handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
+               if (IS_ERR(handle)) {
+                       mutex_unlock(&client->lock);
                        return PTR_ERR(handle);
-               ion_free(client, handle);
-               ion_handle_put(handle);
+               }
+               ion_free_nolock(client, handle);
+               ion_handle_put_nolock(handle);
+               mutex_unlock(&client->lock);
                break;
        }
        case ION_IOC_SHARE:
index 4ab186669f0c27d503a3e33b6e3bdd5fb0e12c7d..ec5b9a23494d4b28538f29e2efddcb199485c502 100644 (file)
 
 #define N_CHANS 8
 
-enum waveform_state_bits {
-       WAVEFORM_AI_RUNNING,
-       WAVEFORM_AO_RUNNING
-};
-
 /* Data unique to this driver */
 struct waveform_private {
        struct timer_list ai_timer;     /* timer for AI commands */
@@ -68,7 +63,6 @@ struct waveform_private {
        unsigned int wf_amplitude;      /* waveform amplitude in microvolts */
        unsigned int wf_period;         /* waveform period in microseconds */
        unsigned int wf_current;        /* current time in waveform period */
-       unsigned long state_bits;
        unsigned int ai_scan_period;    /* AI scan period in usec */
        unsigned int ai_convert_period; /* AI conversion period in usec */
        struct timer_list ao_timer;     /* timer for AO commands */
@@ -191,10 +185,6 @@ static void waveform_ai_timer(unsigned long arg)
        unsigned int nsamples;
        unsigned int time_increment;
 
-       /* check command is still active */
-       if (!test_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits))
-               return;
-
        now = ktime_to_us(ktime_get());
        nsamples = comedi_nsamples_left(s, UINT_MAX);
 
@@ -386,11 +376,6 @@ static int waveform_ai_cmd(struct comedi_device *dev,
         */
        devpriv->ai_timer.expires =
                jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1;
-
-       /* mark command as active */
-       smp_mb__before_atomic();
-       set_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits);
-       smp_mb__after_atomic();
        add_timer(&devpriv->ai_timer);
        return 0;
 }
@@ -400,11 +385,12 @@ static int waveform_ai_cancel(struct comedi_device *dev,
 {
        struct waveform_private *devpriv = dev->private;
 
-       /* mark command as no longer active */
-       clear_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits);
-       smp_mb__after_atomic();
-       /* cannot call del_timer_sync() as may be called from timer routine */
-       del_timer(&devpriv->ai_timer);
+       if (in_softirq()) {
+               /* Assume we were called from the timer routine itself. */
+               del_timer(&devpriv->ai_timer);
+       } else {
+               del_timer_sync(&devpriv->ai_timer);
+       }
        return 0;
 }
 
@@ -436,10 +422,6 @@ static void waveform_ao_timer(unsigned long arg)
        u64 scans_since;
        unsigned int scans_avail = 0;
 
-       /* check command is still active */
-       if (!test_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits))
-               return;
-
        /* determine number of scan periods since last time */
        now = ktime_to_us(ktime_get());
        scans_since = now - devpriv->ao_last_scan_time;
@@ -518,11 +500,6 @@ static int waveform_ao_inttrig_start(struct comedi_device *dev,
        devpriv->ao_last_scan_time = ktime_to_us(ktime_get());
        devpriv->ao_timer.expires =
                jiffies + usecs_to_jiffies(devpriv->ao_scan_period);
-
-       /* mark command as active */
-       smp_mb__before_atomic();
-       set_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits);
-       smp_mb__after_atomic();
        add_timer(&devpriv->ao_timer);
 
        return 1;
@@ -608,11 +585,12 @@ static int waveform_ao_cancel(struct comedi_device *dev,
        struct waveform_private *devpriv = dev->private;
 
        s->async->inttrig = NULL;
-       /* mark command as no longer active */
-       clear_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits);
-       smp_mb__after_atomic();
-       /* cannot call del_timer_sync() as may be called from timer routine */
-       del_timer(&devpriv->ao_timer);
+       if (in_softirq()) {
+               /* Assume we were called from the timer routine itself. */
+               del_timer(&devpriv->ao_timer);
+       } else {
+               del_timer_sync(&devpriv->ao_timer);
+       }
        return 0;
 }
 
index 57ab6680e3aed4c1375820b652ca0938470adcc5..e5fee6e0fb479cc38b66f17912b39ec2cbe861c6 100644 (file)
@@ -636,7 +636,7 @@ static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
        const struct daq200_boardtype *board;
        int i;
 
-       if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
+       if (pcidev->subsystem_vendor != PCI_VENDOR_ID_IOTECH)
                return NULL;
 
        for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
index 27fbf1a810975e86faa7819f06ff717ae842d957..35ab4a9ef95d62f02c4058eadaf27d87ebe85ee7 100644 (file)
@@ -2823,7 +2823,15 @@ static int ni_ao_inttrig(struct comedi_device *dev,
        int i;
        static const int timeout = 1000;
 
-       if (trig_num != cmd->start_arg)
+       /*
+        * Require trig_num == cmd->start_arg when cmd->start_src == TRIG_INT.
+        * For backwards compatibility, also allow trig_num == 0 when
+        * cmd->start_src != TRIG_INT (i.e. when cmd->start_src == TRIG_EXT);
+        * in that case, the internal trigger is being used as a pre-trigger
+        * before the external trigger.
+        */
+       if (!(trig_num == cmd->start_arg ||
+             (trig_num == 0 && cmd->start_src != TRIG_INT)))
                return -EINVAL;
 
        /* Null trig at beginning prevent ao start trigger from executing more than
@@ -5346,7 +5354,7 @@ static int ni_E_init(struct comedi_device *dev,
                s->maxdata      = (devpriv->is_m_series) ? 0xffffffff
                                                         : 0x00ffffff;
                s->insn_read    = ni_tio_insn_read;
-               s->insn_write   = ni_tio_insn_read;
+               s->insn_write   = ni_tio_insn_write;
                s->insn_config  = ni_tio_insn_config;
 #ifdef PCIDMA
                if (dev->irq && devpriv->mite) {
index b1e45161eefcf45cf04e65c1bdab3d2aa52dcf0c..18c2b6daf58857e1d1f34462d5e95a4e5e1d1178 100644 (file)
@@ -392,11 +392,11 @@ static void fbtft_update_display(struct fbtft_par *par, unsigned start_line,
 
        if (unlikely(timeit)) {
                ts_end = ktime_get();
-               if (ktime_to_ns(par->update_time))
+               if (!ktime_to_ns(par->update_time))
                        par->update_time = ts_start;
 
-               par->update_time = ts_start;
                fps = ktime_us_delta(ts_start, par->update_time);
+               par->update_time = ts_start;
                fps = fps ? 1000000 / fps : 0;
 
                throughput = ktime_us_delta(ts_end, ts_start);
index bb40f37287426c4855a70b0b19b124802a52c284..20314ff08be09b9cb4783d754d497bc36f5cda5b 100644 (file)
@@ -236,7 +236,7 @@ static int ad7192_setup(struct ad7192_state *st,
                        st->mclk = pdata->ext_clk_hz;
                else
                        st->mclk = AD7192_INT_FREQ_MHZ;
-                       break;
+               break;
        default:
                ret = -EINVAL;
                goto out;
index 9096d311e45d76baa411fb53b0d331685f304972..c2d9b793759d0c7c2a49000ea8289e101547608c 100644 (file)
@@ -631,8 +631,6 @@ struct ll_file_data {
 
 struct lov_stripe_md;
 
-extern spinlock_t inode_lock;
-
 extern struct dentry *llite_root;
 extern struct kset *llite_kset;
 
index 13c3cd11ab92a5c610ef7a5e32795a0b0a0931c9..05d30f433b19439b335f0d4bfd37a6760373055a 100644 (file)
@@ -45,6 +45,8 @@
 #include <linux/uio.h>
 #include <asm/pgtable.h>
 
+#include <rdma/ib.h>
+
 #include "ipath_kernel.h"
 #include "ipath_common.h"
 #include "ipath_user_sdma.h"
@@ -2243,6 +2245,9 @@ static ssize_t ipath_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 9b7026e7d55b654cf3861a10d0420341eb7846f1..45d0a87f55d233cca40ed653c80fb04f2477e43b 100644 (file)
@@ -718,13 +718,13 @@ u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
        u8      res = _SUCCESS;
 
 
-       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
        if (ph2c == NULL) {
                res = _FAIL;
                goto exit;
        }
 
-       paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_KERNEL);
+       paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC);
        if (paddbareq_parm == NULL) {
                kfree(ph2c);
                res = _FAIL;
index 72204fbf2bb13be5cdb7211ca6001b58f0c4fbc6..bd810c1092777418cf3374db4fa58cc3a0baece0 100644 (file)
@@ -492,7 +492,8 @@ static void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
        bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
 
        spin_lock_bh(&conn->cmd_lock);
-       if (!list_empty(&cmd->i_conn_node))
+       if (!list_empty(&cmd->i_conn_node) &&
+           !(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
                list_del_init(&cmd->i_conn_node);
        spin_unlock_bh(&conn->cmd_lock);
 
@@ -4194,6 +4195,7 @@ transport_err:
 
 static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
 {
+       LIST_HEAD(tmp_list);
        struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
        struct iscsi_session *sess = conn->sess;
        /*
@@ -4202,18 +4204,26 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
         * has been reset -> returned sleeping pre-handler state.
         */
        spin_lock_bh(&conn->cmd_lock);
-       list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
+       list_splice_init(&conn->conn_cmd_list, &tmp_list);
 
+       list_for_each_entry(cmd, &tmp_list, i_conn_node) {
+               struct se_cmd *se_cmd = &cmd->se_cmd;
+
+               if (se_cmd->se_tfo != NULL) {
+                       spin_lock(&se_cmd->t_state_lock);
+                       se_cmd->transport_state |= CMD_T_FABRIC_STOP;
+                       spin_unlock(&se_cmd->t_state_lock);
+               }
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+
+       list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
                list_del_init(&cmd->i_conn_node);
-               spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_increment_maxcmdsn(cmd, sess);
-
                iscsit_free_cmd(cmd, true);
 
-               spin_lock_bh(&conn->cmd_lock);
        }
-       spin_unlock_bh(&conn->cmd_lock);
 }
 
 static void iscsit_stop_timers_for_cmds(
index 96e78c823d13fa2f78feb6ff024fb468518be75b..316f661723350f0872cabdba7571d868b2e4d212 100644 (file)
@@ -1357,8 +1357,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        }
        login->zero_tsih = zero_tsih;
 
-       conn->sess->se_sess->sup_prot_ops =
-               conn->conn_transport->iscsit_get_sup_prot_ops(conn);
+       if (conn->sess)
+               conn->sess->se_sess->sup_prot_ops =
+                       conn->conn_transport->iscsit_get_sup_prot_ops(conn);
 
        tpg = conn->tpg;
        if (!tpg) {
index 3436a83568ea378c51b41f9fe04a2932756c84a7..dcd5ed26eb1829a0a42868c1357ec03ac9396441 100644 (file)
@@ -832,13 +832,15 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
  * in ATA and we need to set TPE=1
  */
 bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
-                                      struct request_queue *q, int block_size)
+                                      struct request_queue *q)
 {
+       int block_size = queue_logical_block_size(q);
+
        if (!blk_queue_discard(q))
                return false;
 
-       attrib->max_unmap_lba_count = (q->limits.max_discard_sectors << 9) /
-                                                               block_size;
+       attrib->max_unmap_lba_count =
+               q->limits.max_discard_sectors >> (ilog2(block_size) - 9);
        /*
         * Currently hardcoded to 1 in Linux/SCSI code..
         */
index 75f0f08b2a34f32d0b2bfdd35fa40f027e74ae75..79291869bce6c72d9eb4a72fa6d6f5614a104aa4 100644 (file)
@@ -161,8 +161,7 @@ static int fd_configure_device(struct se_device *dev)
                        dev_size, div_u64(dev_size, fd_dev->fd_block_size),
                        fd_dev->fd_block_size);
 
-               if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
-                                                     fd_dev->fd_block_size))
+               if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
                        pr_debug("IFILE: BLOCK Discard support available,"
                                 " disabled by default\n");
                /*
index 2c53dcefff3e1517fcd70936a9a6b887c1fc3c42..4620c1dcdbc7df46d02ff0b7eeb0ee2b36a46a3b 100644 (file)
@@ -121,8 +121,7 @@ static int iblock_configure_device(struct se_device *dev)
        dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
        dev->dev_attrib.hw_queue_depth = q->nr_requests;
 
-       if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
-                                             dev->dev_attrib.hw_block_size))
+       if (target_configure_unmap_from_queue(&dev->dev_attrib, q))
                pr_debug("IBLOCK: BLOCK Discard support available,"
                         " disabled by default\n");
 
index dae0750c2032bd87430ab99609d475a615e691db..253a91bff9439f48d9a1632c230006f9ac59cce5 100644 (file)
@@ -148,6 +148,7 @@ sense_reason_t      target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
 void   target_qf_do_work(struct work_struct *work);
 bool   target_check_wce(struct se_device *dev);
 bool   target_check_fua(struct se_device *dev);
+void   __target_execute_cmd(struct se_cmd *, bool);
 
 /* target_core_stat.c */
 void   target_stat_setup_dev_default_groups(struct se_device *);
index 98698d87574262226bcf893da2cb3d3849e6df32..c220bb8dfa9d5387b6f7609c56f81727677d4ced 100644 (file)
@@ -594,7 +594,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
        cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
        spin_unlock_irq(&cmd->t_state_lock);
 
-       __target_execute_cmd(cmd);
+       __target_execute_cmd(cmd, false);
 
        kfree(buf);
        return ret;
index d151bc3d6971b0204613e64cdb136ad98615d3dd..2a67af4e2e135bf7062c12cf26256e09bd203795 100644 (file)
@@ -1270,23 +1270,6 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
 
        trace_target_sequencer_start(cmd);
 
-       /*
-        * Check for an existing UNIT ATTENTION condition
-        */
-       ret = target_scsi3_ua_check(cmd);
-       if (ret)
-               return ret;
-
-       ret = target_alua_state_check(cmd);
-       if (ret)
-               return ret;
-
-       ret = target_check_reservation(cmd);
-       if (ret) {
-               cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
-               return ret;
-       }
-
        ret = dev->transport->parse_cdb(cmd);
        if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
                pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
@@ -1697,6 +1680,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
+       case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
                break;
        case TCM_OUT_OF_RESOURCES:
                sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -1749,20 +1733,45 @@ queue_full:
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-void __target_execute_cmd(struct se_cmd *cmd)
+void __target_execute_cmd(struct se_cmd *cmd, bool do_checks)
 {
        sense_reason_t ret;
 
-       if (cmd->execute_cmd) {
-               ret = cmd->execute_cmd(cmd);
-               if (ret) {
-                       spin_lock_irq(&cmd->t_state_lock);
-                       cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
-                       spin_unlock_irq(&cmd->t_state_lock);
+       if (!cmd->execute_cmd) {
+               ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               goto err;
+       }
+       if (do_checks) {
+               /*
+                * Check for an existing UNIT ATTENTION condition after
+                * target_handle_task_attr() has done SAM task attr
+                * checking, and possibly have already defered execution
+                * out to target_restart_delayed_cmds() context.
+                */
+               ret = target_scsi3_ua_check(cmd);
+               if (ret)
+                       goto err;
+
+               ret = target_alua_state_check(cmd);
+               if (ret)
+                       goto err;
 
-                       transport_generic_request_failure(cmd, ret);
+               ret = target_check_reservation(cmd);
+               if (ret) {
+                       cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+                       goto err;
                }
        }
+
+       ret = cmd->execute_cmd(cmd);
+       if (!ret)
+               return;
+err:
+       spin_lock_irq(&cmd->t_state_lock);
+       cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       transport_generic_request_failure(cmd, ret);
 }
 
 static int target_write_prot_action(struct se_cmd *cmd)
@@ -1807,6 +1816,8 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return false;
 
+       cmd->se_cmd_flags |= SCF_TASK_ATTR_SET;
+
        /*
         * Check for the existence of HEAD_OF_QUEUE, and if true return 1
         * to allow the passed struct se_cmd list of tasks to the front of the list.
@@ -1887,7 +1898,7 @@ void target_execute_cmd(struct se_cmd *cmd)
                return;
        }
 
-       __target_execute_cmd(cmd);
+       __target_execute_cmd(cmd, true);
 }
 EXPORT_SYMBOL(target_execute_cmd);
 
@@ -1911,7 +1922,7 @@ static void target_restart_delayed_cmds(struct se_device *dev)
                list_del(&cmd->se_delayed_node);
                spin_unlock(&dev->delayed_cmd_lock);
 
-               __target_execute_cmd(cmd);
+               __target_execute_cmd(cmd, true);
 
                if (cmd->sam_task_attr == TCM_ORDERED_TAG)
                        break;
@@ -1929,6 +1940,9 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return;
 
+       if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET))
+               goto restart;
+
        if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
                atomic_dec_mb(&dev->simple_cmds);
                dev->dev_cur_ordered_id++;
@@ -1945,7 +1959,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
                pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
                         dev->dev_cur_ordered_id);
        }
-
+restart:
        target_restart_delayed_cmds(dev);
 }
 
@@ -2496,8 +2510,10 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
         * fabric acknowledgement that requires two target_put_sess_cmd()
         * invocations before se_cmd descriptor release.
         */
-       if (ack_kref)
+       if (ack_kref) {
                kref_get(&se_cmd->cmd_kref);
+               se_cmd->se_cmd_flags |= SCF_ACK_KREF;
+       }
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (se_sess->sess_tearing_down) {
@@ -2533,15 +2549,10 @@ static void target_release_cmd_kref(struct kref *kref)
        bool fabric_stop;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       if (list_empty(&se_cmd->se_cmd_list)) {
-               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-               target_free_cmd_mem(se_cmd);
-               se_cmd->se_tfo->release_cmd(se_cmd);
-               return;
-       }
 
        spin_lock(&se_cmd->t_state_lock);
-       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
+       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) &&
+                     (se_cmd->transport_state & CMD_T_ABORTED);
        spin_unlock(&se_cmd->t_state_lock);
 
        if (se_cmd->cmd_wait_set || fabric_stop) {
@@ -2825,6 +2836,12 @@ static const struct sense_info sense_info_table[] = {
                .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
                .add_sector_info = true,
        },
+       [TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = {
+               .key = COPY_ABORTED,
+               .asc = 0x0d,
+               .ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */
+
+       },
        [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = {
                /*
                 * Returning ILLEGAL REQUEST would cause immediate IO errors on
index 47fe94ee10b82d876fedef726308738dc62f5805..153a6f255b6d98782c27f1932274d952092c455d 100644 (file)
@@ -104,7 +104,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
        }
        mutex_unlock(&g_device_mutex);
 
-       pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+       pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
        return -EINVAL;
 }
 
@@ -185,7 +185,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
 
 static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
                                struct xcopy_op *xop, unsigned char *p,
-                               unsigned short tdll)
+                               unsigned short tdll, sense_reason_t *sense_ret)
 {
        struct se_device *local_dev = se_cmd->se_dev;
        unsigned char *desc = p;
@@ -193,6 +193,8 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
        unsigned short start = 0;
        bool src = true;
 
+       *sense_ret = TCM_INVALID_PARAMETER_LIST;
+
        if (offset != 0) {
                pr_err("XCOPY target descriptor list length is not"
                        " multiple of %d\n", XCOPY_TARGET_DESC_LEN);
@@ -243,9 +245,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
                rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
        else
                rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
-
-       if (rc < 0)
+       /*
+        * If a matching IEEE NAA 0x83 descriptor for the requested device
+        * is not located on this node, return COPY_ABORTED with ASQ/ASQC
+        * 0x0d/0x02 - COPY_TARGET_DEVICE_NOT_REACHABLE to request the
+        * initiator to fall back to normal copy method.
+        */
+       if (rc < 0) {
+               *sense_ret = TCM_COPY_TARGET_DEVICE_NOT_REACHABLE;
                goto out;
+       }
 
        pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
                 xop->src_dev, &xop->src_tid_wwn[0]);
@@ -653,6 +662,7 @@ static int target_xcopy_read_source(
        rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
                                remote_port, true);
        if (rc < 0) {
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                transport_generic_free_cmd(se_cmd, 0);
                return rc;
        }
@@ -664,6 +674,7 @@ static int target_xcopy_read_source(
 
        rc = target_xcopy_issue_pt_cmd(xpt_cmd);
        if (rc < 0) {
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                transport_generic_free_cmd(se_cmd, 0);
                return rc;
        }
@@ -714,6 +725,7 @@ static int target_xcopy_write_destination(
                                remote_port, false);
        if (rc < 0) {
                struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                /*
                 * If the failure happened before the t_mem_list hand-off in
                 * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
@@ -729,6 +741,7 @@ static int target_xcopy_write_destination(
 
        rc = target_xcopy_issue_pt_cmd(xpt_cmd);
        if (rc < 0) {
+               ec_cmd->scsi_status = xpt_cmd->se_cmd.scsi_status;
                se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
                transport_generic_free_cmd(se_cmd, 0);
                return rc;
@@ -815,9 +828,14 @@ static void target_xcopy_do_work(struct work_struct *work)
 out:
        xcopy_pt_undepend_remotedev(xop);
        kfree(xop);
-
-       pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n");
-       ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+       /*
+        * Don't override an error scsi status if it has already been set
+        */
+       if (ec_cmd->scsi_status == SAM_STAT_GOOD) {
+               pr_warn_ratelimited("target_xcopy_do_work: rc: %d, Setting X-COPY"
+                       " CHECK_CONDITION -> sending response\n", rc);
+               ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+       }
        target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION);
 }
 
@@ -875,7 +893,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
                " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
                tdll, sdll, inline_dl);
 
-       rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll);
+       rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
        if (rc <= 0)
                goto out;
 
index 7865228f664f9e9e8ab60aec0c938b00afd90757..807d8014568643a18fb061a8c661b0b0c3c5eeb1 100644 (file)
@@ -679,14 +679,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 /* this is called once with whichever end is closed last */
 static void pty_unix98_shutdown(struct tty_struct *tty)
 {
-       struct inode *ptmx_inode;
+       struct pts_fs_info *fsi;
 
        if (tty->driver->subtype == PTY_TYPE_MASTER)
-               ptmx_inode = tty->driver_data;
+               fsi = tty->driver_data;
        else
-               ptmx_inode = tty->link->driver_data;
-       devpts_kill_index(ptmx_inode, tty->index);
-       devpts_del_ref(ptmx_inode);
+               fsi = tty->link->driver_data;
+       devpts_kill_index(fsi, tty->index);
+       devpts_put_ref(fsi);
 }
 
 static const struct tty_operations ptm_unix98_ops = {
@@ -738,6 +738,7 @@ static const struct tty_operations pty_unix98_ops = {
 
 static int ptmx_open(struct inode *inode, struct file *filp)
 {
+       struct pts_fs_info *fsi;
        struct tty_struct *tty;
        struct inode *slave_inode;
        int retval;
@@ -752,47 +753,41 @@ static int ptmx_open(struct inode *inode, struct file *filp)
        if (retval)
                return retval;
 
+       fsi = devpts_get_ref(inode, filp);
+       retval = -ENODEV;
+       if (!fsi)
+               goto out_free_file;
+
        /* find a device that is not in use. */
        mutex_lock(&devpts_mutex);
-       index = devpts_new_index(inode);
-       if (index < 0) {
-               retval = index;
-               mutex_unlock(&devpts_mutex);
-               goto err_file;
-       }
-
+       index = devpts_new_index(fsi);
        mutex_unlock(&devpts_mutex);
 
-       mutex_lock(&tty_mutex);
-       tty = tty_init_dev(ptm_driver, index);
+       retval = index;
+       if (index < 0)
+               goto out_put_ref;
 
-       if (IS_ERR(tty)) {
-               retval = PTR_ERR(tty);
-               goto out;
-       }
 
+       mutex_lock(&tty_mutex);
+       tty = tty_init_dev(ptm_driver, index);
        /* The tty returned here is locked so we can safely
           drop the mutex */
        mutex_unlock(&tty_mutex);
 
-       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-       tty->driver_data = inode;
+       retval = PTR_ERR(tty);
+       if (IS_ERR(tty))
+               goto out;
 
        /*
-        * In the case where all references to ptmx inode are dropped and we
-        * still have /dev/tty opened pointing to the master/slave pair (ptmx
-        * is closed/released before /dev/tty), we must make sure that the inode
-        * is still valid when we call the final pty_unix98_shutdown, thus we
-        * hold an additional reference to the ptmx inode. For the same /dev/tty
-        * last close case, we also need to make sure the super_block isn't
-        * destroyed (devpts instance unmounted), before /dev/tty is closed and
-        * on its release devpts_kill_index is called.
+        * From here on out, the tty is "live", and the index and
+        * fsi will be killed/put by the tty_release()
         */
-       devpts_add_ref(inode);
+       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+       tty->driver_data = fsi;
 
        tty_add_file(tty, filp);
 
-       slave_inode = devpts_pty_new(inode,
+       slave_inode = devpts_pty_new(fsi,
                        MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
                        tty->link);
        if (IS_ERR(slave_inode)) {
@@ -811,12 +806,14 @@ static int ptmx_open(struct inode *inode, struct file *filp)
        return 0;
 err_release:
        tty_unlock(tty);
+       // This will also put-ref the fsi
        tty_release(inode, filp);
        return retval;
 out:
-       mutex_unlock(&tty_mutex);
-       devpts_kill_index(inode, index);
-err_file:
+       devpts_kill_index(fsi, index);
+out_put_ref:
+       devpts_put_ref(fsi);
+out_free_file:
        tty_free_file(filp);
        return retval;
 }
index a5d319e4aae65dad90f64bafd33c2ad02bed7034..8435c3f204c1ed85ef501d0232632659a46d1ffc 100644 (file)
@@ -440,7 +440,7 @@ static int dw8250_probe(struct platform_device *pdev)
        }
 
        data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
-       if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
+       if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) {
                err = -EPROBE_DEFER;
                goto err_clk;
        }
index ed489880e62b3ec4bd988dc833885afc68d7d367..83b3988eb6b20297b9a304fb97c2c2dffaec2848 100644 (file)
@@ -149,6 +149,9 @@ static void mid8250_set_termios(struct uart_port *p,
        unsigned long w = BIT(24) - 1;
        unsigned long mul, div;
 
+       /* Gracefully handle the B0 case: fall back to B9600 */
+       fuart = fuart ? fuart : 9600 * 16;
+
        if (mid->board->freq < fuart) {
                /* Find prescaler value that satisfies Fuart < Fref */
                if (mid->board->freq > baud)
index c1d4a8fa9be889fd839a02ed576511b3c28919cb..029de3f99752ef1a1ce36bbabd9e02e543a6fab9 100644 (file)
@@ -1952,6 +1952,43 @@ pci_wch_ch38x_setup(struct serial_private *priv,
 #define PCI_DEVICE_ID_PERICOM_PI7C9X7954       0x7954
 #define PCI_DEVICE_ID_PERICOM_PI7C9X7958       0x7958
 
+#define PCI_VENDOR_ID_ACCESIO                  0x494f
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB    0x1051
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S     0x1053
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB    0x105C
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S     0x105E
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB  0x1091
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2   0x1093
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB  0x1099
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4   0x109B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB   0x10D1
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM    0x10D3
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB   0x10DA
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM    0x10DC
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1   0x1108
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2   0x1110
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2   0x1111
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4   0x1118
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4   0x1119
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S      0x1152
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S      0x115A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2    0x1190
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2   0x1191
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4    0x1198
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4   0x1199
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM     0x11D0
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4    0x105A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4    0x105B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8    0x106A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8    0x106B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4    0x1098
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8    0x10A9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM     0x10D9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM     0x10E9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM     0x11D8
+
+
+
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588        0x1588
@@ -5119,6 +5156,108 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0,
                0, pbn_pericom_PI7C9X7958 },
+       /*
+        * ACCES I/O Products quad
+        */
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7954 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
+       {       PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_pericom_PI7C9X7958 },
        /*
         * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
         */
index 7bbadd176c74643c8eb8deb0742f0a45729f52ab..7b5462eb83882446685a268559b936c74cd783dd 100644 (file)
@@ -485,19 +485,21 @@ static void atmel_start_tx(struct uart_port *port)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-       if (atmel_use_pdc_tx(port)) {
-               if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN)
-                       /* The transmitter is already running.  Yes, we
-                          really need this.*/
-                       return;
+       if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
+                                      & ATMEL_PDC_TXTEN))
+               /* The transmitter is already running.  Yes, we
+                  really need this.*/
+               return;
 
+       if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
                if ((port->rs485.flags & SER_RS485_ENABLED) &&
                    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
                        atmel_stop_rx(port);
 
+       if (atmel_use_pdc_tx(port))
                /* re-enable PDC transmit */
                atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
-       }
+
        /* Enable interrupts */
        atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
 }
index dcde955475dc9b11029c614d0d137d582d04e77c..e1de4944e0ce5f8eae8ada1020086294c9a13fea 100644 (file)
@@ -726,7 +726,7 @@ static void msm_handle_tx(struct uart_port *port)
                return;
        }
 
-       pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+       pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
        dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
        dma_min = 1;    /* Always DMA */
index 8320173af846b396a40319168b5718f6dd5c816a..237ef5573c1819eeefa078bb03aa221615226092 100644 (file)
@@ -1676,7 +1676,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
                return -ENODEV;
 
        if (port->mapbase != 0)
-               return 0;
+               return -EINVAL;
 
        /* setup info for port */
        port->dev       = &platdev->dev;
@@ -1730,22 +1730,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
                ourport->dma = devm_kzalloc(port->dev,
                                            sizeof(*ourport->dma),
                                            GFP_KERNEL);
-               if (!ourport->dma)
-                       return -ENOMEM;
+               if (!ourport->dma) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
        }
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
        if (IS_ERR(ourport->clk)) {
                pr_err("%s: Controller clock not found\n",
                                dev_name(&platdev->dev));
-               return PTR_ERR(ourport->clk);
+               ret = PTR_ERR(ourport->clk);
+               goto err;
        }
 
        ret = clk_prepare_enable(ourport->clk);
        if (ret) {
                pr_err("uart: clock failed to prepare+enable: %d\n", ret);
                clk_put(ourport->clk);
-               return ret;
+               goto err;
        }
 
        /* Keep all interrupts masked and cleared */
@@ -1761,7 +1764,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 
        /* reset the fifos (and setup the uart) */
        s3c24xx_serial_resetport(port, cfg);
+
        return 0;
+
+err:
+       port->mapbase = 0;
+       return ret;
 }
 
 /* Device driver serial port probe */
index 629e3c865072035f14fd4e6ece5a2544bcbf713c..9bee25cfa0be5e5a39cd00a2aa8e2fd57ac69096 100644 (file)
@@ -417,6 +417,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
  *     they are not on hot paths so a little discipline won't do
  *     any harm.
  *
+ *     The line discipline-related tty_struct fields are reset to
+ *     prevent the ldisc driver from re-using stale information for
+ *     the new ldisc instance.
+ *
  *     Locking: takes termios_rwsem
  */
 
@@ -425,6 +429,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
        down_write(&tty->termios_rwsem);
        tty->termios.c_line = num;
        up_write(&tty->termios_rwsem);
+
+       tty->disc_data = NULL;
+       tty->receive_room = 0;
 }
 
 /**
index 915facbf552e207c68b4b7555b9520d70746853f..e1134a4d97f3fd0005e30dc29e9acf9da77e0e46 100644 (file)
@@ -229,7 +229,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
                ++uiomem;
        }
 
-       priv->dmem_region_start = i;
+       priv->dmem_region_start = uiomem - &uioinfo->mem[0];
        priv->num_dmem_regions = pdata->num_dynamic_regions;
 
        for (i = 0; i < pdata->num_dynamic_regions; ++i) {
index 391a1225b0ba330cd818028f240cb151e8ade65c..68fc5fce4cc55cb2534116d8d3952bdacbbe4fa3 100644 (file)
@@ -939,6 +939,15 @@ static int isr_setup_status_phase(struct ci_hdrc *ci)
        int retval;
        struct ci_hw_ep *hwep;
 
+       /*
+        * Unexpected USB controller behavior, caused by bad signal integrity
+        * or ground reference problems, can lead to isr_setup_status_phase
+        * being called with ci->status equal to NULL.
+        * If this situation occurs, you should review your USB hardware design.
+        */
+       if (WARN_ON_ONCE(!ci->status))
+               return -EPIPE;
+
        hwep = (ci->ep0_dir == TX) ? ci->ep0out : ci->ep0in;
        ci->status->context = ci;
        ci->status->complete = isr_setup_status_complete;
@@ -1585,8 +1594,11 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
 {
        struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
 
-       /* Data+ pullup controlled by OTG state machine in OTG fsm mode */
-       if (ci_otg_is_fsm_mode(ci))
+       /*
+        * Data+ pullup controlled by OTG state machine in OTG fsm mode;
+        * and don't touch Data+ in host mode for dual role config.
+        */
+       if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
                return 0;
 
        pm_runtime_get_sync(&ci->gadget.dev);
index d37fdcc3143c0c097a53b35cc3b6b9edc81eaa78..7f374369e53956e30dd93183590e47ac8d0ea598 100644 (file)
@@ -1336,7 +1336,6 @@ made_compressed_probe:
        spin_lock_init(&acm->write_lock);
        spin_lock_init(&acm->read_lock);
        mutex_init(&acm->mutex);
-       acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
        acm->is_int_ep = usb_endpoint_xfer_int(epread);
        if (acm->is_int_ep)
                acm->bInterval = epread->bInterval;
@@ -1376,14 +1375,14 @@ made_compressed_probe:
                urb->transfer_dma = rb->dma;
                if (acm->is_int_ep) {
                        usb_fill_int_urb(urb, acm->dev,
-                                        acm->rx_endpoint,
+                                        usb_rcvintpipe(usb_dev, epread->bEndpointAddress),
                                         rb->base,
                                         acm->readsize,
                                         acm_read_bulk_callback, rb,
                                         acm->bInterval);
                } else {
                        usb_fill_bulk_urb(urb, acm->dev,
-                                         acm->rx_endpoint,
+                                         usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
                                          rb->base,
                                          acm->readsize,
                                          acm_read_bulk_callback, rb);
index ccfaba9ab4e49cd4a009132397d9467bc949bfd0..b30ac5fcde6875a5e93b2006b86923a26538ad06 100644 (file)
@@ -95,7 +95,6 @@ struct acm {
        struct urb *read_urbs[ACM_NR];
        struct acm_rb read_buffers[ACM_NR];
        int rx_buflimit;
-       int rx_endpoint;
        spinlock_t read_lock;
        int write_used;                                 /* number of non-empty write buffers */
        int transmitting;
index 7a11a8263171caad8ccba867bfa4e2e9734c2c3f..deaddb950c20d6cffbfff91754f30485e4a52c4f 100644 (file)
@@ -121,6 +121,7 @@ static void usbtmc_delete(struct kref *kref)
        struct usbtmc_device_data *data = to_usbtmc_data(kref);
 
        usb_put_dev(data->usb_dev);
+       kfree(data);
 }
 
 static int usbtmc_open(struct inode *inode, struct file *filp)
@@ -1104,7 +1105,7 @@ static int usbtmc_probe(struct usb_interface *intf,
 
        dev_dbg(&intf->dev, "%s called\n", __func__);
 
-       data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
index 86449fb3f5bfde822f6aa183b86e375d3d064c45..57643b3ba2c05b475027e7cd582dd423954a84e2 100644 (file)
@@ -51,6 +51,7 @@ static const char *const speed_names[] = {
        [USB_SPEED_HIGH] = "high-speed",
        [USB_SPEED_WIRELESS] = "wireless",
        [USB_SPEED_SUPER] = "super-speed",
+       [USB_SPEED_SUPER_PLUS] = "super-speed-plus",
 };
 
 const char *usb_speed_string(enum usb_device_speed speed)
index 5050760f5e17cf3872952ae5fa6a40d01aab394b..ff44cfa26af81bf41d1efc6ab66dbec57998e77e 100644 (file)
@@ -142,6 +142,31 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
        }
 }
 
+static const unsigned short low_speed_maxpacket_maxes[4] = {
+       [USB_ENDPOINT_XFER_CONTROL] = 8,
+       [USB_ENDPOINT_XFER_ISOC] = 0,
+       [USB_ENDPOINT_XFER_BULK] = 0,
+       [USB_ENDPOINT_XFER_INT] = 8,
+};
+static const unsigned short full_speed_maxpacket_maxes[4] = {
+       [USB_ENDPOINT_XFER_CONTROL] = 64,
+       [USB_ENDPOINT_XFER_ISOC] = 1023,
+       [USB_ENDPOINT_XFER_BULK] = 64,
+       [USB_ENDPOINT_XFER_INT] = 64,
+};
+static const unsigned short high_speed_maxpacket_maxes[4] = {
+       [USB_ENDPOINT_XFER_CONTROL] = 64,
+       [USB_ENDPOINT_XFER_ISOC] = 1024,
+       [USB_ENDPOINT_XFER_BULK] = 512,
+       [USB_ENDPOINT_XFER_INT] = 1024,
+};
+static const unsigned short super_speed_maxpacket_maxes[4] = {
+       [USB_ENDPOINT_XFER_CONTROL] = 512,
+       [USB_ENDPOINT_XFER_ISOC] = 1024,
+       [USB_ENDPOINT_XFER_BULK] = 1024,
+       [USB_ENDPOINT_XFER_INT] = 1024,
+};
+
 static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
     int asnum, struct usb_host_interface *ifp, int num_ep,
     unsigned char *buffer, int size)
@@ -150,6 +175,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        struct usb_endpoint_descriptor *d;
        struct usb_host_endpoint *endpoint;
        int n, i, j, retval;
+       unsigned int maxp;
+       const unsigned short *maxpacket_maxes;
 
        d = (struct usb_endpoint_descriptor *) buffer;
        buffer += d->bLength;
@@ -184,22 +211,27 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        memcpy(&endpoint->desc, d, n);
        INIT_LIST_HEAD(&endpoint->urb_list);
 
-       /* Fix up bInterval values outside the legal range. Use 32 ms if no
-        * proper value can be guessed. */
+       /*
+        * Fix up bInterval values outside the legal range.
+        * Use 10 or 8 ms if no proper value can be guessed.
+        */
        i = 0;          /* i = min, j = max, n = default */
        j = 255;
        if (usb_endpoint_xfer_int(d)) {
                i = 1;
                switch (to_usb_device(ddev)->speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:
                case USB_SPEED_HIGH:
-                       /* Many device manufacturers are using full-speed
+                       /*
+                        * Many device manufacturers are using full-speed
                         * bInterval values in high-speed interrupt endpoint
-                        * descriptors. Try to fix those and fall back to a
-                        * 32 ms default value otherwise. */
+                        * descriptors. Try to fix those and fall back to an
+                        * 8-ms default value otherwise.
+                        */
                        n = fls(d->bInterval*8);
                        if (n == 0)
-                               n = 9;  /* 32 ms = 2^(9-1) uframes */
+                               n = 7;  /* 8 ms = 2^(7-1) uframes */
                        j = 16;
 
                        /*
@@ -214,10 +246,12 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                        }
                        break;
                default:                /* USB_SPEED_FULL or _LOW */
-                       /* For low-speed, 10 ms is the official minimum.
+                       /*
+                        * For low-speed, 10 ms is the official minimum.
                         * But some "overclocked" devices might want faster
-                        * polling so we'll allow it. */
-                       n = 32;
+                        * polling so we'll allow it.
+                        */
+                       n = 10;
                        break;
                }
        } else if (usb_endpoint_xfer_isoc(d)) {
@@ -225,10 +259,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                j = 16;
                switch (to_usb_device(ddev)->speed) {
                case USB_SPEED_HIGH:
-                       n = 9;          /* 32 ms = 2^(9-1) uframes */
+                       n = 7;          /* 8 ms = 2^(7-1) uframes */
                        break;
                default:                /* USB_SPEED_FULL */
-                       n = 6;          /* 32 ms = 2^(6-1) frames */
+                       n = 4;          /* 8 ms = 2^(4-1) frames */
                        break;
                }
        }
@@ -256,6 +290,42 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                        endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
        }
 
+       /* Validate the wMaxPacketSize field */
+       maxp = usb_endpoint_maxp(&endpoint->desc);
+
+       /* Find the highest legal maxpacket size for this endpoint */
+       i = 0;          /* additional transactions per microframe */
+       switch (to_usb_device(ddev)->speed) {
+       case USB_SPEED_LOW:
+               maxpacket_maxes = low_speed_maxpacket_maxes;
+               break;
+       case USB_SPEED_FULL:
+               maxpacket_maxes = full_speed_maxpacket_maxes;
+               break;
+       case USB_SPEED_HIGH:
+               /* Bits 12..11 are allowed only for HS periodic endpoints */
+               if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
+                       i = maxp & (BIT(12) | BIT(11));
+                       maxp &= ~i;
+               }
+               /* fallthrough */
+       default:
+               maxpacket_maxes = high_speed_maxpacket_maxes;
+               break;
+       case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
+               maxpacket_maxes = super_speed_maxpacket_maxes;
+               break;
+       }
+       j = maxpacket_maxes[usb_endpoint_type(&endpoint->desc)];
+
+       if (maxp > j) {
+               dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid maxpacket %d, setting to %d\n",
+                   cfgno, inum, asnum, d->bEndpointAddress, maxp, j);
+               maxp = j;
+               endpoint->desc.wMaxPacketSize = cpu_to_le16(i | maxp);
+       }
+
        /*
         * Some buggy high speed devices have bulk endpoints using
         * maxpacket sizes other than 512.  High speed HCDs may not
@@ -263,9 +333,6 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
         */
        if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
                        && usb_endpoint_xfer_bulk(d)) {
-               unsigned maxp;
-
-               maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
                if (maxp != 512)
                        dev_warn(ddev, "config %d interface %d altsetting %d "
                                "bulk endpoint 0x%X has invalid maxpacket %d\n",
@@ -274,7 +341,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        }
 
        /* Parse a possible SuperSpeed endpoint companion descriptor */
-       if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
+       if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER)
                usb_parse_ss_endpoint_companion(ddev, cfgno,
                                inum, asnum, endpoint, buffer, size);
 
index 2a3bbdf7eb9407568c71c0896615d30fb48ea9cb..332ed277a06ceb866dffb8e784ec06d92348dc85 100644 (file)
@@ -221,7 +221,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
                break;
        case USB_ENDPOINT_XFER_INT:
                type = "Int.";
-               if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
+               if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
                        interval = 1 << (desc->bInterval - 1);
                else
                        interval = desc->bInterval;
@@ -230,7 +230,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
                return start;
        }
        interval *= (speed == USB_SPEED_HIGH ||
-                    speed == USB_SPEED_SUPER) ? 125 : 1000;
+                    speed >= USB_SPEED_SUPER) ? 125 : 1000;
        if (interval % 1000)
                unit = 'u';
        else {
@@ -322,7 +322,7 @@ static char *usb_dump_config_descriptor(char *start, char *end,
 
        if (start > end)
                return start;
-       if (speed == USB_SPEED_SUPER)
+       if (speed >= USB_SPEED_SUPER)
                mul = 8;
        else
                mul = 2;
@@ -534,6 +534,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
                speed = "480"; break;
        case USB_SPEED_SUPER:
                speed = "5000"; break;
+       case USB_SPEED_SUPER_PLUS:
+               speed = "10000"; break;
        default:
                speed = "??";
        }
@@ -553,7 +555,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
 
                /* super/high speed reserves 80%, full/low reserves 90% */
                if (usbdev->speed == USB_SPEED_HIGH ||
-                   usbdev->speed == USB_SPEED_SUPER)
+                   usbdev->speed >= USB_SPEED_SUPER)
                        max = 800;
                else
                        max = FRAME_TIME_MAX_USECS_ALLOC;
index 3ffb01ff654978a9aa7f5ba62317a23a95aecade..f5c92d904ded329dfff64de542604ce7b5c9f756 100644 (file)
@@ -1530,11 +1530,17 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
        as->urb->start_frame = uurb->start_frame;
        as->urb->number_of_packets = number_of_packets;
        as->urb->stream_id = stream_id;
-       if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
-                       ps->dev->speed == USB_SPEED_HIGH)
-               as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
-       else
-               as->urb->interval = ep->desc.bInterval;
+
+       if (ep->desc.bInterval) {
+               if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+                               ps->dev->speed == USB_SPEED_HIGH ||
+                               ps->dev->speed >= USB_SPEED_SUPER)
+                       as->urb->interval = 1 <<
+                                       min(15, ep->desc.bInterval - 1);
+               else
+                       as->urb->interval = ep->desc.bInterval;
+       }
+
        as->urb->context = as;
        as->urb->complete = async_completed;
        for (totlen = u = 0; u < number_of_packets; u++) {
index b8b580e5ae6e369f2bf1033e3dc054817b51f125..40378487e023c4e41e4b5de99de4feb343548deb 100644 (file)
@@ -206,7 +206,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
         * The xHCI driver has its own irq management
         * make sure irq setup is not touched for xhci in generic hcd code
         */
-       if ((driver->flags & HCD_MASK) != HCD_USB3) {
+       if ((driver->flags & HCD_MASK) < HCD_USB3) {
                if (!dev->irq) {
                        dev_err(&dev->dev,
                        "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
index 1c102d60cd9f4afe861a6933e9495662d74de4f5..f44ce09367bc185a514b12fd32c5a604a36e07cc 100644 (file)
@@ -1078,7 +1078,7 @@ static int register_root_hub(struct usb_hcd *hcd)
                retval = usb_get_bos_descriptor(usb_dev);
                if (!retval) {
                        usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
-               } else if (usb_dev->speed == USB_SPEED_SUPER) {
+               } else if (usb_dev->speed >= USB_SPEED_SUPER) {
                        mutex_unlock(&usb_bus_list_lock);
                        dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
                                        dev_name(&usb_dev->dev), retval);
@@ -2112,7 +2112,7 @@ int usb_alloc_streams(struct usb_interface *interface,
        hcd = bus_to_hcd(dev->bus);
        if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
                return -EINVAL;
-       if (dev->speed != USB_SPEED_SUPER)
+       if (dev->speed < USB_SPEED_SUPER)
                return -EINVAL;
        if (dev->state < USB_STATE_CONFIGURED)
                return -ENODEV;
@@ -2160,7 +2160,7 @@ int usb_free_streams(struct usb_interface *interface,
 
        dev = interface_to_usbdev(interface);
        hcd = bus_to_hcd(dev->bus);
-       if (dev->speed != USB_SPEED_SUPER)
+       if (dev->speed < USB_SPEED_SUPER)
                return -EINVAL;
 
        /* Double-free is not allowed */
index 84df093639acb18c37e7b8b45bb878d0aca2bf5a..bcc1e1b729adf139cd9452864183195245d79ac3 100644 (file)
@@ -298,7 +298,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
        unsigned int hub_u1_del;
        unsigned int hub_u2_del;
 
-       if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+       if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
                return;
 
        hub = usb_hub_to_struct_hub(udev->parent);
@@ -1036,14 +1036,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 
        /* Continue a partial initialization */
        if (type == HUB_INIT2 || type == HUB_INIT3) {
-               device_lock(hub->intfdev);
+               device_lock(&hdev->dev);
 
                /* Was the hub disconnected while we were waiting? */
-               if (hub->disconnected) {
-                       device_unlock(hub->intfdev);
-                       kref_put(&hub->kref, hub_release);
-                       return;
-               }
+               if (hub->disconnected)
+                       goto disconnected;
                if (type == HUB_INIT2)
                        goto init2;
                goto init3;
@@ -1246,7 +1243,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                        queue_delayed_work(system_power_efficient_wq,
                                        &hub->init_work,
                                        msecs_to_jiffies(delay));
-                       device_unlock(hub->intfdev);
+                       device_unlock(&hdev->dev);
                        return;         /* Continues at init3: below */
                } else {
                        msleep(delay);
@@ -1265,12 +1262,12 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
        /* Scan all ports that need attention */
        kick_hub_wq(hub);
 
-       /* Allow autosuspend if it was suppressed */
-       if (type <= HUB_INIT3)
+       if (type == HUB_INIT2 || type == HUB_INIT3) {
+               /* Allow autosuspend if it was suppressed */
+ disconnected:
                usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
-
-       if (type == HUB_INIT2 || type == HUB_INIT3)
-               device_unlock(hub->intfdev);
+               device_unlock(&hdev->dev);
+       }
 
        kref_put(&hub->kref, hub_release);
 }
@@ -1299,8 +1296,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
        struct usb_device *hdev = hub->hdev;
        int i;
 
-       cancel_delayed_work_sync(&hub->init_work);
-
        /* hub_wq and related activity won't re-trigger */
        hub->quiescing = 1;
 
@@ -2645,7 +2640,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
  */
 static bool use_new_scheme(struct usb_device *udev, int retry)
 {
-       if (udev->speed == USB_SPEED_SUPER)
+       if (udev->speed >= USB_SPEED_SUPER)
                return false;
 
        return USE_NEW_SCHEME(retry);
@@ -3985,7 +3980,7 @@ int usb_disable_lpm(struct usb_device *udev)
        struct usb_hcd *hcd;
 
        if (!udev || !udev->parent ||
-                       udev->speed != USB_SPEED_SUPER ||
+                       udev->speed < USB_SPEED_SUPER ||
                        !udev->lpm_capable ||
                        udev->state < USB_STATE_DEFAULT)
                return 0;
@@ -4042,7 +4037,7 @@ void usb_enable_lpm(struct usb_device *udev)
        struct usb_hcd *hcd;
 
        if (!udev || !udev->parent ||
-                       udev->speed != USB_SPEED_SUPER ||
+                       udev->speed < USB_SPEED_SUPER ||
                        !udev->lpm_capable ||
                        udev->state < USB_STATE_DEFAULT)
                return;
@@ -4308,7 +4303,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
 
        retval = -ENODEV;
 
-       if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
+       /* Don't allow speed changes at reset, except usb 3.0 to faster */
+       if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
+           !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
                dev_dbg(&udev->dev, "device reset changed speed!\n");
                goto fail;
        }
@@ -4320,6 +4317,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
         * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
         */
        switch (udev->speed) {
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
        case USB_SPEED_WIRELESS:        /* fixed at 512 */
                udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
@@ -4346,7 +4344,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
        else
                speed = usb_speed_string(udev->speed);
 
-       if (udev->speed != USB_SPEED_SUPER)
+       if (udev->speed < USB_SPEED_SUPER)
                dev_info(&udev->dev,
                                "%s %s USB device number %d using %s\n",
                                (udev->config) ? "reset" : "new", speed,
@@ -4476,11 +4474,12 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
                                                        devnum, retval);
                                goto fail;
                        }
-                       if (udev->speed == USB_SPEED_SUPER) {
+                       if (udev->speed >= USB_SPEED_SUPER) {
                                devnum = udev->devnum;
                                dev_info(&udev->dev,
-                                               "%s SuperSpeed USB device number %d using %s\n",
+                                               "%s SuperSpeed%s USB device number %d using %s\n",
                                                (udev->config) ? "reset" : "new",
+                                        (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
                                                devnum, udev->bus->controller->driver->name);
                        }
 
@@ -4519,7 +4518,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
         * got from those devices show they aren't superspeed devices. Warm
         * reset the port attached by the devices can fix them.
         */
-       if ((udev->speed == USB_SPEED_SUPER) &&
+       if ((udev->speed >= USB_SPEED_SUPER) &&
                        (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
                dev_err(&udev->dev, "got a wrong device descriptor, "
                                "warm reset device\n");
@@ -4530,7 +4529,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
        }
 
        if (udev->descriptor.bMaxPacketSize0 == 0xff ||
-                       udev->speed == USB_SPEED_SUPER)
+                       udev->speed >= USB_SPEED_SUPER)
                i = 512;
        else
                i = udev->descriptor.bMaxPacketSize0;
@@ -4740,7 +4739,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
                udev->level = hdev->level + 1;
                udev->wusb = hub_is_wusb(hub);
 
-               /* Only USB 3.0 devices are connected to SuperSpeed hubs. */
+               /* Devices connected to SuperSpeed hubs are USB 3.0 or later */
                if (hub_is_superspeed(hub->hdev))
                        udev->speed = USB_SPEED_SUPER;
                else
index 944a6dca0fcb50298ce1b0c21f9f7cd36c1707ca..d2e50a27140c9254be2a80b6c6ae69bc71a93b4a 100644 (file)
@@ -128,6 +128,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x04f3, 0x016f), .driver_info =
                        USB_QUIRK_DEVICE_QUALIFIER },
 
+       { USB_DEVICE(0x04f3, 0x0381), .driver_info =
+                       USB_QUIRK_NO_LPM },
+
        { USB_DEVICE(0x04f3, 0x21b8), .driver_info =
                        USB_QUIRK_DEVICE_QUALIFIER },
 
index 3d274778caaf8f9f473aacc89b1be6c20de19ab2..c601e25b609fb58e6842c18e62e5c484c98182ae 100644 (file)
@@ -401,7 +401,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                /* SuperSpeed isoc endpoints have up to 16 bursts of up to
                 * 3 packets each
                 */
-               if (dev->speed == USB_SPEED_SUPER) {
+               if (dev->speed >= USB_SPEED_SUPER) {
                        int     burst = 1 + ep->ss_ep_comp.bMaxBurst;
                        int     mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
                        max *= burst;
@@ -499,6 +499,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                }
                /* too big? */
                switch (dev->speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:   /* units are 125us */
                        /* Handle up to 2^(16-1) microframes */
                        if (urb->interval > (1 << 15))
index 05b5e17abf92fc158530d13f3e2ae8edf9923c5a..53318126ed91b24603934030702a0dae178cc5d1 100644 (file)
@@ -45,7 +45,7 @@ static inline unsigned usb_get_max_power(struct usb_device *udev,
                struct usb_host_config *c)
 {
        /* SuperSpeed power is in 8 mA units; others are in 2 mA units */
-       unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
+       unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2);
 
        return c->desc.bMaxPower * mul;
 }
index 45f5a232d9fb658b76845e19bb3ef4fa0a0aabf6..2eb84d6c24a6903fe57039e59a4321d7bb7ac6b3 100644 (file)
@@ -37,6 +37,7 @@
 #define PCI_DEVICE_ID_INTEL_BXT                        0x0aaa
 #define PCI_DEVICE_ID_INTEL_BXT_M              0x1aaa
 #define PCI_DEVICE_ID_INTEL_APL                        0x5aaa
+#define PCI_DEVICE_ID_INTEL_KBP                        0xa2b0
 
 static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
 static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@@ -227,6 +228,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
        {  }    /* Terminating Entry */
 };
index ca4229f3a1cc84848c5b3227acf29d5a97293635..5cb5407dbbfa39163b444d8f910ec91a95801717 100644 (file)
@@ -2019,14 +2019,6 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
                        s_pkt = 1;
        }
 
-       /*
-        * We assume here we will always receive the entire data block
-        * which we should receive. Meaning, if we program RX to
-        * receive 4K but we receive only 2K, we assume that's all we
-        * should receive and we simply bounce the request back to the
-        * gadget driver for further processing.
-        */
-       req->request.actual += req->request.length - count;
        if (s_pkt)
                return 1;
        if ((event->status & DEPEVT_STATUS_LST) &&
@@ -2046,6 +2038,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
        struct dwc3_trb         *trb;
        unsigned int            slot;
        unsigned int            i;
+       int                     count = 0;
        int                     ret;
 
        do {
@@ -2060,6 +2053,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                                slot++;
                        slot %= DWC3_TRB_NUM;
                        trb = &dep->trb_pool[slot];
+                       count += trb->size & DWC3_TRB_SIZE_MASK;
+
 
                        ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
                                        event, status);
@@ -2067,6 +2062,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                                break;
                } while (++i < req->request.num_mapped_sgs);
 
+               /*
+                * We assume here we will always receive the entire data block
+                * which we should receive. Meaning, if we program RX to
+                * receive 4K but we receive only 2K, we assume that's all we
+                * should receive and we simply bounce the request back to the
+                * gadget driver for further processing.
+                */
+               req->request.actual += req->request.length - count;
                dwc3_gadget_giveback(dep, req, status);
 
                if (ret)
index b27ce0747c188d95a52a9dee5fa14f00b66f7e76..8df96cb3bb582d5d6d8974ba67aea1f5f933569e 100644 (file)
@@ -1737,7 +1737,9 @@ void unregister_gadget_item(struct config_item *item)
 {
        struct gadget_info *gi = to_gadget_info(item);
 
+       mutex_lock(&gi->lock);
        unregister_gadget(gi);
+       mutex_unlock(&gi->lock);
 }
 EXPORT_SYMBOL_GPL(unregister_gadget_item);
 
index 067eb3bba65b231d817638d3f7e05f6abcfb5da2..4d27af468a0799255ea55671cb227f4fe2f49865 100644 (file)
@@ -531,15 +531,6 @@ static int create_bulk_endpoints(struct acc_dev *dev,
        ep->driver_data = dev;          /* claim the endpoint */
        dev->ep_out = ep;
 
-       ep = usb_ep_autoconfig(cdev->gadget, out_desc);
-       if (!ep) {
-               DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
-               return -ENODEV;
-       }
-       DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name);
-       ep->driver_data = dev;          /* claim the endpoint */
-       dev->ep_out = ep;
-
        /* now allocate requests for our endpoints */
        for (i = 0; i < TX_REQ_MAX; i++) {
                req = acc_request_new(dev->ep_in, BULK_BUFFER_SIZE);
index 97ef75af9632d81c093b85160363cee2fb5a6525..803c503a2e3d262b8a6ee858fab929596c84de43 100644 (file)
@@ -2740,6 +2740,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
                func->ffs->ss_descs_count;
 
        int fs_len, hs_len, ss_len, ret, i;
+       struct ffs_ep *eps_ptr;
 
        /* Make it a single chunk, less management later on */
        vla_group(d);
@@ -2788,12 +2789,9 @@ static int _ffs_func_bind(struct usb_configuration *c,
               ffs->raw_descs_length);
 
        memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
-       for (ret = ffs->eps_count; ret; --ret) {
-               struct ffs_ep *ptr;
-
-               ptr = vla_ptr(vlabuf, d, eps);
-               ptr[ret].num = -1;
-       }
+       eps_ptr = vla_ptr(vlabuf, d, eps);
+       for (i = 0; i < ffs->eps_count; i++)
+               eps_ptr[i].num = -1;
 
        /* Save pointers
         * d_eps == vlabuf, func->eps used to kfree vlabuf later
index 044ca79d3cb5d3b8a4764e27c1a1749caa43c971..12628dd36e55a3aea069863cd5d59ee38d5f63e9 100644 (file)
@@ -1291,6 +1291,7 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
 
        if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
                struct cntrl_cur_lay3 c;
+               memset(&c, 0, sizeof(struct cntrl_cur_lay3));
 
                if (entity_id == USB_IN_CLK_ID)
                        c.dCUR = p_srate;
index 55386619a0f11832160594ec7a549f92e0bfcbbe..e57f48f9528f9ccce70d76f111c5153e8e45da5d 100644 (file)
@@ -541,7 +541,7 @@ static ssize_t ep_aio(struct kiocb *iocb,
         */
        spin_lock_irq(&epdata->dev->lock);
        value = -ENODEV;
-       if (unlikely(epdata->ep))
+       if (unlikely(epdata->ep == NULL))
                goto fail;
 
        req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
index 5fb6f8b4f0b4889f51d1686610ab07b40cc9bdc0..b38a33584d4ac3af3a796e6eda756d6efd6b05ea 100644 (file)
@@ -1878,11 +1878,8 @@ static int qe_get_frame(struct usb_gadget *gadget)
 
        tmp = in_be16(&udc->usb_param->frame_n);
        if (tmp & 0x8000)
-               tmp = tmp & 0x07ff;
-       else
-               tmp = -EINVAL;
-
-       return (int)tmp;
+               return tmp & 0x07ff;
+       return -EINVAL;
 }
 
 static int fsl_qe_start(struct usb_gadget *gadget,
@@ -2053,7 +2050,7 @@ static void setup_received_handle(struct qe_udc *udc,
                        struct qe_ep *ep;
 
                        if (wValue != 0 || wLength != 0
-                               || pipe > USB_MAX_ENDPOINTS)
+                               || pipe >= USB_MAX_ENDPOINTS)
                                break;
                        ep = &udc->eps[pipe];
 
index 48c92bf78bd065ecc21bdda8ee5f50f426f25fda..f7661d9750fdc9a249663cbd88d97906c8cbaadf 100644 (file)
@@ -332,11 +332,11 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
        int     port = HCS_N_PORTS(ehci->hcs_params);
 
        while (port--) {
-               ehci_writel(ehci, PORT_RWC_BITS,
-                               &ehci->regs->port_status[port]);
                spin_unlock_irq(&ehci->lock);
                ehci_port_power(ehci, port, false);
                spin_lock_irq(&ehci->lock);
+               ehci_writel(ehci, PORT_RWC_BITS,
+                               &ehci->regs->port_status[port]);
        }
 }
 
index d029bbe9eb36a884fed45fd6f648bfca51199d65..641fed609911578ca8481ebb7a830f7ae418a924 100644 (file)
@@ -183,7 +183,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
 {
        int     branch;
 
-       ed->state = ED_OPER;
        ed->ed_prev = NULL;
        ed->ed_next = NULL;
        ed->hwNextED = 0;
@@ -259,6 +258,8 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
        /* the HC may not see the schedule updates yet, but if it does
         * then they'll be properly ordered.
         */
+
+       ed->state = ED_OPER;
        return 0;
 }
 
index f980c239eded9bd5e9615ebf96deefce5c7ec591..1da876605e4d9d863274643885a6f9da7b8b5ee4 100644 (file)
@@ -377,6 +377,9 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
 
        ret = 0;
        virt_dev = xhci->devs[slot_id];
+       if (!virt_dev)
+               return -ENODEV;
+
        cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
        if (!cmd) {
                xhci_dbg(xhci, "Couldn't allocate command structure.\n");
index d8dbd7e5194b19c7daee1ea44dff8a5de7a8e05b..8ea2c05beca2d42fc95caad030803809e10fa173 100644 (file)
@@ -1072,7 +1072,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
        struct usb_device *top_dev;
        struct usb_hcd *hcd;
 
-       if (udev->speed == USB_SPEED_SUPER)
+       if (udev->speed >= USB_SPEED_SUPER)
                hcd = xhci->shared_hcd;
        else
                hcd = xhci->main_hcd;
@@ -1107,6 +1107,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        /* 3) Only the control endpoint is valid - one endpoint context */
        slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route);
        switch (udev->speed) {
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
                slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
                max_packets = MAX_PACKET(512);
@@ -1294,6 +1295,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
                }
                /* Fall through - SS and HS isoc/int have same decoding */
 
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
                if (usb_endpoint_xfer_int(&ep->desc) ||
                    usb_endpoint_xfer_isoc(&ep->desc)) {
@@ -1334,7 +1336,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
 static u32 xhci_get_endpoint_mult(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
-       if (udev->speed != USB_SPEED_SUPER ||
+       if (udev->speed < USB_SPEED_SUPER ||
                        !usb_endpoint_xfer_isoc(&ep->desc))
                return 0;
        return ep->ss_ep_comp.bmAttributes;
@@ -1384,7 +1386,7 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev,
                        usb_endpoint_xfer_bulk(&ep->desc))
                return 0;
 
-       if (udev->speed == USB_SPEED_SUPER)
+       if (udev->speed >= USB_SPEED_SUPER)
                return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
 
        max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
@@ -1455,6 +1457,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
        max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
        max_burst = 0;
        switch (udev->speed) {
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
                /* dig out max burst from ep companion desc */
                max_burst = ep->ss_ep_comp.bMaxBurst;
index de644e56aa3b7b6f545e0bcbac1387e44dde6004..963867c2c1d55b29745c742ea61863e183ef9987 100644 (file)
@@ -311,11 +311,12 @@ static void xhci_pci_remove(struct pci_dev *dev)
                usb_remove_hcd(xhci->shared_hcd);
                usb_put_hcd(xhci->shared_hcd);
        }
-       usb_hcd_pci_remove(dev);
 
        /* Workaround for spurious wakeups at shutdown with HSW */
        if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
                pci_set_power_state(dev, PCI_D3hot);
+
+       usb_hcd_pci_remove(dev);
 }
 
 #ifdef CONFIG_PM
index 4a2f6c57a92b4744dae11cd18f64e7ad918959ce..62a5c8d5e0280ef1090bb32e9ba2cb0573e1e9b0 100644 (file)
@@ -1335,12 +1335,6 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
 
        cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list);
 
-       if (cmd->command_trb != xhci->cmd_ring->dequeue) {
-               xhci_err(xhci,
-                        "Command completion event does not match command\n");
-               return;
-       }
-
        del_timer(&xhci->cmd_timer);
 
        trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event);
@@ -1352,6 +1346,13 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                xhci_handle_stopped_cmd_ring(xhci, cmd);
                return;
        }
+
+       if (cmd->command_trb != xhci->cmd_ring->dequeue) {
+               xhci_err(xhci,
+                        "Command completion event does not match command\n");
+               return;
+       }
+
        /*
         * Host aborted the command ring, check if the current command was
         * supposed to be aborted, otherwise continue normally.
@@ -3579,7 +3580,7 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
 {
        unsigned int max_burst;
 
-       if (xhci->hci_version < 0x100 || udev->speed != USB_SPEED_SUPER)
+       if (xhci->hci_version < 0x100 || udev->speed < USB_SPEED_SUPER)
                return 0;
 
        max_burst = urb->ep->ss_ep_comp.bMaxBurst;
@@ -3605,6 +3606,7 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
                return 0;
 
        switch (udev->speed) {
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_SUPER:
                /* bMaxBurst is zero based: 0 means 1 packet per burst */
                max_burst = urb->ep->ss_ep_comp.bMaxBurst;
index 6373f159de12486bb7c8c37f967a07424d29ed40..e6ed6b2eab8ee2e4f4d9da95d1acc564cbad60ab 100644 (file)
@@ -2082,6 +2082,7 @@ static unsigned int xhci_get_block_size(struct usb_device *udev)
        case USB_SPEED_HIGH:
                return HS_BLOCK;
        case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
                return SS_BLOCK;
        case USB_SPEED_UNKNOWN:
        case USB_SPEED_WIRELESS:
@@ -2207,7 +2208,7 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
        unsigned int packets_remaining = 0;
        unsigned int i;
 
-       if (virt_dev->udev->speed == USB_SPEED_SUPER)
+       if (virt_dev->udev->speed >= USB_SPEED_SUPER)
                return xhci_check_ss_bw(xhci, virt_dev);
 
        if (virt_dev->udev->speed == USB_SPEED_HIGH) {
@@ -2408,7 +2409,7 @@ void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
        if (xhci_is_async_ep(ep_bw->type))
                return;
 
-       if (udev->speed == USB_SPEED_SUPER) {
+       if (udev->speed >= USB_SPEED_SUPER) {
                if (xhci_is_sync_in_ep(ep_bw->type))
                        xhci->devs[udev->slot_id]->bw_table->ss_bw_in -=
                                xhci_get_ss_bw_consumed(ep_bw);
@@ -2446,6 +2447,7 @@ void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
                interval_bw->overhead[HS_OVERHEAD_TYPE] -= 1;
                break;
        case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_UNKNOWN:
        case USB_SPEED_WIRELESS:
                /* Should never happen because only LS/FS/HS endpoints will get
@@ -2505,6 +2507,7 @@ static void xhci_add_ep_to_interval_table(struct xhci_hcd *xhci,
                interval_bw->overhead[HS_OVERHEAD_TYPE] += 1;
                break;
        case USB_SPEED_SUPER:
+       case USB_SPEED_SUPER_PLUS:
        case USB_SPEED_UNKNOWN:
        case USB_SPEED_WIRELESS:
                /* Should never happen because only LS/FS/HS endpoints will get
index 7771be3ac178ea0e95ca7da1f85ff55543ff4a00..4dd531ac5a7ffe0ecde019bc0d7024674f9f0ee9 100644 (file)
@@ -898,24 +898,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
        dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
        dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
 
-       /* we can register the device now, as it is ready */
-       usb_set_intfdata (interface, dev);
-
-       retval = usb_register_dev (interface, &tower_class);
-
-       if (retval) {
-               /* something prevented us from registering this driver */
-               dev_err(idev, "Not able to get a minor for this device.\n");
-               usb_set_intfdata (interface, NULL);
-               goto error;
-       }
-       dev->minor = interface->minor;
-
-       /* let the user know what node this device is now attached to */
-       dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major "
-                "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE),
-                USB_MAJOR, dev->minor);
-
        /* get the firmware version and log it */
        result = usb_control_msg (udev,
                                  usb_rcvctrlpipe(udev, 0),
@@ -936,6 +918,23 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
                 get_version_reply.minor,
                 le16_to_cpu(get_version_reply.build_no));
 
+       /* we can register the device now, as it is ready */
+       usb_set_intfdata (interface, dev);
+
+       retval = usb_register_dev (interface, &tower_class);
+
+       if (retval) {
+               /* something prevented us from registering this driver */
+               dev_err(idev, "Not able to get a minor for this device.\n");
+               usb_set_intfdata (interface, NULL);
+               goto error;
+       }
+       dev->minor = interface->minor;
+
+       /* let the user know what node this device is now attached to */
+       dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major "
+                "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE),
+                USB_MAJOR, dev->minor);
 
 exit:
        return retval;
index 1a812eafe6706955fa7e762611593e90b66af58e..1624b09d974818194b66defad12d5af31bd5c956 100644 (file)
@@ -558,7 +558,6 @@ static void sg_timeout(unsigned long _req)
 {
        struct usb_sg_request   *req = (struct usb_sg_request *) _req;
 
-       req->status = -ETIMEDOUT;
        usb_sg_cancel(req);
 }
 
@@ -589,8 +588,10 @@ static int perform_sglist(
                mod_timer(&sg_timer, jiffies +
                                msecs_to_jiffies(SIMPLE_IO_TIMEOUT));
                usb_sg_wait(req);
-               del_timer_sync(&sg_timer);
-               retval = req->status;
+               if (!del_timer_sync(&sg_timer))
+                       retval = -ETIMEDOUT;
+               else
+                       retval = req->status;
 
                /* FIXME check resulting data pattern */
 
index 59a63a0b79850c7c959f5ef5080de02fb19b1db8..e0a083f6ab68a5d9cd79c5296d58f47d21758a21 100644 (file)
@@ -661,7 +661,7 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
                csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
                csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
        }
-       channel->desired_mode = mode;
+       channel->desired_mode = *mode;
        musb_writew(epio, MUSB_TXCSR, csr);
 
        return 0;
@@ -2008,10 +2008,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                                qh->offset,
                                urb->transfer_buffer_length);
 
-                       done = musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh,
-                                                             urb, xfer_len,
-                                                             iso_err);
-                       if (done)
+                       if (musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh, urb,
+                                                          xfer_len, iso_err))
                                goto finish;
                        else
                                dev_err(musb->controller, "error: rx_dma failed\n");
index f1893e08e51a43649fe71bb2956cd884d4eca4fa..36e5b5c530bdcd39ce17f0990a5827e471d98f91 100644 (file)
@@ -808,20 +808,27 @@ static void xfer_work(struct work_struct *work)
 {
        struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
        struct usbhs_pipe *pipe = pkt->pipe;
-       struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
+       struct usbhs_fifo *fifo;
        struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
        struct dma_async_tx_descriptor *desc;
-       struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
+       struct dma_chan *chan;
        struct device *dev = usbhs_priv_to_dev(priv);
        enum dma_transfer_direction dir;
+       unsigned long flags;
 
+       usbhs_lock(priv, flags);
+       fifo = usbhs_pipe_to_fifo(pipe);
+       if (!fifo)
+               goto xfer_work_end;
+
+       chan = usbhsf_dma_chan_get(fifo, pkt);
        dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
 
        desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual,
                                        pkt->trans, dir,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc)
-               return;
+               goto xfer_work_end;
 
        desc->callback          = usbhsf_dma_complete;
        desc->callback_param    = pipe;
@@ -829,7 +836,7 @@ static void xfer_work(struct work_struct *work)
        pkt->cookie = dmaengine_submit(desc);
        if (pkt->cookie < 0) {
                dev_err(dev, "Failed to submit dma descriptor\n");
-               return;
+               goto xfer_work_end;
        }
 
        dev_dbg(dev, "  %s %d (%d/ %d)\n",
@@ -840,6 +847,9 @@ static void xfer_work(struct work_struct *work)
        usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
        dma_async_issue_pending(chan);
        usbhs_pipe_enable(pipe);
+
+xfer_work_end:
+       usbhs_unlock(priv, flags);
 }
 
 /*
@@ -859,7 +869,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
 
        /* use PIO if packet is less than pio_dma_border or pipe is DCP */
        if ((len < usbhs_get_dparam(priv, pio_dma_border)) ||
-           usbhs_pipe_is_dcp(pipe))
+           usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
                goto usbhsf_pio_prepare_push;
 
        /* check data length if this driver don't use USB-DMAC */
@@ -964,7 +974,7 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt,
 
        /* use PIO if packet is less than pio_dma_border or pipe is DCP */
        if ((pkt->length < usbhs_get_dparam(priv, pio_dma_border)) ||
-           usbhs_pipe_is_dcp(pipe))
+           usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC))
                goto usbhsf_pio_prepare_pop;
 
        fifo = usbhsf_get_dma_fifo(priv, pkt);
index d4be5d5948960cd32353d3007be4373d914be114..28965ef4f824a0117e94fc8c271b347858d0a5e6 100644 (file)
@@ -282,9 +282,16 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
        if (usbhs_mod_is_host(priv))
                usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
 
-       usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
+       /*
+        * The driver should not clear the xxxSTS after the line of
+        * "call irq callback functions" because each "if" statement is
+        * possible to call the callback function for avoiding any side effects.
+        */
+       if (irq_state.intsts0 & BRDY)
+               usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
        usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
-       usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
+       if (irq_state.intsts0 & BEMP)
+               usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
 
        /*
         * call irq callback functions
index fa14198daf77a7d4479566e4d2cfc1845a2c619a..efc4fae123a4c44bbfd53afa334740f148ee89d6 100644 (file)
@@ -586,6 +586,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
        struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
        struct usbhs_pipe *pipe;
        int ret = -EIO;
+       unsigned long flags;
+
+       usbhs_lock(priv, flags);
 
        /*
         * if it already have pipe,
@@ -594,7 +597,8 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
        if (uep->pipe) {
                usbhs_pipe_clear(uep->pipe);
                usbhs_pipe_sequence_data0(uep->pipe);
-               return 0;
+               ret = 0;
+               goto usbhsg_ep_enable_end;
        }
 
        pipe = usbhs_pipe_malloc(priv,
@@ -614,14 +618,20 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
                 * use dmaengine if possible.
                 * It will use pio handler if impossible.
                 */
-               if (usb_endpoint_dir_in(desc))
+               if (usb_endpoint_dir_in(desc)) {
                        pipe->handler = &usbhs_fifo_dma_push_handler;
-               else
+               } else {
                        pipe->handler = &usbhs_fifo_dma_pop_handler;
+                       usbhs_xxxsts_clear(priv, BRDYSTS,
+                                          usbhs_pipe_number(pipe));
+               }
 
                ret = 0;
        }
 
+usbhsg_ep_enable_end:
+       usbhs_unlock(priv, flags);
+
        return ret;
 }
 
@@ -1065,7 +1075,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
 
        gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
        dev_info(dev, "%stransceiver found\n",
-                gpriv->transceiver ? "" : "no ");
+                !IS_ERR(gpriv->transceiver) ? "" : "no ");
 
        /*
         * CAUTION
index a2b43a6e7fa76f78a8150aa9b69a65277d79da8e..6eccded3bc338dcb1940d42a4729d9685458a2d9 100644 (file)
@@ -117,6 +117,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
        { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
+       { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */
        { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
        { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */
        { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
@@ -784,7 +785,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
                } else {
                        modem_ctl[0] &= ~0x7B;
                        modem_ctl[0] |= 0x01;
-                       modem_ctl[1] |= 0x40;
+                       modem_ctl[1] = 0x40;
                        dev_dbg(dev, "%s - flow control = NONE\n", __func__);
                }
 
index b61f12160d37b9ed5bfcd2cfe4e57041d14f5034..8c48c9d83d48c8f3bfa3abc808badc2bedab16c0 100644 (file)
@@ -648,6 +648,8 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_PALMSENS_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_IVIUM_XSTAT_PID) },
        { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
        { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
        { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -1008,6 +1010,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) },
+       { USB_DEVICE(WICED_VID, WICED_USB20706V2_PID) },
        { }                                     /* Terminating entry */
 };
 
index c5d6c1e73e8e0450d46dc7140637146404f262bb..f87a938cf00571eb69edbd8d625f58041384d5fa 100644 (file)
 #define FTDI_4N_GALAXY_DE_2_PID        0xF3C1
 #define FTDI_4N_GALAXY_DE_3_PID        0xF3C2
 
+/*
+ * Ivium Technologies product IDs
+ */
+#define FTDI_PALMSENS_PID      0xf440
+#define FTDI_IVIUM_XSTAT_PID   0xf441
+
 /*
  * Linx Technologies product ids
  */
 #define INTREPID_VALUECAN_PID  0x0601
 #define INTREPID_NEOVI_PID     0x0701
 
+/*
+ * WICED USB UART
+ */
+#define WICED_VID              0x0A5C
+#define WICED_USB20706V2_PID   0x6422
+
 /*
  * Definitions for ID TECH (www.idt-net.com) devices
  */
index 06c7dbc1c8026d7b41fdbaa417da141ce68171c0..63db004af21fc9748b557f91156c62816c90d7c7 100644 (file)
@@ -1252,7 +1252,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
 
        if (urb->transfer_buffer == NULL) {
                urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
-                                              GFP_KERNEL);
+                                              GFP_ATOMIC);
                if (!urb->transfer_buffer)
                        goto exit;
        }
index 8ac9b55f05afb0c7d9c806f7b13773679ff402ac..7f3ddd7ba2cee98af385830226ce52e72ff60a05 100644 (file)
@@ -1340,8 +1340,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        }
 
        if (urb->transfer_buffer == NULL) {
-               urb->transfer_buffer =
-                   kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+               urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+                                              GFP_ATOMIC);
                if (!urb->transfer_buffer)
                        goto exit;
        }
index d96d423d00e6cdc930281f4df71ea81c5fd280bd..9894e341c6ac93953a119c224729881a00682ef9 100644 (file)
@@ -273,6 +273,13 @@ static void option_instat_callback(struct urb *urb);
 #define TELIT_PRODUCT_LE922_USBCFG5            0x1045
 #define TELIT_PRODUCT_LE920                    0x1200
 #define TELIT_PRODUCT_LE910                    0x1201
+#define TELIT_PRODUCT_LE910_USBCFG4            0x1206
+#define TELIT_PRODUCT_LE920A4_1207             0x1207
+#define TELIT_PRODUCT_LE920A4_1208             0x1208
+#define TELIT_PRODUCT_LE920A4_1211             0x1211
+#define TELIT_PRODUCT_LE920A4_1212             0x1212
+#define TELIT_PRODUCT_LE920A4_1213             0x1213
+#define TELIT_PRODUCT_LE920A4_1214             0x1214
 
 /* ZTE PRODUCTS */
 #define ZTE_VENDOR_ID                          0x19d2
@@ -518,6 +525,12 @@ static void option_instat_callback(struct urb *urb);
 #define VIATELECOM_VENDOR_ID                   0x15eb
 #define VIATELECOM_PRODUCT_CDS7                        0x0001
 
+/* WeTelecom products */
+#define WETELECOM_VENDOR_ID                    0x22de
+#define WETELECOM_PRODUCT_WMD200               0x6801
+#define WETELECOM_PRODUCT_6802                 0x6802
+#define WETELECOM_PRODUCT_WMD300               0x6803
+
 struct option_blacklist_info {
        /* bitmask of interface numbers blacklisted for send_setup */
        const unsigned long sendsetup;
@@ -627,6 +640,11 @@ static const struct option_blacklist_info telit_le920_blacklist = {
        .reserved = BIT(1) | BIT(5),
 };
 
+static const struct option_blacklist_info telit_le920a4_blacklist_1 = {
+       .sendsetup = BIT(0),
+       .reserved = BIT(1),
+};
+
 static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = {
        .sendsetup = BIT(2),
        .reserved = BIT(0) | BIT(1) | BIT(3),
@@ -1198,8 +1216,20 @@ static const struct usb_device_id option_ids[] = {
                .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
                .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
+               .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
                .driver_info = (kernel_ulong_t)&telit_le920_blacklist },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1207) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1208),
+               .driver_info = (kernel_ulong_t)&telit_le920a4_blacklist_1 },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1211),
+               .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1212),
+               .driver_info = (kernel_ulong_t)&telit_le920a4_blacklist_1 },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214),
+               .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
@@ -1963,9 +1993,13 @@ static const struct usb_device_id option_ids[] = {
          .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_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },                /* OLICARD300 - MT6225 */
        { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
        { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
+       { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index a204782ae530e1de8f7982f869a94f9b80ce9dad..e98b6e57b703dbd84c3b618fe56dc50eff3fd7ec 100644 (file)
@@ -54,7 +54,8 @@ DEVICE(funsoft, FUNSOFT_IDS);
 /* Infineon Flashloader driver */
 #define FLASHLOADER_IDS()              \
        { USB_DEVICE_INTERFACE_CLASS(0x058b, 0x0041, USB_CLASS_CDC_DATA) }, \
-       { USB_DEVICE(0x8087, 0x0716) }
+       { USB_DEVICE(0x8087, 0x0716) }, \
+       { USB_DEVICE(0x8087, 0x0801) }
 DEVICE(flashloader, FLASHLOADER_IDS);
 
 /* Google Serial USB SubClass */
index 46f1f13b41f1459264e292d36087962f1a666b6f..a0ca291bc07f7377c43deebbccc31f9268f4db35 100644 (file)
@@ -1432,7 +1432,7 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[]
 
        rc = usb_register(udriver);
        if (rc)
-               return rc;
+               goto failed_usb_register;
 
        for (sd = serial_drivers; *sd; ++sd) {
                (*sd)->usb_driver = udriver;
@@ -1450,6 +1450,8 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[]
        while (sd-- > serial_drivers)
                usb_serial_deregister(*sd);
        usb_deregister(udriver);
+failed_usb_register:
+       kfree(udriver);
        return rc;
 }
 EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
index 3b3ba15558b73dbb612228791ae89478644f8096..20e9a86d2dcf62f0e71db1943438440da6f2d3b3 100644 (file)
@@ -563,67 +563,80 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_device *vdev,
 }
 
 static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx,
-                                          uint32_t flags, void *data)
+                                          unsigned int count, uint32_t flags,
+                                          void *data)
 {
-       int32_t fd = *(int32_t *)data;
-
-       if (!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
-               return -EINVAL;
-
        /* DATA_NONE/DATA_BOOL enables loopback testing */
        if (flags & VFIO_IRQ_SET_DATA_NONE) {
-               if (*ctx)
-                       eventfd_signal(*ctx, 1);
-               return 0;
+               if (*ctx) {
+                       if (count) {
+                               eventfd_signal(*ctx, 1);
+                       } else {
+                               eventfd_ctx_put(*ctx);
+                               *ctx = NULL;
+                       }
+                       return 0;
+               }
        } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
-               uint8_t trigger = *(uint8_t *)data;
+               uint8_t trigger;
+
+               if (!count)
+                       return -EINVAL;
+
+               trigger = *(uint8_t *)data;
                if (trigger && *ctx)
                        eventfd_signal(*ctx, 1);
-               return 0;
-       }
 
-       /* Handle SET_DATA_EVENTFD */
-       if (fd == -1) {
-               if (*ctx)
-                       eventfd_ctx_put(*ctx);
-               *ctx = NULL;
                return 0;
-       } else if (fd >= 0) {
-               struct eventfd_ctx *efdctx;
-               efdctx = eventfd_ctx_fdget(fd);
-               if (IS_ERR(efdctx))
-                       return PTR_ERR(efdctx);
-               if (*ctx)
-                       eventfd_ctx_put(*ctx);
-               *ctx = efdctx;
+       } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+               int32_t fd;
+
+               if (!count)
+                       return -EINVAL;
+
+               fd = *(int32_t *)data;
+               if (fd == -1) {
+                       if (*ctx)
+                               eventfd_ctx_put(*ctx);
+                       *ctx = NULL;
+               } else if (fd >= 0) {
+                       struct eventfd_ctx *efdctx;
+
+                       efdctx = eventfd_ctx_fdget(fd);
+                       if (IS_ERR(efdctx))
+                               return PTR_ERR(efdctx);
+
+                       if (*ctx)
+                               eventfd_ctx_put(*ctx);
+
+                       *ctx = efdctx;
+               }
                return 0;
-       } else
-               return -EINVAL;
+       }
+
+       return -EINVAL;
 }
 
 static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
                                    unsigned index, unsigned start,
                                    unsigned count, uint32_t flags, void *data)
 {
-       if (index != VFIO_PCI_ERR_IRQ_INDEX)
+       if (index != VFIO_PCI_ERR_IRQ_INDEX || start != 0 || count > 1)
                return -EINVAL;
 
-       /*
-        * We should sanitize start & count, but that wasn't caught
-        * originally, so this IRQ index must forever ignore them :-(
-        */
-
-       return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, flags, data);
+       return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger,
+                                              count, flags, data);
 }
 
 static int vfio_pci_set_req_trigger(struct vfio_pci_device *vdev,
                                    unsigned index, unsigned start,
                                    unsigned count, uint32_t flags, void *data)
 {
-       if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count != 1)
+       if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count > 1)
                return -EINVAL;
 
-       return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, flags, data);
+       return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger,
+                                              count, flags, data);
 }
 
 int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
index 29cfc57d496e9497ebcf7bd5c5bd07a083bd91dc..e4110d6de0b5785dd3690f59449f322e4a54972b 100644 (file)
@@ -88,7 +88,7 @@ struct vhost_scsi_cmd {
        struct scatterlist *tvc_prot_sgl;
        struct page **tvc_upages;
        /* Pointer to response header iovec */
-       struct iovec *tvc_resp_iov;
+       struct iovec tvc_resp_iov;
        /* Pointer to vhost_scsi for our device */
        struct vhost_scsi *tvc_vhost;
        /* Pointer to vhost_virtqueue for the cmd */
@@ -557,7 +557,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
                memcpy(v_rsp.sense, cmd->tvc_sense_buf,
                       se_cmd->scsi_sense_length);
 
-               iov_iter_init(&iov_iter, READ, cmd->tvc_resp_iov,
+               iov_iter_init(&iov_iter, READ, &cmd->tvc_resp_iov,
                              cmd->tvc_in_iovs, sizeof(v_rsp));
                ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
                if (likely(ret == sizeof(v_rsp))) {
@@ -1054,7 +1054,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                }
                cmd->tvc_vhost = vs;
                cmd->tvc_vq = vq;
-               cmd->tvc_resp_iov = &vq->iov[out];
+               cmd->tvc_resp_iov = vq->iov[out];
                cmd->tvc_in_iovs = in;
 
                pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
index 95d293b7445a83473bc2131cf657f5de14ef52b3..dc2fcda54d53d767d57a6d6c02fd7d383380ebe5 100644 (file)
@@ -52,9 +52,9 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
                return 1;
 
        if (regno < 16) {
-               red   >>= 8;
-               green >>= 8;
-               blue  >>= 8;
+               red   >>= 16 - info->var.red.length;
+               green >>= 16 - info->var.green.length;
+               blue  >>= 16 - info->var.blue.length;
                ((u32 *)(info->pseudo_palette))[regno] =
                        (red   << info->var.red.offset)   |
                        (green << info->var.green.offset) |
index 8ab6238c9299efa92f72a907775e0dd416d82407..56f7e2521202740101a7b1bb982fce83fda71f3e 100644 (file)
@@ -196,6 +196,8 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num)
        num = min(num, ARRAY_SIZE(vb->pfns));
 
        mutex_lock(&vb->balloon_lock);
+       /* We can't release more pages than taken */
+       num = min(num, (size_t)vb->num_pages);
        for (vb->num_pfns = 0; vb->num_pfns < num;
             vb->num_pfns += VIRTIO_BALLOON_PAGES_PER_PAGE) {
                page = balloon_page_dequeue(vb_dev_info);
index ee663c458b20a449c353c5ea0df4632933087e66..dc2b94142f53251560e0734b769f5bf5f7f1feb0 100644 (file)
@@ -202,6 +202,8 @@ static inline int virtqueue_add(struct virtqueue *_vq,
                 * host should service the ring ASAP. */
                if (out_sgs)
                        vq->notify(&vq->vq);
+               if (indirect)
+                       kfree(desc);
                END_USE(vq);
                return -ENOSPC;
        }
index 0e2f43bccf1ffba52d1a7fe60a089ea4da8e3b60..0c427d6a12d144070bbe76823b2ad3df478f8067 100644 (file)
@@ -390,8 +390,6 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
                goto out;
        }
 
-       hdq_data->hdq_irqstatus = 0;
-
        if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
                hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
                        OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
index 9c234209d8b52d44d6483397f33a190fa2899c90..47a4177b16d20cf30f0faece67f975ed9c2b402c 100644 (file)
@@ -183,8 +183,7 @@ int xen_pcibk_config_read(struct pci_dev *dev, int offset, int size,
                field_start = OFFSET(cfg_entry);
                field_end = OFFSET(cfg_entry) + field->size;
 
-               if ((req_start >= field_start && req_start < field_end)
-                   || (req_end > field_start && req_end <= field_end)) {
+                if (req_end > field_start && field_end > req_start) {
                        err = conf_space_read(dev, cfg_entry, field_start,
                                              &tmp_val);
                        if (err)
@@ -230,8 +229,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
                field_start = OFFSET(cfg_entry);
                field_end = OFFSET(cfg_entry) + field->size;
 
-               if ((req_start >= field_start && req_start < field_end)
-                   || (req_end > field_start && req_end <= field_end)) {
+                if (req_end > field_start && field_end > req_start) {
                        tmp_val = 0;
 
                        err = xen_pcibk_config_read(dev, field_start,
index 9433e46518c8dc8680fd1e5a44d823aa7f65fdb0..0e0eb10f82a028c737949a4041a944d9798bb6bf 100644 (file)
@@ -316,11 +316,18 @@ static int xenbus_write_transaction(unsigned msg_type,
                        rc = -ENOMEM;
                        goto out;
                }
+       } else if (msg_type == XS_TRANSACTION_END) {
+               list_for_each_entry(trans, &u->transactions, list)
+                       if (trans->handle.id == u->u.msg.tx_id)
+                               break;
+               if (&trans->list == &u->transactions)
+                       return -ESRCH;
        }
 
        reply = xenbus_dev_request_and_reply(&u->u.msg);
        if (IS_ERR(reply)) {
-               kfree(trans);
+               if (msg_type == XS_TRANSACTION_START)
+                       kfree(trans);
                rc = PTR_ERR(reply);
                goto out;
        }
@@ -333,12 +340,7 @@ static int xenbus_write_transaction(unsigned msg_type,
                        list_add(&trans->list, &u->transactions);
                }
        } else if (u->u.msg.type == XS_TRANSACTION_END) {
-               list_for_each_entry(trans, &u->transactions, list)
-                       if (trans->handle.id == u->u.msg.tx_id)
-                               break;
-               BUG_ON(&trans->list == &u->transactions);
                list_del(&trans->list);
-
                kfree(trans);
        }
 
index ba804f3d8278d945934fd2750f2f6345302fd5cc..ce65591b4168f132f3c0dc1d631b9e0593a86176 100644 (file)
@@ -250,9 +250,6 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
 
        mutex_unlock(&xs_state.request_mutex);
 
-       if (IS_ERR(ret))
-               return ret;
-
        if ((msg->type == XS_TRANSACTION_END) ||
            ((req_msg.type == XS_TRANSACTION_START) &&
             (msg->type == XS_ERROR)))
index a7e28890f5efb4ec8729fc9de4f09e16d4fb91bd..929b618da43bb345cc69699ee96fd00beb358e73 100644 (file)
@@ -282,32 +282,26 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
        switch (handler->flags) {
        case ACL_TYPE_ACCESS:
                if (acl) {
-                       umode_t mode = inode->i_mode;
-                       retval = posix_acl_equiv_mode(acl, &mode);
-                       if (retval < 0)
+                       struct iattr iattr;
+
+                       retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+                       if (retval)
                                goto err_out;
-                       else {
-                               struct iattr iattr;
-                               if (retval == 0) {
-                                       /*
-                                        * ACL can be represented
-                                        * by the mode bits. So don't
-                                        * update ACL.
-                                        */
-                                       acl = NULL;
-                                       value = NULL;
-                                       size = 0;
-                               }
-                               /* Updte the mode bits */
-                               iattr.ia_mode = ((mode & S_IALLUGO) |
-                                                (inode->i_mode & ~S_IALLUGO));
-                               iattr.ia_valid = ATTR_MODE;
-                               /* FIXME should we update ctime ?
-                                * What is the following setxattr update the
-                                * mode ?
+                       if (!acl) {
+                               /*
+                                * ACL can be represented
+                                * by the mode bits. So don't
+                                * update ACL.
                                 */
-                               v9fs_vfs_setattr_dotl(dentry, &iattr);
+                               value = NULL;
+                               size = 0;
                        }
+                       iattr.ia_valid = ATTR_MODE;
+                       /* FIXME should we update ctime ?
+                        * What is the following setxattr update the
+                        * mode ?
+                        */
+                       v9fs_vfs_setattr_dotl(dentry, &iattr);
                }
                break;
        case ACL_TYPE_DEFAULT:
index 7bf835f85bc822ef1119b639be82619af066d326..12ceaf52dae60dfe8dce93ecf9e2677f8d4491f1 100644 (file)
@@ -74,7 +74,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
                                        v9fs_proto_dotu(v9ses));
        fid = file->private_data;
        if (!fid) {
-               fid = v9fs_fid_clone(file->f_path.dentry);
+               fid = v9fs_fid_clone(file_dentry(file));
                if (IS_ERR(fid))
                        return PTR_ERR(fid);
 
@@ -100,7 +100,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
                 * because we want write after unlink usecase
                 * to work.
                 */
-               fid = v9fs_writeback_fid(file->f_path.dentry);
+               fid = v9fs_writeback_fid(file_dentry(file));
                if (IS_ERR(fid)) {
                        err = PTR_ERR(fid);
                        mutex_unlock(&v9inode->v_mutex);
@@ -516,7 +516,7 @@ v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma)
                 * because we want write after unlink usecase
                 * to work.
                 */
-               fid = v9fs_writeback_fid(filp->f_path.dentry);
+               fid = v9fs_writeback_fid(file_dentry(filp));
                if (IS_ERR(fid)) {
                        retval = PTR_ERR(fid);
                        mutex_unlock(&v9inode->v_mutex);
index 155f84253f331a4d9d13ffac3d1ea70322b09b11..fe4f49212b99ac5eb3e8692d07ab3315577ab246 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -239,7 +239,12 @@ static struct dentry *aio_mount(struct file_system_type *fs_type,
        static const struct dentry_operations ops = {
                .d_dname        = simple_dname,
        };
-       return mount_pseudo(fs_type, "aio:", NULL, &ops, AIO_RING_MAGIC);
+       struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, &ops,
+                                          AIO_RING_MAGIC);
+
+       if (!IS_ERR(root))
+               root->d_sb->s_iflags |= SB_I_NOEXEC;
+       return root;
 }
 
 /* aio_setup
index 6530ced19697d49a9189fa289c9112187448fee3..d62f674a605ff687972507ffce003bc08121b81d 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -202,6 +202,21 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
                        return -EPERM;
        }
 
+       /*
+        * If utimes(2) and friends are called with times == NULL (or both
+        * times are UTIME_NOW), then we need to check for write permission
+        */
+       if (ia_valid & ATTR_TOUCH) {
+               if (IS_IMMUTABLE(inode))
+                       return -EPERM;
+
+               if (!inode_owner_or_capable(inode)) {
+                       error = inode_permission(inode, MAY_WRITE);
+                       if (error)
+                               return error;
+               }
+       }
+
        if ((ia_valid & ATTR_MODE)) {
                umode_t amode = attr->ia_mode;
                /* Flag setting protected by i_mutex */
index c37149b929be50442ef40aacc36423eab9b264a2..502d3892d8a45d9268fbeb4bf1c3be848ac55b51 100644 (file)
@@ -79,9 +79,13 @@ struct autofs_info {
 };
 
 #define AUTOFS_INF_EXPIRING    (1<<0) /* dentry is in the process of expiring */
-#define AUTOFS_INF_NO_RCU      (1<<1) /* the dentry is being considered
+#define AUTOFS_INF_WANT_EXPIRE (1<<1) /* the dentry is being considered
                                        * for expiry, so RCU_walk is
-                                       * not permitted
+                                       * not permitted.  If it progresses to
+                                       * actual expiry attempt, the flag is
+                                       * not cleared when EXPIRING is set -
+                                       * in that case it gets cleared only
+                                       * when it comes to clearing EXPIRING.
                                        */
 #define AUTOFS_INF_PENDING     (1<<2) /* dentry pending mount */
 
index 1cebc3c52fa5792242144c939908be50040b9e0b..7a5a598a2d9456db5e1586f5187f663e03d1625d 100644 (file)
@@ -315,19 +315,17 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
        if (ino->flags & AUTOFS_INF_PENDING)
                goto out;
        if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
-               ino->flags |= AUTOFS_INF_NO_RCU;
+               ino->flags |= AUTOFS_INF_WANT_EXPIRE;
                spin_unlock(&sbi->fs_lock);
                synchronize_rcu();
                spin_lock(&sbi->fs_lock);
                if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
                        ino->flags |= AUTOFS_INF_EXPIRING;
-                       smp_mb();
-                       ino->flags &= ~AUTOFS_INF_NO_RCU;
                        init_completion(&ino->expire_complete);
                        spin_unlock(&sbi->fs_lock);
                        return root;
                }
-               ino->flags &= ~AUTOFS_INF_NO_RCU;
+               ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
        }
 out:
        spin_unlock(&sbi->fs_lock);
@@ -417,6 +415,7 @@ static struct dentry *should_expire(struct dentry *dentry,
        }
        return NULL;
 }
+
 /*
  * Find an eligible tree to time-out
  * A tree is eligible if :-
@@ -432,6 +431,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
        struct dentry *root = sb->s_root;
        struct dentry *dentry;
        struct dentry *expired;
+       struct dentry *found;
        struct autofs_info *ino;
 
        if (!root)
@@ -442,48 +442,54 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
 
        dentry = NULL;
        while ((dentry = get_next_positive_subdir(dentry, root))) {
+               int flags = how;
+
                spin_lock(&sbi->fs_lock);
                ino = autofs4_dentry_ino(dentry);
-               if (ino->flags & AUTOFS_INF_NO_RCU)
-                       expired = NULL;
-               else
-                       expired = should_expire(dentry, mnt, timeout, how);
-               if (!expired) {
+               if (ino->flags & AUTOFS_INF_WANT_EXPIRE) {
                        spin_unlock(&sbi->fs_lock);
                        continue;
                }
+               spin_unlock(&sbi->fs_lock);
+
+               expired = should_expire(dentry, mnt, timeout, flags);
+               if (!expired)
+                       continue;
+
+               spin_lock(&sbi->fs_lock);
                ino = autofs4_dentry_ino(expired);
-               ino->flags |= AUTOFS_INF_NO_RCU;
+               ino->flags |= AUTOFS_INF_WANT_EXPIRE;
                spin_unlock(&sbi->fs_lock);
                synchronize_rcu();
-               spin_lock(&sbi->fs_lock);
-               if (should_expire(expired, mnt, timeout, how)) {
-                       if (expired != dentry)
-                               dput(dentry);
-                       goto found;
-               }
 
-               ino->flags &= ~AUTOFS_INF_NO_RCU;
+               /* Make sure a reference is not taken on found if
+                * things have changed.
+                */
+               flags &= ~AUTOFS_EXP_LEAVES;
+               found = should_expire(expired, mnt, timeout, how);
+               if (!found || found != expired)
+                       /* Something has changed, continue */
+                       goto next;
+
                if (expired != dentry)
-                       dput(expired);
+                       dput(dentry);
+
+               spin_lock(&sbi->fs_lock);
+               goto found;
+next:
+               spin_lock(&sbi->fs_lock);
+               ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
                spin_unlock(&sbi->fs_lock);
+               if (expired != dentry)
+                       dput(expired);
        }
        return NULL;
 
 found:
        DPRINTK("returning %p %pd", expired, expired);
        ino->flags |= AUTOFS_INF_EXPIRING;
-       smp_mb();
-       ino->flags &= ~AUTOFS_INF_NO_RCU;
        init_completion(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
-       spin_lock(&sbi->lookup_lock);
-       spin_lock(&expired->d_parent->d_lock);
-       spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
-       list_move(&expired->d_parent->d_subdirs, &expired->d_child);
-       spin_unlock(&expired->d_lock);
-       spin_unlock(&expired->d_parent->d_lock);
-       spin_unlock(&sbi->lookup_lock);
        return expired;
 }
 
@@ -492,15 +498,27 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        int status;
+       int state;
 
        /* Block on any pending expire */
-       if (!(ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU)))
+       if (!(ino->flags & AUTOFS_INF_WANT_EXPIRE))
                return 0;
        if (rcu_walk)
                return -ECHILD;
 
+retry:
        spin_lock(&sbi->fs_lock);
-       if (ino->flags & AUTOFS_INF_EXPIRING) {
+       state = ino->flags & (AUTOFS_INF_WANT_EXPIRE | AUTOFS_INF_EXPIRING);
+       if (state == AUTOFS_INF_WANT_EXPIRE) {
+               spin_unlock(&sbi->fs_lock);
+               /*
+                * Possibly being selected for expire, wait until
+                * it's selected or not.
+                */
+               schedule_timeout_uninterruptible(HZ/10);
+               goto retry;
+       }
+       if (state & AUTOFS_INF_EXPIRING) {
                spin_unlock(&sbi->fs_lock);
 
                DPRINTK("waiting for expire %p name=%pd", dentry, dentry);
@@ -551,7 +569,7 @@ int autofs4_expire_run(struct super_block *sb,
        ino = autofs4_dentry_ino(dentry);
        /* avoid rapid-fire expire attempts if expiry fails */
        ino->last_used = now;
-       ino->flags &= ~AUTOFS_INF_EXPIRING;
+       ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
        complete_all(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
 
@@ -579,7 +597,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
                spin_lock(&sbi->fs_lock);
                /* avoid rapid-fire expire attempts if expiry fails */
                ino->last_used = now;
-               ino->flags &= ~AUTOFS_INF_EXPIRING;
+               ino->flags &= ~(AUTOFS_INF_EXPIRING|AUTOFS_INF_WANT_EXPIRE);
                complete_all(&ino->expire_complete);
                spin_unlock(&sbi->fs_lock);
                dput(dentry);
index c6d7d3dbd52abfa9af11ea0fb7aab955e355bbc9..7a54c6a867c89cc819bb5c0768e75e7b84527259 100644 (file)
@@ -455,7 +455,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
                 * a mount-trap.
                 */
                struct inode *inode;
-               if (ino->flags & (AUTOFS_INF_EXPIRING | AUTOFS_INF_NO_RCU))
+               if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
                        return 0;
                if (d_mountpoint(dentry))
                        return 0;
index 9a0124a95851014c9000ed7822dc5fad0a2f6995..fb3e64d37cb4ca6d2faf4fadefd85b1477a95f2e 100644 (file)
@@ -83,11 +83,9 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       ret = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (ret < 0)
+                       ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                       if (ret)
                                return ret;
-                       if (ret == 0)
-                               acl = NULL;
                }
                ret = 0;
                break;
index c473c42d7d6c4d559dbe1587491cd2fb93804145..bae05c5c75bad4c7f3f8ac74fb38e0b3dca460ac 100644 (file)
@@ -694,7 +694,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                        ret = btrfs_map_bio(root, READ, comp_bio,
                                            mirror_num, 0);
                        if (ret) {
-                               bio->bi_error = ret;
+                               comp_bio->bi_error = ret;
                                bio_endio(comp_bio);
                        }
 
@@ -723,7 +723,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
        if (ret) {
-               bio->bi_error = ret;
+               comp_bio->bi_error = ret;
                bio_endio(comp_bio);
        }
 
index 385b449fd7ed4969d9e408f9ac756217209b48d9..1391f72c28c30f090d7eff406d2dbf1246db60d8 100644 (file)
@@ -1770,6 +1770,7 @@ struct btrfs_fs_info {
        struct btrfs_workqueue *qgroup_rescan_workers;
        struct completion qgroup_rescan_completion;
        struct btrfs_work qgroup_rescan_work;
+       bool qgroup_rescan_running;     /* protected by qgroup_rescan_lock */
 
        /* filesystem state */
        unsigned long fs_state;
index 41fb43183406c944086ca6eefaf10c7f5a35880e..85b207d19aa5336ea0b97e413fb0c1621b9231fb 100644 (file)
@@ -2276,6 +2276,7 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info)
        fs_info->quota_enabled = 0;
        fs_info->pending_quota_state = 0;
        fs_info->qgroup_ulist = NULL;
+       fs_info->qgroup_rescan_running = false;
        mutex_init(&fs_info->qgroup_rescan_lock);
 }
 
@@ -3811,7 +3812,7 @@ void close_ctree(struct btrfs_root *root)
        smp_mb();
 
        /* wait for the qgroup rescan worker to stop */
-       btrfs_qgroup_wait_for_completion(fs_info);
+       btrfs_qgroup_wait_for_completion(fs_info, false);
 
        /* wait for the uuid_scan task to finish */
        down(&fs_info->uuid_tree_rescan_sem);
index 9abe18763a7fb001632246fd712a64fdffcc0225..257bbdcb5df64582236bfc9be9f721f418e957a0 100644 (file)
@@ -2786,12 +2786,6 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
                btrfs_bio->csum = NULL;
                btrfs_bio->csum_allocated = NULL;
                btrfs_bio->end_io = NULL;
-
-#ifdef CONFIG_BLK_CGROUP
-               /* FIXME, put this into bio_clone_bioset */
-               if (bio->bi_css)
-                       bio_associate_blkcg(new, bio->bi_css);
-#endif
        }
        return new;
 }
index 5e5db3687e348a9cfa54e588670637a62081ee9d..353f4bae658c570002e6ea9504443044a238e96e 100644 (file)
@@ -1526,27 +1526,24 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 
                reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
 
-               if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
-                                            BTRFS_INODE_PREALLOC)) {
-                       ret = check_can_nocow(inode, pos, &write_bytes);
-                       if (ret < 0)
-                               break;
-                       if (ret > 0) {
-                               /*
-                                * For nodata cow case, no need to reserve
-                                * data space.
-                                */
-                               only_release_metadata = true;
-                               /*
-                                * our prealloc extent may be smaller than
-                                * write_bytes, so scale down.
-                                */
-                               num_pages = DIV_ROUND_UP(write_bytes + offset,
-                                                        PAGE_CACHE_SIZE);
-                               reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
-                               goto reserve_metadata;
-                       }
+               if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
+                                             BTRFS_INODE_PREALLOC)) &&
+                   check_can_nocow(inode, pos, &write_bytes) > 0) {
+                       /*
+                        * For nodata cow case, no need to reserve
+                        * data space.
+                        */
+                       only_release_metadata = true;
+                       /*
+                        * our prealloc extent may be smaller than
+                        * write_bytes, so scale down.
+                        */
+                       num_pages = DIV_ROUND_UP(write_bytes + offset,
+                                                PAGE_CACHE_SIZE);
+                       reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
+                       goto reserve_metadata;
                }
+
                ret = btrfs_check_data_free_space(inode, pos, write_bytes);
                if (ret < 0)
                        break;
index bfcd87ee8ff543ad6da1d2c8a9da903ef0ad3758..a7e18dbadf748ebaea90da93d982c2369a356833 100644 (file)
@@ -1619,6 +1619,9 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
        int namelen;
        int ret = 0;
 
+       if (!S_ISDIR(file_inode(file)->i_mode))
+               return -ENOTDIR;
+
        ret = mnt_want_write_file(file);
        if (ret)
                goto out;
@@ -1676,6 +1679,9 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
        struct btrfs_ioctl_vol_args *vol_args;
        int ret;
 
+       if (!S_ISDIR(file_inode(file)->i_mode))
+               return -ENOTDIR;
+
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args))
                return PTR_ERR(vol_args);
@@ -1699,6 +1705,9 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
        bool readonly = false;
        struct btrfs_qgroup_inherit *inherit = NULL;
 
+       if (!S_ISDIR(file_inode(file)->i_mode))
+               return -ENOTDIR;
+
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args))
                return PTR_ERR(vol_args);
@@ -2345,6 +2354,9 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        int ret;
        int err = 0;
 
+       if (!S_ISDIR(dir->i_mode))
+               return -ENOTDIR;
+
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args))
                return PTR_ERR(vol_args);
@@ -5121,7 +5133,7 @@ static long btrfs_ioctl_quota_rescan_wait(struct file *file, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       return btrfs_qgroup_wait_for_completion(root->fs_info);
+       return btrfs_qgroup_wait_for_completion(root->fs_info, true);
 }
 
 static long _btrfs_ioctl_set_received_subvol(struct file *file,
index 5279fdae7142fbe3177a556a020ed1af3a7aa8f1..bcc965ed5fa1797a5c57fb9d561033af6d973a68 100644 (file)
@@ -995,7 +995,7 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
                goto out;
        fs_info->quota_enabled = 0;
        fs_info->pending_quota_state = 0;
-       btrfs_qgroup_wait_for_completion(fs_info);
+       btrfs_qgroup_wait_for_completion(fs_info, false);
        spin_lock(&fs_info->qgroup_lock);
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
@@ -2283,6 +2283,10 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
        int err = -ENOMEM;
        int ret = 0;
 
+       mutex_lock(&fs_info->qgroup_rescan_lock);
+       fs_info->qgroup_rescan_running = true;
+       mutex_unlock(&fs_info->qgroup_rescan_lock);
+
        path = btrfs_alloc_path();
        if (!path)
                goto out;
@@ -2349,6 +2353,9 @@ out:
        }
 
 done:
+       mutex_lock(&fs_info->qgroup_rescan_lock);
+       fs_info->qgroup_rescan_running = false;
+       mutex_unlock(&fs_info->qgroup_rescan_lock);
        complete_all(&fs_info->qgroup_rescan_completion);
 }
 
@@ -2467,20 +2474,26 @@ btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info)
        return 0;
 }
 
-int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info)
+int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info,
+                                    bool interruptible)
 {
        int running;
        int ret = 0;
 
        mutex_lock(&fs_info->qgroup_rescan_lock);
        spin_lock(&fs_info->qgroup_lock);
-       running = fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN;
+       running = fs_info->qgroup_rescan_running;
        spin_unlock(&fs_info->qgroup_lock);
        mutex_unlock(&fs_info->qgroup_rescan_lock);
 
-       if (running)
+       if (!running)
+               return 0;
+
+       if (interruptible)
                ret = wait_for_completion_interruptible(
                                        &fs_info->qgroup_rescan_completion);
+       else
+               wait_for_completion(&fs_info->qgroup_rescan_completion);
 
        return ret;
 }
index ecb2c143ef756bd0356e3968b3f9f13fe5ac21cd..3d73e4c9c7df3e6afb65c67f3837635202163ee5 100644 (file)
@@ -46,7 +46,8 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
                        struct btrfs_fs_info *fs_info);
 int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info);
 void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info);
-int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info);
+int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info,
+                                    bool interruptible);
 int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
                              struct btrfs_fs_info *fs_info, u64 src, u64 dst);
 int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
index 0e044d7ee721ec1708def2298fa47f6a359764d6..1415f6d5863342ea35fcaf125b6484a121861b77 100644 (file)
@@ -2850,6 +2850,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) {
                blk_finish_plug(&plug);
+               list_del_init(&root_log_ctx.list);
                mutex_unlock(&log_root_tree->log_mutex);
                ret = root_log_ctx.log_ret;
                goto out;
index 8f84646f10e9560ade100c1dafa180768f1d76de..4d8caeb94a118d339031b79a55c46ba59a537a05 100644 (file)
@@ -94,11 +94,9 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       ret = posix_acl_equiv_mode(acl, &new_mode);
-                       if (ret < 0)
+                       ret = posix_acl_update_mode(inode, &new_mode, &acl);
+                       if (ret)
                                goto out;
-                       if (ret == 0)
-                               acl = NULL;
                }
                break;
        case ACL_TYPE_DEFAULT:
index 3c68e6aee2f0531bdd8afb0125bbae48419d0dfb..c8222bfe1e5669b00874274d2d4ee697d9ee2102 100644 (file)
@@ -929,7 +929,8 @@ again:
                statret = __ceph_do_getattr(inode, page,
                                            CEPH_STAT_CAP_INLINE_DATA, !!page);
                if (statret < 0) {
-                        __free_page(page);
+                       if (page)
+                               __free_page(page);
                        if (statret == -ENODATA) {
                                BUG_ON(retry_op != READ_INLINE);
                                goto again;
index 498dcfa2dcdbedf393ae26fc9f7f68cf90bceb90..d98536c8abfc03adf01c744c33fe014cbda9fabc 100644 (file)
@@ -1358,15 +1358,20 @@ static int fill_readdir_cache(struct inode *dir, struct dentry *dn,
 
        if (!ctl->page || pgoff != page_index(ctl->page)) {
                ceph_readdir_cache_release(ctl);
-               ctl->page  = grab_cache_page(&dir->i_data, pgoff);
+               if (idx == 0)
+                       ctl->page = grab_cache_page(&dir->i_data, pgoff);
+               else
+                       ctl->page = find_lock_page(&dir->i_data, pgoff);
                if (!ctl->page) {
                        ctl->index = -1;
-                       return -ENOMEM;
+                       return idx == 0 ? -ENOMEM : 0;
                }
                /* reading/filling the cache are serialized by
                 * i_mutex, no need to use page lock */
                unlock_page(ctl->page);
                ctl->dentries = kmap(ctl->page);
+               if (idx == 0)
+                       memset(ctl->dentries, 0, PAGE_CACHE_SIZE);
        }
 
        if (req->r_dir_release_cnt == atomic64_read(&ci->i_release_count) &&
index 50b268483302922ee63d205a2fa560ec27676eed..0a3544fb50f920d64d1162dc0947e490251f0c4c 100644 (file)
@@ -152,6 +152,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
        list_for_each(tmp1, &cifs_tcp_ses_list) {
                server = list_entry(tmp1, struct TCP_Server_Info,
                                    tcp_ses_list);
+               seq_printf(m, "\nNumber of credits: %d", server->credits);
                i++;
                list_for_each(tmp2, &server->smb_ses_list) {
                        ses = list_entry(tmp2, struct cifs_ses,
@@ -255,7 +256,6 @@ static const struct file_operations cifs_debug_data_proc_fops = {
 static ssize_t cifs_stats_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *ppos)
 {
-       char c;
        bool bv;
        int rc;
        struct list_head *tmp1, *tmp2, *tmp3;
@@ -263,11 +263,8 @@ static ssize_t cifs_stats_proc_write(struct file *file,
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
 
-       rc = get_user(c, buffer);
-       if (rc)
-               return rc;
-
-       if (strtobool(&c, &bv) == 0) {
+       rc = kstrtobool_from_user(buffer, count, &bv);
+       if (rc == 0) {
 #ifdef CONFIG_CIFS_STATS2
                atomic_set(&totBufAllocCount, 0);
                atomic_set(&totSmBufAllocCount, 0);
@@ -290,6 +287,8 @@ static ssize_t cifs_stats_proc_write(struct file *file,
                        }
                }
                spin_unlock(&cifs_tcp_ses_lock);
+       } else {
+               return rc;
        }
 
        return count;
@@ -433,17 +432,17 @@ static int cifsFYI_proc_open(struct inode *inode, struct file *file)
 static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
                size_t count, loff_t *ppos)
 {
-       char c;
+       char c[2] = { '\0' };
        bool bv;
        int rc;
 
-       rc = get_user(c, buffer);
+       rc = get_user(c[0], buffer);
        if (rc)
                return rc;
-       if (strtobool(&c, &bv) == 0)
+       if (strtobool(c, &bv) == 0)
                cifsFYI = bv;
-       else if ((c > '1') && (c <= '9'))
-               cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
+       else if ((c[0] > '1') && (c[0] <= '9'))
+               cifsFYI = (int) (c[0] - '0'); /* see cifs_debug.h for meanings */
 
        return count;
 }
@@ -471,20 +470,12 @@ static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file)
 static ssize_t cifs_linux_ext_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *ppos)
 {
-       char c;
-       bool bv;
        int rc;
 
-       rc = get_user(c, buffer);
+       rc = kstrtobool_from_user(buffer, count, &linuxExtEnabled);
        if (rc)
                return rc;
 
-       rc = strtobool(&c, &bv);
-       if (rc)
-               return rc;
-
-       linuxExtEnabled = bv;
-
        return count;
 }
 
@@ -511,20 +502,12 @@ static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file)
 static ssize_t cifs_lookup_cache_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *ppos)
 {
-       char c;
-       bool bv;
        int rc;
 
-       rc = get_user(c, buffer);
+       rc = kstrtobool_from_user(buffer, count, &lookupCacheEnabled);
        if (rc)
                return rc;
 
-       rc = strtobool(&c, &bv);
-       if (rc)
-               return rc;
-
-       lookupCacheEnabled = bv;
-
        return count;
 }
 
@@ -551,20 +534,12 @@ static int traceSMB_proc_open(struct inode *inode, struct file *file)
 static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
                size_t count, loff_t *ppos)
 {
-       char c;
-       bool bv;
        int rc;
 
-       rc = get_user(c, buffer);
+       rc = kstrtobool_from_user(buffer, count, &traceSMB);
        if (rc)
                return rc;
 
-       rc = strtobool(&c, &bv);
-       if (rc)
-               return rc;
-
-       traceSMB = bv;
-
        return count;
 }
 
@@ -622,7 +597,6 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
        int rc;
        unsigned int flags;
        char flags_string[12];
-       char c;
        bool bv;
 
        if ((count < 1) || (count > 11))
@@ -635,11 +609,10 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
 
        if (count < 3) {
                /* single char or single char followed by null */
-               c = flags_string[0];
-               if (strtobool(&c, &bv) == 0) {
+               if (strtobool(flags_string, &bv) == 0) {
                        global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
                        return count;
-               } else if (!isdigit(c)) {
+               } else if (!isdigit(flags_string[0])) {
                        cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
                                        flags_string);
                        return -EINVAL;
index 66cf0f9fff8984cb12eed1c89d91bc9c6ccc6a9d..c611ca2339d71e982da848bf1a5c1432d691e53c 100644 (file)
@@ -25,7 +25,7 @@
 void cifs_dump_mem(char *label, void *data, int length);
 void cifs_dump_detail(void *);
 void cifs_dump_mids(struct TCP_Server_Info *);
-extern int traceSMB;           /* flag which enables the function below */
+extern bool traceSMB;          /* flag which enables the function below */
 void dump_smb(void *, int);
 #define CIFS_INFO      0x01
 #define CIFS_RC                0x02
index 3182273a34079e2e7768ec819b39a41006c2e9c9..1418daa03d959f7144f6ae0f0eabb0fdcb1f8d34 100644 (file)
@@ -46,6 +46,9 @@
 #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
 #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
 #define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */
+#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible
+                                             * root mountable
+                                             */
 
 struct cifs_sb_info {
        struct rb_root tlink_tree;
@@ -67,5 +70,6 @@ struct cifs_sb_info {
        struct backing_dev_info bdi;
        struct delayed_work prune_tlinks;
        struct rcu_head rcu;
+       char *prepath;
 };
 #endif                         /* _CIFS_FS_SB_H */
index e682b36a210f236561817bd11a799d3a8f57caf2..4acbc390a7d6b40d3cc9a6ae839ae068493a5bcc 100644 (file)
@@ -731,24 +731,26 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
        memcpy(ses->auth_key.response + baselen, tiblob, tilen);
 
+       mutex_lock(&ses->server->srv_mutex);
+
        rc = crypto_hmacmd5_alloc(ses->server);
        if (rc) {
                cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        /* calculate ntlmv2_hash */
        rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
        if (rc) {
                cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        /* calculate first part of the client response (CR1) */
        rc = CalcNTLMv2_response(ses, ntlmv2_hash);
        if (rc) {
                cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        /* now calculate the session key for NTLMv2 */
@@ -757,13 +759,13 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        if (rc) {
                cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
                         __func__);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
@@ -771,7 +773,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
                CIFS_HMAC_MD5_HASH_SIZE);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
-               goto setup_ntlmv2_rsp_ret;
+               goto unlock;
        }
 
        rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
@@ -779,6 +781,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        if (rc)
                cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
 
+unlock:
+       mutex_unlock(&ses->server->srv_mutex);
 setup_ntlmv2_rsp_ret:
        kfree(tiblob);
 
index cbc0f4bca0c0dfa73b6a545fb6978a72b1a702ef..4f4fc9ff36365faf5826049e3179a8c1d9eed37c 100644 (file)
 #endif
 
 int cifsFYI = 0;
-int traceSMB = 0;
+bool traceSMB;
 bool enable_oplocks = true;
-unsigned int linuxExtEnabled = 1;
-unsigned int lookupCacheEnabled = 1;
+bool linuxExtEnabled = true;
+bool lookupCacheEnabled = true;
 unsigned int global_secflags = CIFSSEC_DEF;
 /* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
@@ -268,7 +268,7 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->createtime = 0;
        cifs_inode->epoch = 0;
 #ifdef CONFIG_CIFS_SMB2
-       get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
+       generate_random_uuid(cifs_inode->lease_key);
 #endif
        /*
         * Can not set i_flags here - they get immediately overwritten to zero
@@ -686,6 +686,14 @@ cifs_do_mount(struct file_system_type *fs_type,
                goto out_cifs_sb;
        }
 
+       if (volume_info->prepath) {
+               cifs_sb->prepath = kstrdup(volume_info->prepath, GFP_KERNEL);
+               if (cifs_sb->prepath == NULL) {
+                       root = ERR_PTR(-ENOMEM);
+                       goto out_cifs_sb;
+               }
+       }
+
        cifs_setup_cifs_sb(volume_info, cifs_sb);
 
        rc = cifs_mount(cifs_sb, volume_info);
@@ -724,7 +732,11 @@ cifs_do_mount(struct file_system_type *fs_type,
                sb->s_flags |= MS_ACTIVE;
        }
 
-       root = cifs_get_root(volume_info, sb);
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+               root = dget(sb->s_root);
+       else
+               root = cifs_get_root(volume_info, sb);
+
        if (IS_ERR(root))
                goto out_super;
 
@@ -1198,7 +1210,6 @@ init_cifs(void)
        GlobalTotalActiveXid = 0;
        GlobalMaxActiveXid = 0;
        spin_lock_init(&cifs_tcp_ses_lock);
-       spin_lock_init(&cifs_file_list_lock);
        spin_lock_init(&GlobalMid_Lock);
 
        if (cifs_max_pending < 2) {
index 2b510c537a0d588c532fe9200cdd4a9b03a4c9f4..c669a1471395e329aa7801d966597c9c0649ba93 100644 (file)
@@ -827,6 +827,7 @@ struct cifs_tcon {
        struct list_head tcon_list;
        int tc_count;
        struct list_head openFileList;
+       spinlock_t open_file_lock; /* protects list above */
        struct cifs_ses *ses;   /* pointer to session associated with */
        char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
        char *nativeFileSystem;
@@ -883,7 +884,7 @@ struct cifs_tcon {
 #endif /* CONFIG_CIFS_STATS2 */
        __u64    bytes_read;
        __u64    bytes_written;
-       spinlock_t stat_lock;
+       spinlock_t stat_lock;  /* protects the two fields above */
 #endif /* CONFIG_CIFS_STATS */
        FILE_SYSTEM_DEVICE_INFO fsDevInfo;
        FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
@@ -1034,8 +1035,10 @@ struct cifs_fid_locks {
 };
 
 struct cifsFileInfo {
+       /* following two lists are protected by tcon->open_file_lock */
        struct list_head tlist; /* pointer to next fid owned by tcon */
        struct list_head flist; /* next fid (file instance) for this inode */
+       /* lock list below protected by cifsi->lock_sem */
        struct cifs_fid_locks *llist;   /* brlocks held by this fid */
        kuid_t uid;             /* allows finding which FileInfo structure */
        __u32 pid;              /* process id who opened file */
@@ -1043,11 +1046,12 @@ struct cifsFileInfo {
        /* BB add lock scope info here if needed */ ;
        /* lock scope id (0 if none) */
        struct dentry *dentry;
-       unsigned int f_flags;
        struct tcon_link *tlink;
+       unsigned int f_flags;
        bool invalidHandle:1;   /* file closed via session abend */
        bool oplock_break_cancelled:1;
-       int count;              /* refcount protected by cifs_file_list_lock */
+       int count;
+       spinlock_t file_info_lock; /* protects four flag/count fields above */
        struct mutex fh_mutex; /* prevents reopen race after dead ses*/
        struct cifs_search_info srch_inf;
        struct work_struct oplock_break; /* work for oplock breaks */
@@ -1114,7 +1118,7 @@ struct cifs_writedata {
 
 /*
  * Take a reference on the file private data. Must be called with
- * cifs_file_list_lock held.
+ * cfile->file_info_lock held.
  */
 static inline void
 cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
@@ -1508,8 +1512,10 @@ require use of the stronger protocol */
  *  GlobalMid_Lock protects:
  *     list operations on pending_mid_q and oplockQ
  *      updates to XID counters, multiplex id  and SMB sequence numbers
- *  cifs_file_list_lock protects:
- *     list operations on tcp and SMB session lists and tCon lists
+ *  tcp_ses_lock protects:
+ *     list operations on tcp and SMB session lists
+ *  tcon->open_file_lock protects the list of open files hanging off the tcon
+ *  cfile->file_info_lock protects counters and fields in cifs file struct
  *  f_owner.lock protects certain per file struct operations
  *  mapping->page_lock protects certain per page operations
  *
@@ -1541,18 +1547,12 @@ GLOBAL_EXTERN struct list_head          cifs_tcp_ses_list;
  * tcp session, and the list of tcon's per smb session. It also protects
  * the reference counters for the server, smb session, and tcon. Finally,
  * changes to the tcon->tidStatus should be done while holding this lock.
+ * generally the locks should be taken in order tcp_ses_lock before
+ * tcon->open_file_lock and that before file->file_info_lock since the
+ * structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file
  */
 GLOBAL_EXTERN spinlock_t               cifs_tcp_ses_lock;
 
-/*
- * This lock protects the cifs_file->llist and cifs_file->flist
- * list operations, and updates to some flags (cifs_file->invalidHandle)
- * It will be moved to either use the tcon->stat_lock or equivalent later.
- * If cifs_tcp_ses_lock and the lock below are both needed to be held, then
- * the cifs_tcp_ses_lock must be grabbed first and released last.
- */
-GLOBAL_EXTERN spinlock_t       cifs_file_list_lock;
-
 #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
 /* Outstanding dir notify requests */
 GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
@@ -1588,11 +1588,11 @@ GLOBAL_EXTERN atomic_t midCount;
 
 /* Misc globals */
 GLOBAL_EXTERN bool enable_oplocks; /* enable or disable oplocks */
-GLOBAL_EXTERN unsigned int lookupCacheEnabled;
+GLOBAL_EXTERN bool lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int global_secflags;    /* if on, session setup sent
                                with more secure ntlmssp2 challenge/resp */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
-GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
+GLOBAL_EXTERN bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
index 76fcb50295a38b63a58a0d3f656d023e02b988a8..b1104ed8f54c042177061166da7c3088307b1fb3 100644 (file)
@@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
        struct list_head *tmp1;
 
        /* list all files open on tree connection and mark them invalid */
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tcon->open_file_lock);
        list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
                open_file = list_entry(tmp, struct cifsFileInfo, tlist);
                open_file->invalidHandle = true;
                open_file->oplock_break_cancelled = true;
        }
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tcon->open_file_lock);
        /*
         * BB Add call to invalidate_inodes(sb) for all superblocks mounted
         * to this tcon.
index 5481a6eb9a958090b7ca65ffb5eca09746ee66e8..812a8cb07c632b855c7e4deee62d3b1eaf626e3f 100644 (file)
@@ -2200,7 +2200,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
                sizeof(tcp_ses->dstaddr));
 #ifdef CONFIG_CIFS_SMB2
-       get_random_bytes(tcp_ses->client_guid, SMB2_CLIENT_GUID_SIZE);
+       generate_random_uuid(tcp_ses->client_guid);
 #endif
        /*
         * at this point we are the only ones with the pointer
@@ -3517,6 +3517,44 @@ cifs_get_volume_info(char *mount_data, const char *devname)
        return volume_info;
 }
 
+static int
+cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
+                                       unsigned int xid,
+                                       struct cifs_tcon *tcon,
+                                       struct cifs_sb_info *cifs_sb,
+                                       char *full_path)
+{
+       int rc;
+       char *s;
+       char sep, tmp;
+
+       sep = CIFS_DIR_SEP(cifs_sb);
+       s = full_path;
+
+       rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
+       while (rc == 0) {
+               /* skip separators */
+               while (*s == sep)
+                       s++;
+               if (!*s)
+                       break;
+               /* next separator */
+               while (*s && *s != sep)
+                       s++;
+
+               /*
+                * temporarily null-terminate the path at the end of
+                * the current component
+                */
+               tmp = *s;
+               *s = 0;
+               rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
+                                                    full_path);
+               *s = tmp;
+       }
+       return rc;
+}
+
 int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
@@ -3654,6 +3692,18 @@ remote_path_check:
                        kfree(full_path);
                        goto mount_fail_check;
                }
+
+               if (rc != -EREMOTE) {
+                       rc = cifs_are_all_path_components_accessible(server,
+                                                            xid, tcon, cifs_sb,
+                                                            full_path);
+                       if (rc != 0) {
+                               cifs_dbg(VFS, "cannot query dirs between root and final path, "
+                                        "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
+                               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
+                               rc = 0;
+                       }
+               }
                kfree(full_path);
        }
 
@@ -3923,6 +3973,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
 
        bdi_destroy(&cifs_sb->bdi);
        kfree(cifs_sb->mountdata);
+       kfree(cifs_sb->prepath);
        call_rcu(&cifs_sb->rcu, delayed_free);
 }
 
index c3eb998a99bd18a2ed9b7b843c99be15fedab9df..26a3b389a265b7bb5eac182b51a5bfbedb14e114 100644 (file)
@@ -84,6 +84,7 @@ build_path_from_dentry(struct dentry *direntry)
        struct dentry *temp;
        int namelen;
        int dfsplen;
+       int pplen = 0;
        char *full_path;
        char dirsep;
        struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
@@ -95,8 +96,12 @@ build_path_from_dentry(struct dentry *direntry)
                dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
        else
                dfsplen = 0;
+
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+               pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
+
 cifs_bp_rename_retry:
-       namelen = dfsplen;
+       namelen = dfsplen + pplen;
        seq = read_seqbegin(&rename_lock);
        rcu_read_lock();
        for (temp = direntry; !IS_ROOT(temp);) {
@@ -137,7 +142,7 @@ cifs_bp_rename_retry:
                }
        }
        rcu_read_unlock();
-       if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
+       if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
                cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
                         namelen, dfsplen);
                /* presumably this is only possible if racing with a rename
@@ -153,6 +158,17 @@ cifs_bp_rename_retry:
           those safely to '/' if any are found in the middle of the prepath */
        /* BB test paths to Windows with '/' in the midst of prepath */
 
+       if (pplen) {
+               int i;
+
+               cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
+               memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
+               full_path[dfsplen] = '\\';
+               for (i = 0; i < pplen-1; i++)
+                       if (full_path[dfsplen+1+i] == '/')
+                               full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
+       }
+
        if (dfsplen) {
                strncpy(full_path, tcon->treeName, dfsplen);
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
@@ -229,6 +245,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
                                goto cifs_create_get_file_info;
                        }
 
+                       if (S_ISDIR(newinode->i_mode)) {
+                               CIFSSMBClose(xid, tcon, fid->netfid);
+                               iput(newinode);
+                               rc = -EISDIR;
+                               goto out;
+                       }
+
                        if (!S_ISREG(newinode->i_mode)) {
                                /*
                                 * The server may allow us to open things like
@@ -399,10 +422,14 @@ cifs_create_set_dentry:
        if (rc != 0) {
                cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n",
                         rc);
-               if (server->ops->close)
-                       server->ops->close(xid, tcon, fid);
-               goto out;
+               goto out_err;
        }
+
+       if (S_ISDIR(newinode->i_mode)) {
+               rc = -EISDIR;
+               goto out_err;
+       }
+
        d_drop(direntry);
        d_add(direntry, newinode);
 
@@ -410,6 +437,13 @@ out:
        kfree(buf);
        kfree(full_path);
        return rc;
+
+out_err:
+       if (server->ops->close)
+               server->ops->close(xid, tcon, fid);
+       if (newinode)
+               iput(newinode);
+       goto out;
 }
 
 int
index 0068e82217c3f98b1fa5fbc4e95926ae52182a6e..72f270d4bd17946526f202b209f456305049b5df 100644 (file)
@@ -305,6 +305,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
        cfile->tlink = cifs_get_tlink(tlink);
        INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
        mutex_init(&cfile->fh_mutex);
+       spin_lock_init(&cfile->file_info_lock);
 
        cifs_sb_active(inode->i_sb);
 
@@ -317,7 +318,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
                oplock = 0;
        }
 
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tcon->open_file_lock);
        if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
                oplock = fid->pending_open->oplock;
        list_del(&fid->pending_open->olist);
@@ -326,12 +327,13 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
        server->ops->set_fid(cfile, fid, oplock);
 
        list_add(&cfile->tlist, &tcon->openFileList);
+
        /* if readable file instance put first in list*/
        if (file->f_mode & FMODE_READ)
                list_add(&cfile->flist, &cinode->openFileList);
        else
                list_add_tail(&cfile->flist, &cinode->openFileList);
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tcon->open_file_lock);
 
        if (fid->purge_cache)
                cifs_zap_mapping(inode);
@@ -343,16 +345,16 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
 struct cifsFileInfo *
 cifsFileInfo_get(struct cifsFileInfo *cifs_file)
 {
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&cifs_file->file_info_lock);
        cifsFileInfo_get_locked(cifs_file);
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&cifs_file->file_info_lock);
        return cifs_file;
 }
 
 /*
  * Release a reference on the file private data. This may involve closing
  * the filehandle out on the server. Must be called without holding
- * cifs_file_list_lock.
+ * tcon->open_file_lock and cifs_file->file_info_lock.
  */
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
@@ -367,11 +369,15 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        struct cifs_pending_open open;
        bool oplock_break_cancelled;
 
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tcon->open_file_lock);
+
+       spin_lock(&cifs_file->file_info_lock);
        if (--cifs_file->count > 0) {
-               spin_unlock(&cifs_file_list_lock);
+               spin_unlock(&cifs_file->file_info_lock);
+               spin_unlock(&tcon->open_file_lock);
                return;
        }
+       spin_unlock(&cifs_file->file_info_lock);
 
        if (server->ops->get_lease_key)
                server->ops->get_lease_key(inode, &fid);
@@ -395,7 +401,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
                        set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
                cifs_set_oplock_level(cifsi, 0);
        }
-       spin_unlock(&cifs_file_list_lock);
+
+       spin_unlock(&tcon->open_file_lock);
 
        oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
 
@@ -772,10 +779,10 @@ int cifs_closedir(struct inode *inode, struct file *file)
        server = tcon->ses->server;
 
        cifs_dbg(FYI, "Freeing private data in close dir\n");
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&cfile->file_info_lock);
        if (server->ops->dir_needs_close(cfile)) {
                cfile->invalidHandle = true;
-               spin_unlock(&cifs_file_list_lock);
+               spin_unlock(&cfile->file_info_lock);
                if (server->ops->close_dir)
                        rc = server->ops->close_dir(xid, tcon, &cfile->fid);
                else
@@ -784,7 +791,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
                /* not much we can do if it fails anyway, ignore rc */
                rc = 0;
        } else
-               spin_unlock(&cifs_file_list_lock);
+               spin_unlock(&cfile->file_info_lock);
 
        buf = cfile->srch_inf.ntwrk_buf_start;
        if (buf) {
@@ -1720,12 +1727,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
 {
        struct cifsFileInfo *open_file = NULL;
        struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 
        /* only filter by fsuid on multiuser mounts */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
 
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tcon->open_file_lock);
        /* we could simply get the first_list_entry since write-only entries
           are always at the end of the list but since the first entry might
           have a close pending, we go through the whole list */
@@ -1736,8 +1744,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
                        if (!open_file->invalidHandle) {
                                /* found a good file */
                                /* lock it so it will not be closed on us */
-                               cifsFileInfo_get_locked(open_file);
-                               spin_unlock(&cifs_file_list_lock);
+                               cifsFileInfo_get(open_file);
+                               spin_unlock(&tcon->open_file_lock);
                                return open_file;
                        } /* else might as well continue, and look for
                             another, or simply have the caller reopen it
@@ -1745,7 +1753,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
                } else /* write only file */
                        break; /* write only files are last so must be done */
        }
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tcon->open_file_lock);
        return NULL;
 }
 
@@ -1754,6 +1762,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
 {
        struct cifsFileInfo *open_file, *inv_file = NULL;
        struct cifs_sb_info *cifs_sb;
+       struct cifs_tcon *tcon;
        bool any_available = false;
        int rc;
        unsigned int refind = 0;
@@ -1769,15 +1778,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
        }
 
        cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+       tcon = cifs_sb_master_tcon(cifs_sb);
 
        /* only filter by fsuid on multiuser mounts */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
 
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tcon->open_file_lock);
 refind_writable:
        if (refind > MAX_REOPEN_ATT) {
-               spin_unlock(&cifs_file_list_lock);
+               spin_unlock(&tcon->open_file_lock);
                return NULL;
        }
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
@@ -1788,8 +1798,8 @@ refind_writable:
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
                        if (!open_file->invalidHandle) {
                                /* found a good writable file */
-                               cifsFileInfo_get_locked(open_file);
-                               spin_unlock(&cifs_file_list_lock);
+                               cifsFileInfo_get(open_file);
+                               spin_unlock(&tcon->open_file_lock);
                                return open_file;
                        } else {
                                if (!inv_file)
@@ -1805,24 +1815,24 @@ refind_writable:
 
        if (inv_file) {
                any_available = false;
-               cifsFileInfo_get_locked(inv_file);
+               cifsFileInfo_get(inv_file);
        }
 
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tcon->open_file_lock);
 
        if (inv_file) {
                rc = cifs_reopen_file(inv_file, false);
                if (!rc)
                        return inv_file;
                else {
-                       spin_lock(&cifs_file_list_lock);
+                       spin_lock(&tcon->open_file_lock);
                        list_move_tail(&inv_file->flist,
                                        &cifs_inode->openFileList);
-                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&tcon->open_file_lock);
                        cifsFileInfo_put(inv_file);
-                       spin_lock(&cifs_file_list_lock);
                        ++refind;
                        inv_file = NULL;
+                       spin_lock(&tcon->open_file_lock);
                        goto refind_writable;
                }
        }
@@ -3632,15 +3642,17 @@ static int cifs_readpage(struct file *file, struct page *page)
 static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
 {
        struct cifsFileInfo *open_file;
+       struct cifs_tcon *tcon =
+               cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
 
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tcon->open_file_lock);
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
-                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&tcon->open_file_lock);
                        return 1;
                }
        }
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tcon->open_file_lock);
        return 0;
 }
 
index a329f5ba35aad8649ce3f644b9b11913c57cc5f8..9cdeb0293267512c08296b520e7ee25110af8822 100644 (file)
@@ -982,10 +982,26 @@ struct inode *cifs_root_iget(struct super_block *sb)
        struct inode *inode = NULL;
        long rc;
        struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       char *path = NULL;
+       int len;
+
+       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
+           && cifs_sb->prepath) {
+               len = strlen(cifs_sb->prepath);
+               path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
+               if (path == NULL)
+                       return ERR_PTR(-ENOMEM);
+               path[0] = '/';
+               memcpy(path+1, cifs_sb->prepath, len);
+       } else {
+               path = kstrdup("", GFP_KERNEL);
+               if (path == NULL)
+                       return ERR_PTR(-ENOMEM);
+       }
 
        xid = get_xid();
        if (tcon->unix_ext) {
-               rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
+               rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
                /* some servers mistakenly claim POSIX support */
                if (rc != -EOPNOTSUPP)
                        goto iget_no_retry;
@@ -993,7 +1009,8 @@ struct inode *cifs_root_iget(struct super_block *sb)
                tcon->unix_ext = false;
        }
 
-       rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
+       convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
+       rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
 
 iget_no_retry:
        if (!inode) {
@@ -1022,6 +1039,7 @@ iget_no_retry:
        }
 
 out:
+       kfree(path);
        /* can not call macro free_xid here since in a void func
         * TODO: This is no longer true
         */
index 8442b8b8e0be145e7f68055e0025f1909442d156..2396ab099849a132d884d79202a5d5bae0ea9a18 100644 (file)
@@ -120,6 +120,7 @@ tconInfoAlloc(void)
                ++ret_buf->tc_count;
                INIT_LIST_HEAD(&ret_buf->openFileList);
                INIT_LIST_HEAD(&ret_buf->tcon_list);
+               spin_lock_init(&ret_buf->open_file_lock);
 #ifdef CONFIG_CIFS_STATS
                spin_lock_init(&ret_buf->stat_lock);
 #endif
@@ -465,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
                                continue;
 
                        cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
-                       spin_lock(&cifs_file_list_lock);
+                       spin_lock(&tcon->open_file_lock);
                        list_for_each(tmp2, &tcon->openFileList) {
                                netfile = list_entry(tmp2, struct cifsFileInfo,
                                                     tlist);
@@ -495,11 +496,11 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
                                           &netfile->oplock_break);
                                netfile->oplock_break_cancelled = false;
 
-                               spin_unlock(&cifs_file_list_lock);
+                               spin_unlock(&tcon->open_file_lock);
                                spin_unlock(&cifs_tcp_ses_lock);
                                return true;
                        }
-                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&tcon->open_file_lock);
                        spin_unlock(&cifs_tcp_ses_lock);
                        cifs_dbg(FYI, "No matching file for oplock break\n");
                        return true;
@@ -613,9 +614,9 @@ backup_cred(struct cifs_sb_info *cifs_sb)
 void
 cifs_del_pending_open(struct cifs_pending_open *open)
 {
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
        list_del(&open->olist);
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
 }
 
 void
@@ -635,7 +636,7 @@ void
 cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
                      struct cifs_pending_open *open)
 {
-       spin_lock(&cifs_file_list_lock);
+       spin_lock(&tlink_tcon(tlink)->open_file_lock);
        cifs_add_pending_open_locked(fid, tlink, open);
-       spin_unlock(&cifs_file_list_lock);
+       spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
 }
index b30a4a6d98a0f002c235bf3128012aff06ba2bc3..833e5844a2dbbc207b59d8a6727f5d255e16e5cb 100644 (file)
@@ -594,14 +594,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
             is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
                /* close and restart search */
                cifs_dbg(FYI, "search backing up - close and restart search\n");
-               spin_lock(&cifs_file_list_lock);
+               spin_lock(&cfile->file_info_lock);
                if (server->ops->dir_needs_close(cfile)) {
                        cfile->invalidHandle = true;
-                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&cfile->file_info_lock);
                        if (server->ops->close_dir)
                                server->ops->close_dir(xid, tcon, &cfile->fid);
                } else
-                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&cfile->file_info_lock);
                if (cfile->srch_inf.ntwrk_buf_start) {
                        cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n");
                        if (cfile->srch_inf.smallBuf)
index 0ffa180943357c5514b5ae025f61e4b19f574f38..238759c146badd9eddc372e31c558ec948647343 100644 (file)
 /* Maximum buffer size value we can send with 1 credit */
 #define SMB2_MAX_BUFFER_SIZE 65536
 
+/*
+ * Maximum number of credits to keep available.
+ * This value is chosen somewhat arbitrarily. The Windows client
+ * defaults to 128 credits, the Windows server allows clients up to
+ * 512 credits, and the NetApp server does not limit clients at all.
+ * Choose a high enough value such that the client shouldn't limit
+ * performance.
+ */
+#define SMB2_MAX_CREDITS_AVAILABLE 32000
+
 #endif /* _SMB2_GLOB_H */
index 4f0231e685a922efcb97a6c5905bfedc7ca7ece6..1238cd3552f9cc8e8f8fc560117af37cd224aa13 100644 (file)
@@ -266,9 +266,15 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
        struct tcon_link *tlink;
        int rc;
 
+       if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
+           (buf->LastWriteTime == 0) && (buf->ChangeTime) &&
+           (buf->Attributes == 0))
+               return 0; /* would be a no op, no sense sending this */
+
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
+
        rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
                                FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, buf,
                                SMB2_OP_SET_INFO);
index 1c5907019045517ac302daf4c04e8caea21f1fda..e5bc85e49be713d9148341a0339da234fc6d588e 100644 (file)
@@ -525,19 +525,19 @@ smb2_is_valid_lease_break(char *buffer)
                list_for_each(tmp1, &server->smb_ses_list) {
                        ses = list_entry(tmp1, struct cifs_ses, smb_ses_list);
 
-                       spin_lock(&cifs_file_list_lock);
                        list_for_each(tmp2, &ses->tcon_list) {
                                tcon = list_entry(tmp2, struct cifs_tcon,
                                                  tcon_list);
+                               spin_lock(&tcon->open_file_lock);
                                cifs_stats_inc(
                                    &tcon->stats.cifs_stats.num_oplock_brks);
                                if (smb2_tcon_has_lease(tcon, rsp, lw)) {
-                                       spin_unlock(&cifs_file_list_lock);
+                                       spin_unlock(&tcon->open_file_lock);
                                        spin_unlock(&cifs_tcp_ses_lock);
                                        return true;
                                }
+                               spin_unlock(&tcon->open_file_lock);
                        }
-                       spin_unlock(&cifs_file_list_lock);
                }
        }
        spin_unlock(&cifs_tcp_ses_lock);
@@ -579,7 +579,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
                        tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
 
                        cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
-                       spin_lock(&cifs_file_list_lock);
+                       spin_lock(&tcon->open_file_lock);
                        list_for_each(tmp2, &tcon->openFileList) {
                                cfile = list_entry(tmp2, struct cifsFileInfo,
                                                     tlist);
@@ -591,7 +591,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 
                                cifs_dbg(FYI, "file id match, oplock break\n");
                                cinode = CIFS_I(d_inode(cfile->dentry));
-
+                               spin_lock(&cfile->file_info_lock);
                                if (!CIFS_CACHE_WRITE(cinode) &&
                                    rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
                                        cfile->oplock_break_cancelled = true;
@@ -613,14 +613,14 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
                                        clear_bit(
                                           CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
                                           &cinode->flags);
-
+                               spin_unlock(&cfile->file_info_lock);
                                queue_work(cifsiod_wq, &cfile->oplock_break);
 
-                               spin_unlock(&cifs_file_list_lock);
+                               spin_unlock(&tcon->open_file_lock);
                                spin_unlock(&cifs_tcp_ses_lock);
                                return true;
                        }
-                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&tcon->open_file_lock);
                        spin_unlock(&cifs_tcp_ses_lock);
                        cifs_dbg(FYI, "No matching file for oplock break\n");
                        return true;
index 53ccdde6ff187c16084e10dd07372d6516d25139..be34b4860675f046cf8a475393eb994fe52f9fda 100644 (file)
@@ -282,7 +282,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
                cifs_dbg(FYI, "Link Speed %lld\n",
                        le64_to_cpu(out_buf->LinkSpeed));
        }
-
+       kfree(out_buf);
        return rc;
 }
 #endif /* STATS2 */
@@ -536,6 +536,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
        server->ops->set_oplock_level(cinode, oplock, fid->epoch,
                                      &fid->purge_cache);
        cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
+       memcpy(cfile->fid.create_guid, fid->create_guid, 16);
 }
 
 static void
@@ -694,6 +695,7 @@ smb2_clone_range(const unsigned int xid,
 
 cchunk_out:
        kfree(pcchunk);
+       kfree(retbuf);
        return rc;
 }
 
@@ -818,7 +820,6 @@ smb2_duplicate_extents(const unsigned int xid,
 {
        int rc;
        unsigned int ret_data_len;
-       char *retbuf = NULL;
        struct duplicate_extents_to_file dup_ext_buf;
        struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
 
@@ -844,7 +845,7 @@ smb2_duplicate_extents(const unsigned int xid,
                        FSCTL_DUPLICATE_EXTENTS_TO_FILE,
                        true /* is_fsctl */, (char *)&dup_ext_buf,
                        sizeof(struct duplicate_extents_to_file),
-                       (char **)&retbuf,
+                       NULL,
                        &ret_data_len);
 
        if (ret_data_len > 0)
@@ -867,7 +868,6 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
                   struct cifsFileInfo *cfile)
 {
        struct fsctl_set_integrity_information_req integr_info;
-       char *retbuf = NULL;
        unsigned int ret_data_len;
 
        integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED);
@@ -879,7 +879,7 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
                        FSCTL_SET_INTEGRITY_INFORMATION,
                        true /* is_fsctl */, (char *)&integr_info,
                        sizeof(struct fsctl_set_integrity_information_req),
-                       (char **)&retbuf,
+                       NULL,
                        &ret_data_len);
 
 }
@@ -1036,9 +1036,12 @@ smb2_set_lease_key(struct inode *inode, struct cifs_fid *fid)
 static void
 smb2_new_lease_key(struct cifs_fid *fid)
 {
-       get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
+       generate_random_uuid(fid->lease_key);
 }
 
+#define SMB2_SYMLINK_STRUCT_SIZE \
+       (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
+
 static int
 smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
                   const char *full_path, char **target_path,
@@ -1051,7 +1054,10 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_fid fid;
        struct smb2_err_rsp *err_buf = NULL;
        struct smb2_symlink_err_rsp *symlink;
-       unsigned int sub_len, sub_offset;
+       unsigned int sub_len;
+       unsigned int sub_offset;
+       unsigned int print_len;
+       unsigned int print_offset;
 
        cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
 
@@ -1072,11 +1078,33 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
                kfree(utf16_path);
                return -ENOENT;
        }
+
+       if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
+           get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+
        /* open must fail on symlink - reset rc */
        rc = 0;
        symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
        sub_len = le16_to_cpu(symlink->SubstituteNameLength);
        sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
+       print_len = le16_to_cpu(symlink->PrintNameLength);
+       print_offset = le16_to_cpu(symlink->PrintNameOffset);
+
+       if (get_rfc1002_length(err_buf) + 4 <
+                       SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+
+       if (get_rfc1002_length(err_buf) + 4 <
+                       SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+
        *target_path = cifs_strndup_from_utf16(
                                (char *)symlink->PathBuffer + sub_offset,
                                sub_len, true, cifs_sb->local_nls);
index 0b6dc1942bdcccae62b0bba199f9c166fac7e3d1..0dbbdf5e4aeeb2fc56e7a9d4df235c18c188430e 100644 (file)
@@ -103,7 +103,21 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
        hdr->ProtocolId[3] = 'B';
        hdr->StructureSize = cpu_to_le16(64);
        hdr->Command = smb2_cmd;
-       hdr->CreditRequest = cpu_to_le16(2); /* BB make this dynamic */
+       if (tcon && tcon->ses && tcon->ses->server) {
+               struct TCP_Server_Info *server = tcon->ses->server;
+
+               spin_lock(&server->req_lock);
+               /* Request up to 2 credits but don't go over the limit. */
+               if (server->credits >= SMB2_MAX_CREDITS_AVAILABLE)
+                       hdr->CreditRequest = cpu_to_le16(0);
+               else
+                       hdr->CreditRequest = cpu_to_le16(
+                               min_t(int, SMB2_MAX_CREDITS_AVAILABLE -
+                                               server->credits, 2));
+               spin_unlock(&server->req_lock);
+       } else {
+               hdr->CreditRequest = cpu_to_le16(2);
+       }
        hdr->ProcessId = cpu_to_le32((__u16)current->tgid);
 
        if (!tcon)
@@ -593,6 +607,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        char *security_blob = NULL;
        unsigned char *ntlmssp_blob = NULL;
        bool use_spnego = false; /* else use raw ntlmssp */
+       u64 previous_session = ses->Suid;
 
        cifs_dbg(FYI, "Session Setup\n");
 
@@ -630,6 +645,10 @@ ssetup_ntlmssp_authenticate:
                return rc;
 
        req->hdr.SessionId = 0; /* First session, not a reauthenticate */
+
+       /* if reconnect, we need to send previous sess id, otherwise it is 0 */
+       req->PreviousSessionId = previous_session;
+
        req->Flags = 0; /* MBZ */
        /* to enable echos and oplocks */
        req->hdr.CreditRequest = cpu_to_le16(3);
@@ -1167,7 +1186,7 @@ create_durable_v2_buf(struct cifs_fid *pfid)
 
        buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
        buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
-       get_random_bytes(buf->dcontext.CreateGuid, 16);
+       generate_random_uuid(buf->dcontext.CreateGuid);
        memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
 
        /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
@@ -2059,6 +2078,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
        if (rdata->credits) {
                buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
                                                SMB2_MAX_BUFFER_SIZE));
+               buf->CreditRequest = buf->CreditCharge;
                spin_lock(&server->req_lock);
                server->credits += rdata->credits -
                                                le16_to_cpu(buf->CreditCharge);
@@ -2245,6 +2265,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        if (wdata->credits) {
                req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
                                                    SMB2_MAX_BUFFER_SIZE));
+               req->hdr.CreditRequest = req->hdr.CreditCharge;
                spin_lock(&server->req_lock);
                server->credits += wdata->credits -
                                        le16_to_cpu(req->hdr.CreditCharge);
index 4af52780ec350323cd41e993389e7214fb50f97d..b8f553b32ddab34eae501a49b04eebdcfd759632 100644 (file)
@@ -276,7 +276,7 @@ struct smb2_sess_setup_req {
        __le32 Channel;
        __le16 SecurityBufferOffset;
        __le16 SecurityBufferLength;
-       __le64 PreviousSessionId;
+       __u64 PreviousSessionId;
        __u8   Buffer[1];       /* variable length GSS security buffer */
 } __packed;
 
index d049200362690961431ae07c41bb9582ae6ebf94..9e5099997fcd8da473bbdf50211873108c4f7194 100644 (file)
@@ -578,7 +578,6 @@ static struct dentry *dentry_kill(struct dentry *dentry)
 
 failed:
        spin_unlock(&dentry->d_lock);
-       cpu_relax();
        return dentry; /* try again with same dentry */
 }
 
@@ -752,6 +751,8 @@ void dput(struct dentry *dentry)
                return;
 
 repeat:
+       might_sleep();
+
        rcu_read_lock();
        if (likely(fast_dput(dentry))) {
                rcu_read_unlock();
@@ -783,8 +784,10 @@ repeat:
 
 kill_it:
        dentry = dentry_kill(dentry);
-       if (dentry)
+       if (dentry) {
+               cond_resched();
                goto repeat;
+       }
 }
 EXPORT_SYMBOL(dput);
 
index 706de324f2a619b8a15f0d7bf82263fb3a45dee2..c82edb0491170dffe131aefab27e2cb2e5d6c982 100644 (file)
@@ -128,6 +128,7 @@ static const match_table_t tokens = {
 struct pts_fs_info {
        struct ida allocated_ptys;
        struct pts_mount_opts mount_opts;
+       struct super_block *sb;
        struct dentry *ptmx_dentry;
 };
 
@@ -358,7 +359,7 @@ static const struct super_operations devpts_sops = {
        .show_options   = devpts_show_options,
 };
 
-static void *new_pts_fs_info(void)
+static void *new_pts_fs_info(struct super_block *sb)
 {
        struct pts_fs_info *fsi;
 
@@ -369,6 +370,7 @@ static void *new_pts_fs_info(void)
        ida_init(&fsi->allocated_ptys);
        fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
        fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+       fsi->sb = sb;
 
        return fsi;
 }
@@ -384,7 +386,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
        s->s_op = &devpts_sops;
        s->s_time_gran = 1;
 
-       s->s_fs_info = new_pts_fs_info();
+       s->s_fs_info = new_pts_fs_info(s);
        if (!s->s_fs_info)
                goto fail;
 
@@ -524,17 +526,14 @@ static struct file_system_type devpts_fs_type = {
  * to the System V naming convention
  */
 
-int devpts_new_index(struct inode *ptmx_inode)
+int devpts_new_index(struct pts_fs_info *fsi)
 {
-       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
-       struct pts_fs_info *fsi;
        int index;
        int ida_ret;
 
-       if (!sb)
+       if (!fsi)
                return -ENODEV;
 
-       fsi = DEVPTS_SB(sb);
 retry:
        if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
                return -ENOMEM;
@@ -564,11 +563,8 @@ retry:
        return index;
 }
 
-void devpts_kill_index(struct inode *ptmx_inode, int idx)
+void devpts_kill_index(struct pts_fs_info *fsi, int idx)
 {
-       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
-       struct pts_fs_info *fsi = DEVPTS_SB(sb);
-
        mutex_lock(&allocated_ptys_lock);
        ida_remove(&fsi->allocated_ptys, idx);
        pty_count--;
@@ -578,21 +574,25 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
 /*
  * pty code needs to hold extra references in case of last /dev/tty close
  */
-
-void devpts_add_ref(struct inode *ptmx_inode)
+struct pts_fs_info *devpts_get_ref(struct inode *ptmx_inode, struct file *file)
 {
-       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+       struct super_block *sb;
+       struct pts_fs_info *fsi;
+
+       sb = pts_sb_from_inode(ptmx_inode);
+       if (!sb)
+               return NULL;
+       fsi = DEVPTS_SB(sb);
+       if (!fsi)
+               return NULL;
 
        atomic_inc(&sb->s_active);
-       ihold(ptmx_inode);
+       return fsi;
 }
 
-void devpts_del_ref(struct inode *ptmx_inode)
+void devpts_put_ref(struct pts_fs_info *fsi)
 {
-       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
-
-       iput(ptmx_inode);
-       deactivate_super(sb);
+       deactivate_super(fsi->sb);
 }
 
 /**
@@ -604,22 +604,21 @@ void devpts_del_ref(struct inode *ptmx_inode)
  *
  * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill.
  */
-struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
+struct inode *devpts_pty_new(struct pts_fs_info *fsi, dev_t device, int index,
                void *priv)
 {
        struct dentry *dentry;
-       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+       struct super_block *sb;
        struct inode *inode;
        struct dentry *root;
-       struct pts_fs_info *fsi;
        struct pts_mount_opts *opts;
        char s[12];
 
-       if (!sb)
+       if (!fsi)
                return ERR_PTR(-ENODEV);
 
+       sb = fsi->sb;
        root = sb->s_root;
-       fsi = DEVPTS_SB(sb);
        opts = &fsi->mount_opts;
 
        inode = new_inode(sb);
index 3a37bd3f9637811c3b86e5c05be5aa47f32819c3..9d7a4a71490738029fbc33e6d6a1ca1b00fe97f0 100644 (file)
@@ -1607,16 +1607,12 @@ void dlm_lowcomms_stop(void)
        mutex_lock(&connections_lock);
        dlm_allow_conn = 0;
        foreach_conn(stop_conn);
+       clean_writequeues();
+       foreach_conn(free_conn);
        mutex_unlock(&connections_lock);
 
        work_stop();
 
-       mutex_lock(&connections_lock);
-       clean_writequeues();
-
-       foreach_conn(free_conn);
-
-       mutex_unlock(&connections_lock);
        kmem_cache_destroy(con_cache);
 }
 
index feef8a9c4de7cf09bcbc0effb45f83c207c9015b..27794b137b2440009cf9ce04ca5b3c7627b347bc 100644 (file)
@@ -112,7 +112,6 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
                .sb = inode->i_sb,
        };
        lower_file = ecryptfs_file_to_lower(file);
-       lower_file->f_pos = ctx->pos;
        rc = iterate_dir(lower_file, &buf.ctx);
        ctx->pos = buf.ctx.pos;
        if (rc < 0)
@@ -170,6 +169,19 @@ out:
        return rc;
 }
 
+static int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct file *lower_file = ecryptfs_file_to_lower(file);
+       /*
+        * Don't allow mmap on top of file systems that don't support it
+        * natively.  If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs
+        * allows recursive mounting, this will need to be extended.
+        */
+       if (!lower_file->f_op->mmap)
+               return -ENODEV;
+       return generic_file_mmap(file, vma);
+}
+
 /**
  * ecryptfs_open
  * @inode: inode speciying file to open
@@ -223,14 +235,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
        }
        ecryptfs_set_file_lower(
                file, ecryptfs_inode_to_private(inode)->lower_file);
-       if (d_is_dir(ecryptfs_dentry)) {
-               ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
-               mutex_lock(&crypt_stat->cs_mutex);
-               crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
-               mutex_unlock(&crypt_stat->cs_mutex);
-               rc = 0;
-               goto out;
-       }
        rc = read_or_initialize_metadata(ecryptfs_dentry);
        if (rc)
                goto out_put;
@@ -247,6 +251,45 @@ out:
        return rc;
 }
 
+/**
+ * ecryptfs_dir_open
+ * @inode: inode speciying file to open
+ * @file: Structure to return filled in
+ *
+ * Opens the file specified by inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_dir_open(struct inode *inode, struct file *file)
+{
+       struct dentry *ecryptfs_dentry = file->f_path.dentry;
+       /* Private value of ecryptfs_dentry allocated in
+        * ecryptfs_lookup() */
+       struct ecryptfs_file_info *file_info;
+       struct file *lower_file;
+
+       /* Released in ecryptfs_release or end of function if failure */
+       file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
+       ecryptfs_set_file_private(file, file_info);
+       if (unlikely(!file_info)) {
+               ecryptfs_printk(KERN_ERR,
+                               "Error attempting to allocate memory\n");
+               return -ENOMEM;
+       }
+       lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry),
+                                file->f_flags, current_cred());
+       if (IS_ERR(lower_file)) {
+               printk(KERN_ERR "%s: Error attempting to initialize "
+                       "the lower file for the dentry with name "
+                       "[%pd]; rc = [%ld]\n", __func__,
+                       ecryptfs_dentry, PTR_ERR(lower_file));
+               kmem_cache_free(ecryptfs_file_info_cache, file_info);
+               return PTR_ERR(lower_file);
+       }
+       ecryptfs_set_file_lower(file, lower_file);
+       return 0;
+}
+
 static int ecryptfs_flush(struct file *file, fl_owner_t td)
 {
        struct file *lower_file = ecryptfs_file_to_lower(file);
@@ -267,6 +310,19 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int ecryptfs_dir_release(struct inode *inode, struct file *file)
+{
+       fput(ecryptfs_file_to_lower(file));
+       kmem_cache_free(ecryptfs_file_info_cache,
+                       ecryptfs_file_to_private(file));
+       return 0;
+}
+
+static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+       return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence);
+}
+
 static int
 ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
@@ -346,25 +402,21 @@ const struct file_operations ecryptfs_dir_fops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl = ecryptfs_compat_ioctl,
 #endif
-       .open = ecryptfs_open,
-       .flush = ecryptfs_flush,
-       .release = ecryptfs_release,
+       .open = ecryptfs_dir_open,
+       .release = ecryptfs_dir_release,
        .fsync = ecryptfs_fsync,
-       .fasync = ecryptfs_fasync,
-       .splice_read = generic_file_splice_read,
-       .llseek = default_llseek,
+       .llseek = ecryptfs_dir_llseek,
 };
 
 const struct file_operations ecryptfs_main_fops = {
        .llseek = generic_file_llseek,
        .read_iter = ecryptfs_read_update_atime,
        .write_iter = generic_file_write_iter,
-       .iterate = ecryptfs_readdir,
        .unlocked_ioctl = ecryptfs_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = ecryptfs_compat_ioctl,
 #endif
-       .mmap = generic_file_mmap,
+       .mmap = ecryptfs_mmap,
        .open = ecryptfs_open,
        .flush = ecryptfs_flush,
        .release = ecryptfs_release,
index e818f5ac7a2692b6bb5c1a132d7bbfd967ad956a..866bb18efefea9953250ba1cbdc145e7d4be49af 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/mount.h>
-#include <linux/file.h>
 #include "ecryptfs_kernel.h"
 
 struct ecryptfs_open_req {
@@ -148,7 +147,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
        flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR;
        (*lower_file) = dentry_open(&req.path, flags, cred);
        if (!IS_ERR(*lower_file))
-               goto have_file;
+               goto out;
        if ((flags & O_ACCMODE) == O_RDONLY) {
                rc = PTR_ERR((*lower_file));
                goto out;
@@ -166,16 +165,8 @@ int ecryptfs_privileged_open(struct file **lower_file,
        mutex_unlock(&ecryptfs_kthread_ctl.mux);
        wake_up(&ecryptfs_kthread_ctl.wait);
        wait_for_completion(&req.done);
-       if (IS_ERR(*lower_file)) {
+       if (IS_ERR(*lower_file))
                rc = PTR_ERR(*lower_file);
-               goto out;
-       }
-have_file:
-       if ((*lower_file)->f_op->mmap == NULL) {
-               fput(*lower_file);
-               *lower_file = NULL;
-               rc = -EMEDIUMTYPE;
-       }
 out:
        return rc;
 }
index 27695e6f4e46629a8a888f38bcaf6f0e4ceaf1ec..d6aeb84e90b61acb8dff22443b9a9694c7ba3dba 100644 (file)
@@ -193,15 +193,11 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                case ACL_TYPE_ACCESS:
                        name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
                        if (acl) {
-                               error = posix_acl_equiv_mode(acl, &inode->i_mode);
-                               if (error < 0)
+                               error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                               if (error)
                                        return error;
-                               else {
-                                       inode->i_ctime = CURRENT_TIME_SEC;
-                                       mark_inode_dirty(inode);
-                                       if (error == 0)
-                                               acl = NULL;
-                               }
+                               inode->i_ctime = CURRENT_TIME_SEC;
+                               mark_inode_dirty(inode);
                        }
                        break;
 
index 69b1e73026a51f6b8ae0e591d33abb0fdc9169d8..c3fe1e323951f9da0d19aa3eeb333c119f59a142 100644 (file)
@@ -196,15 +196,11 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
        case ACL_TYPE_ACCESS:
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
                if (acl) {
-                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (error < 0)
+                       error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                       if (error)
                                return error;
-                       else {
-                               inode->i_ctime = ext4_current_time(inode);
-                               ext4_mark_inode_dirty(handle, inode);
-                               if (error == 0)
-                                       acl = NULL;
-                       }
+                       inode->i_ctime = ext4_current_time(inode);
+                       ext4_mark_inode_dirty(handle, inode);
                }
                break;
 
index fe1f50fe764ff9238354e2e30491c6e1e6d149b9..f97110461c196b2b770baa7d2e0b7694cb750fa2 100644 (file)
@@ -208,6 +208,9 @@ static int ext4_init_block_bitmap(struct super_block *sb,
        memset(bh->b_data, 0, sb->s_blocksize);
 
        bit_max = ext4_num_base_meta_clusters(sb, block_group);
+       if ((bit_max >> 3) >= bh->b_size)
+               return -EFSCORRUPTED;
+
        for (bit = 0; bit < bit_max; bit++)
                ext4_set_bit(bit, bh->b_data);
 
index ad050698143fde483e9c5cddc5e32c88041a9b29..8a9feb341f314ea94f7f4e5984aea57f4b8e20a4 100644 (file)
@@ -102,6 +102,9 @@ static int ext4_create_encryption_context_from_policy(
 int ext4_process_policy(const struct ext4_encryption_policy *policy,
                        struct inode *inode)
 {
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
        if (policy->version != 0)
                return -EINVAL;
 
index 3578b25fccfd8eef98062e22ee037037a9c8ca38..9da42ace762a3e1cff1bbb2d2c5a667195cf2ee6 100644 (file)
@@ -376,9 +376,13 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
        ext4_fsblk_t block = ext4_ext_pblock(ext);
        int len = ext4_ext_get_actual_len(ext);
        ext4_lblk_t lblock = le32_to_cpu(ext->ee_block);
-       ext4_lblk_t last = lblock + len - 1;
 
-       if (len == 0 || lblock > last)
+       /*
+        * We allow neither:
+        *  - zero length
+        *  - overflow/wrap-around
+        */
+       if (lblock + len <= lblock)
                return 0;
        return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
 }
@@ -469,6 +473,10 @@ static int __ext4_ext_check(const char *function, unsigned int line,
                error_msg = "invalid extent entries";
                goto corrupted;
        }
+       if (unlikely(depth > 32)) {
+               error_msg = "too large eh_depth";
+               goto corrupted;
+       }
        /* Verify checksum on non-root extent tree nodes */
        if (ext_depth(inode) != depth &&
            !ext4_extent_block_csum_verify(inode, eh)) {
@@ -5730,6 +5738,9 @@ int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                        up_write(&EXT4_I(inode)->i_data_sem);
                        goto out_stop;
                }
+       } else {
+               ext4_ext_drop_refs(path);
+               kfree(path);
        }
 
        ret = ext4_es_remove_extent(inode, offset_lblk,
index d884989cc83dd99238a710f8131ab38b1139c7ca..af34979684a4df6f7f35f22a4cf30bcb57007a1b 100644 (file)
@@ -18,6 +18,7 @@
 #include "ext4.h"
 #include "xattr.h"
 #include "truncate.h"
+#include <trace/events/android_fs.h>
 
 #define EXT4_XATTR_SYSTEM_DATA "data"
 #define EXT4_MIN_INLINE_DATA_SIZE      ((sizeof(__le32) * EXT4_N_BLOCKS))
@@ -500,6 +501,9 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
                return -EAGAIN;
        }
 
+       trace_android_fs_dataread_start(inode, page_offset(page), PAGE_SIZE,
+                                       current->pid, current->comm);
+
        /*
         * Current inline data can only exist in the 1st page,
         * So for all the other pages, just set them uptodate.
@@ -511,6 +515,8 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
                SetPageUptodate(page);
        }
 
+       trace_android_fs_dataread_end(inode, page_offset(page), PAGE_SIZE);
+
        up_read(&EXT4_I(inode)->xattr_sem);
 
        unlock_page(page);
index e31d762eedce14e19a9d4f1c5e7d72756cd55147..a4149cc2c6c0e329e2060ce83b5644bf46cfcf50 100644 (file)
@@ -44,6 +44,7 @@
 #include "truncate.h"
 
 #include <trace/events/ext4.h>
+#include <trace/events/android_fs.h>
 
 #define MPAGE_DA_EXTENT_TAIL 0x01
 
@@ -51,25 +52,31 @@ static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
                              struct ext4_inode_info *ei)
 {
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-       __u16 csum_lo;
-       __u16 csum_hi = 0;
        __u32 csum;
+       __u16 dummy_csum = 0;
+       int offset = offsetof(struct ext4_inode, i_checksum_lo);
+       unsigned int csum_size = sizeof(dummy_csum);
 
-       csum_lo = le16_to_cpu(raw->i_checksum_lo);
-       raw->i_checksum_lo = 0;
-       if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
-           EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
-               csum_hi = le16_to_cpu(raw->i_checksum_hi);
-               raw->i_checksum_hi = 0;
-       }
+       csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw, offset);
+       csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, csum_size);
+       offset += csum_size;
+       csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+                          EXT4_GOOD_OLD_INODE_SIZE - offset);
 
-       csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw,
-                          EXT4_INODE_SIZE(inode->i_sb));
-
-       raw->i_checksum_lo = cpu_to_le16(csum_lo);
-       if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
-           EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
-               raw->i_checksum_hi = cpu_to_le16(csum_hi);
+       if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
+               offset = offsetof(struct ext4_inode, i_checksum_hi);
+               csum = ext4_chksum(sbi, csum, (__u8 *)raw +
+                                  EXT4_GOOD_OLD_INODE_SIZE,
+                                  offset - EXT4_GOOD_OLD_INODE_SIZE);
+               if (EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
+                       csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
+                                          csum_size);
+                       offset += csum_size;
+                       csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+                                          EXT4_INODE_SIZE(inode->i_sb) -
+                                          offset);
+               }
+       }
 
        return csum;
 }
@@ -205,9 +212,9 @@ void ext4_evict_inode(struct inode *inode)
                 * Note that directories do not have this problem because they
                 * don't use page cache.
                 */
-               if (ext4_should_journal_data(inode) &&
-                   (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) &&
-                   inode->i_ino != EXT4_JOURNAL_INO) {
+               if (inode->i_ino != EXT4_JOURNAL_INO &&
+                   ext4_should_journal_data(inode) &&
+                   (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) {
                        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
                        tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
 
@@ -1010,6 +1017,8 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        unsigned from, to;
 
+       trace_android_fs_datawrite_start(inode, pos, len,
+                                        current->pid, current->comm);
        trace_ext4_write_begin(inode, pos, len, flags);
        /*
         * Reserve one block more for addition to orphan list in case
@@ -1146,6 +1155,7 @@ static int ext4_write_end(struct file *file,
        int ret = 0, ret2;
        int i_size_changed = 0;
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_ext4_write_end(inode, pos, len, copied);
        if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
                ret = ext4_jbd2_file_inode(handle, inode);
@@ -1254,6 +1264,7 @@ static int ext4_journalled_write_end(struct file *file,
        unsigned from, to;
        int size_changed = 0;
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_ext4_journalled_write_end(inode, pos, len, copied);
        from = pos & (PAGE_CACHE_SIZE - 1);
        to = from + len;
@@ -2589,13 +2600,36 @@ retry:
                                done = true;
                        }
                }
-               ext4_journal_stop(handle);
+               /*
+                * Caution: If the handle is synchronous,
+                * ext4_journal_stop() can wait for transaction commit
+                * to finish which may depend on writeback of pages to
+                * complete or on page lock to be released.  In that
+                * case, we have to wait until after after we have
+                * submitted all the IO, released page locks we hold,
+                * and dropped io_end reference (for extent conversion
+                * to be able to complete) before stopping the handle.
+                */
+               if (!ext4_handle_valid(handle) || handle->h_sync == 0) {
+                       ext4_journal_stop(handle);
+                       handle = NULL;
+               }
                /* Submit prepared bio */
                ext4_io_submit(&mpd.io_submit);
                /* Unlock pages we didn't use */
                mpage_release_unused_pages(&mpd, give_up_on_write);
-               /* Drop our io_end reference we got from init */
-               ext4_put_io_end(mpd.io_submit.io_end);
+               /*
+                * Drop our io_end reference we got from init. We have
+                * to be careful and use deferred io_end finishing if
+                * we are still holding the transaction as we can
+                * release the last reference to io_end which may end
+                * up doing unwritten extent conversion.
+                */
+               if (handle) {
+                       ext4_put_io_end_defer(mpd.io_submit.io_end);
+                       ext4_journal_stop(handle);
+               } else
+                       ext4_put_io_end(mpd.io_submit.io_end);
 
                if (ret == -ENOSPC && sbi->s_journal) {
                        /*
@@ -2698,6 +2732,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
                                        len, flags, pagep, fsdata);
        }
        *fsdata = (void *)0;
+       trace_android_fs_datawrite_start(inode, pos, len,
+                                        current->pid, current->comm);
        trace_ext4_da_write_begin(inode, pos, len, flags);
 
        if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
@@ -2816,6 +2852,7 @@ static int ext4_da_write_end(struct file *file,
                return ext4_write_end(file, mapping, pos,
                                      len, copied, page, fsdata);
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_ext4_da_write_end(inode, pos, len, copied);
        start = pos & (PAGE_CACHE_SIZE - 1);
        end = start + copied - 1;
@@ -3304,12 +3341,31 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
        if (ext4_has_inline_data(inode))
                return 0;
 
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_start(inode, offset, count,
+                                               current->pid,
+                                               current->comm);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_start(inode, offset, count,
+                                                current->pid,
+                                                current->comm);
+
        trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                ret = ext4_ext_direct_IO(iocb, iter, offset);
        else
                ret = ext4_ind_direct_IO(iocb, iter, offset);
        trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
+
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_end(inode, offset, count);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_end(inode, offset, count);
+
        return ret;
 }
 
@@ -3616,7 +3672,7 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
 }
 
 /*
- * ext4_punch_hole: punches a hole in a file by releaseing the blocks
+ * ext4_punch_hole: punches a hole in a file by releasing the blocks
  * associated with the given offset and length
  *
  * @inode:  File inode
@@ -3645,7 +3701,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
         * Write out all dirty pages to avoid race conditions
         * Then release them.
         */
-       if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+       if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
                ret = filemap_write_and_wait_range(mapping, offset,
                                                   offset + length - 1);
                if (ret)
@@ -4520,14 +4576,14 @@ static int ext4_do_update_inode(handle_t *handle,
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
-               if (!ei->i_dtime) {
+               if (ei->i_dtime && list_empty(&ei->i_orphan)) {
+                       raw_inode->i_uid_high = 0;
+                       raw_inode->i_gid_high = 0;
+               } else {
                        raw_inode->i_uid_high =
                                cpu_to_le16(high_16_bits(i_uid));
                        raw_inode->i_gid_high =
                                cpu_to_le16(high_16_bits(i_gid));
-               } else {
-                       raw_inode->i_uid_high = 0;
-                       raw_inode->i_gid_high = 0;
                }
        } else {
                raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
@@ -5163,8 +5219,6 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
                                                      sbi->s_want_extra_isize,
                                                      iloc, handle);
                        if (ret) {
-                               ext4_set_inode_state(inode,
-                                                    EXT4_STATE_NO_EXPAND);
                                if (mnt_count !=
                                        le16_to_cpu(sbi->s_es->s_mnt_count)) {
                                        ext4_warning(inode->i_sb,
index 95315b1f4b71c58458f0a6fa2b4d5ae2059e06a5..7e974878d9a9ca1774acf59059bf9cd88ebf890e 100644 (file)
@@ -633,7 +633,13 @@ resizefs_out:
                        goto encryption_policy_out;
                }
 
+               err = mnt_want_write_file(filp);
+               if (err)
+                       goto encryption_policy_out;
+
                err = ext4_process_policy(&policy, inode);
+
+               mnt_drop_write_file(filp);
 encryption_policy_out:
                return err;
 #else
index 2f53c3822daaf4151a131f2bc8cbc86541699763..0b1c97875686bbe2732c0dbb9cb2a131c4d52c80 100644 (file)
@@ -815,7 +815,7 @@ static void mb_regenerate_buddy(struct ext4_buddy *e4b)
  * for this page; do not hold this lock when calling this routine!
  */
 
-static int ext4_mb_init_cache(struct page *page, char *incore)
+static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
 {
        ext4_group_t ngroups;
        int blocksize;
@@ -848,7 +848,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
        /* allocate buffer_heads to read bitmaps */
        if (groups_per_page > 1) {
                i = sizeof(struct buffer_head *) * groups_per_page;
-               bh = kzalloc(i, GFP_NOFS);
+               bh = kzalloc(i, gfp);
                if (bh == NULL) {
                        err = -ENOMEM;
                        goto out;
@@ -983,7 +983,7 @@ out:
  * are on the same page e4b->bd_buddy_page is NULL and return value is 0.
  */
 static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
-               ext4_group_t group, struct ext4_buddy *e4b)
+               ext4_group_t group, struct ext4_buddy *e4b, gfp_t gfp)
 {
        struct inode *inode = EXT4_SB(sb)->s_buddy_cache;
        int block, pnum, poff;
@@ -1002,7 +1002,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
        block = group * 2;
        pnum = block / blocks_per_page;
        poff = block % blocks_per_page;
-       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+       page = find_or_create_page(inode->i_mapping, pnum, gfp);
        if (!page)
                return -ENOMEM;
        BUG_ON(page->mapping != inode->i_mapping);
@@ -1016,7 +1016,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
 
        block++;
        pnum = block / blocks_per_page;
-       page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+       page = find_or_create_page(inode->i_mapping, pnum, gfp);
        if (!page)
                return -ENOMEM;
        BUG_ON(page->mapping != inode->i_mapping);
@@ -1042,7 +1042,7 @@ static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b)
  * calling this routine!
  */
 static noinline_for_stack
-int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
+int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp)
 {
 
        struct ext4_group_info *this_grp;
@@ -1062,7 +1062,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
         * The call to ext4_mb_get_buddy_page_lock will mark the
         * page accessed.
         */
-       ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b);
+       ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b, gfp);
        if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) {
                /*
                 * somebody initialized the group
@@ -1072,7 +1072,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
        }
 
        page = e4b.bd_bitmap_page;
-       ret = ext4_mb_init_cache(page, NULL);
+       ret = ext4_mb_init_cache(page, NULL, gfp);
        if (ret)
                goto err;
        if (!PageUptodate(page)) {
@@ -1091,7 +1091,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
        }
        /* init buddy cache */
        page = e4b.bd_buddy_page;
-       ret = ext4_mb_init_cache(page, e4b.bd_bitmap);
+       ret = ext4_mb_init_cache(page, e4b.bd_bitmap, gfp);
        if (ret)
                goto err;
        if (!PageUptodate(page)) {
@@ -1109,8 +1109,8 @@ err:
  * calling this routine!
  */
 static noinline_for_stack int
-ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
-                                       struct ext4_buddy *e4b)
+ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
+                      struct ext4_buddy *e4b, gfp_t gfp)
 {
        int blocks_per_page;
        int block;
@@ -1140,7 +1140,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
                 * we need full data about the group
                 * to make a good selection
                 */
-               ret = ext4_mb_init_group(sb, group);
+               ret = ext4_mb_init_group(sb, group, gfp);
                if (ret)
                        return ret;
        }
@@ -1168,11 +1168,11 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
                         * wait for it to initialize.
                         */
                        page_cache_release(page);
-               page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+               page = find_or_create_page(inode->i_mapping, pnum, gfp);
                if (page) {
                        BUG_ON(page->mapping != inode->i_mapping);
                        if (!PageUptodate(page)) {
-                               ret = ext4_mb_init_cache(page, NULL);
+                               ret = ext4_mb_init_cache(page, NULL, gfp);
                                if (ret) {
                                        unlock_page(page);
                                        goto err;
@@ -1204,11 +1204,12 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
        if (page == NULL || !PageUptodate(page)) {
                if (page)
                        page_cache_release(page);
-               page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
+               page = find_or_create_page(inode->i_mapping, pnum, gfp);
                if (page) {
                        BUG_ON(page->mapping != inode->i_mapping);
                        if (!PageUptodate(page)) {
-                               ret = ext4_mb_init_cache(page, e4b->bd_bitmap);
+                               ret = ext4_mb_init_cache(page, e4b->bd_bitmap,
+                                                        gfp);
                                if (ret) {
                                        unlock_page(page);
                                        goto err;
@@ -1247,6 +1248,12 @@ err:
        return ret;
 }
 
+static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+                             struct ext4_buddy *e4b)
+{
+       return ext4_mb_load_buddy_gfp(sb, group, e4b, GFP_NOFS);
+}
+
 static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
 {
        if (e4b->bd_bitmap_page)
@@ -2047,7 +2054,7 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac,
 
        /* We only do this if the grp has never been initialized */
        if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
-               int ret = ext4_mb_init_group(ac->ac_sb, group);
+               int ret = ext4_mb_init_group(ac->ac_sb, group, GFP_NOFS);
                if (ret)
                        return ret;
        }
@@ -2933,7 +2940,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                ext4_error(sb, "Allocating blocks %llu-%llu which overlap "
                           "fs metadata", block, block+len);
                /* File system mounted not to panic on error
-                * Fix the bitmap and repeat the block allocation
+                * Fix the bitmap and return EFSCORRUPTED
                 * We leak some of the blocks here.
                 */
                ext4_lock_group(sb, ac->ac_b_ex.fe_group);
@@ -2942,7 +2949,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
                err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
                if (!err)
-                       err = -EAGAIN;
+                       err = -EFSCORRUPTED;
                goto out_err;
        }
 
@@ -4507,18 +4514,7 @@ repeat:
        }
        if (likely(ac->ac_status == AC_STATUS_FOUND)) {
                *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs);
-               if (*errp == -EAGAIN) {
-                       /*
-                        * drop the reference that we took
-                        * in ext4_mb_use_best_found
-                        */
-                       ext4_mb_release_context(ac);
-                       ac->ac_b_ex.fe_group = 0;
-                       ac->ac_b_ex.fe_start = 0;
-                       ac->ac_b_ex.fe_len = 0;
-                       ac->ac_status = AC_STATUS_CONTINUE;
-                       goto repeat;
-               } else if (*errp) {
+               if (*errp) {
                        ext4_discard_allocated_blocks(ac);
                        goto errout;
                } else {
@@ -4820,7 +4816,9 @@ do_more:
 #endif
        trace_ext4_mballoc_free(sb, inode, block_group, bit, count_clusters);
 
-       err = ext4_mb_load_buddy(sb, block_group, &e4b);
+       /* __GFP_NOFAIL: retry infinitely, ignore TIF_MEMDIE and memcg limit. */
+       err = ext4_mb_load_buddy_gfp(sb, block_group, &e4b,
+                                    GFP_NOFS|__GFP_NOFAIL);
        if (err)
                goto error_return;
 
@@ -5229,7 +5227,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range,
                grp = ext4_get_group_info(sb, group);
                /* We only do this if the grp has never been initialized */
                if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
-                       ret = ext4_mb_init_group(sb, group);
+                       ret = ext4_mb_init_group(sb, group, GFP_NOFS);
                        if (ret)
                                break;
                }
index 796ff0eafd3c352beccb2347edcc3df87fc91422..7861d801b048e5d47143c2a3d9d6148cf8a6c971 100644 (file)
@@ -598,6 +598,13 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
                return -EOPNOTSUPP;
        }
 
+       if (ext4_encrypted_inode(orig_inode) ||
+           ext4_encrypted_inode(donor_inode)) {
+               ext4_msg(orig_inode->i_sb, KERN_ERR,
+                        "Online defrag not supported for encrypted files");
+               return -EOPNOTSUPP;
+       }
+
        /* Protect orig and donor inodes against a truncate */
        lock_two_nondirectories(orig_inode, donor_inode);
 
index 91bf36f22dbfba05123dea6efc5ac90bc9fcd5bd..573b4cbb0cb991e1c60dd12d88d7c3c05d9a0120 100644 (file)
@@ -420,15 +420,14 @@ static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent,
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        struct ext4_inode_info *ei = EXT4_I(inode);
        __u32 csum;
-       __le32 save_csum;
        int size;
+       __u32 dummy_csum = 0;
+       int offset = offsetof(struct dx_tail, dt_checksum);
 
        size = count_offset + (count * sizeof(struct dx_entry));
-       save_csum = t->dt_checksum;
-       t->dt_checksum = 0;
        csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size);
-       csum = ext4_chksum(sbi, csum, (__u8 *)t, sizeof(struct dx_tail));
-       t->dt_checksum = save_csum;
+       csum = ext4_chksum(sbi, csum, (__u8 *)t, offset);
+       csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
 
        return cpu_to_le32(csum);
 }
@@ -2018,33 +2017,31 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
        frame->entries = entries;
        frame->at = entries;
        frame->bh = bh;
-       bh = bh2;
 
        retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
        if (retval)
                goto out_frames;        
-       retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
+       retval = ext4_handle_dirty_dirent_node(handle, dir, bh2);
        if (retval)
                goto out_frames;        
 
-       de = do_split(handle,dir, &bh, frame, &fname->hinfo);
+       de = do_split(handle,dir, &bh2, frame, &fname->hinfo);
        if (IS_ERR(de)) {
                retval = PTR_ERR(de);
                goto out_frames;
        }
-       dx_release(frames);
 
-       retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh);
-       brelse(bh);
-       return retval;
+       retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2);
 out_frames:
        /*
         * Even if the block split failed, we have to properly write
         * out all the changes we did so far. Otherwise we can end up
         * with corrupted filesystem.
         */
-       ext4_mark_inode_dirty(handle, dir);
+       if (retval)
+               ext4_mark_inode_dirty(handle, dir);
        dx_release(frames);
+       brelse(bh2);
        return retval;
 }
 
index 5dc5e95063de2a7e42749a94464f00f7c50be4b8..1ce24a6759a090de564813b6639e011da10b3271 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/cleancache.h>
 
 #include "ext4.h"
+#include <trace/events/android_fs.h>
 
 /*
  * Call ext4_decrypt on every single page, reusing the encryption
@@ -86,6 +87,17 @@ static inline bool ext4_bio_encrypted(struct bio *bio)
 #endif
 }
 
+static void
+ext4_trace_read_completion(struct bio *bio)
+{
+       struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+       if (first_page != NULL)
+               trace_android_fs_dataread_end(first_page->mapping->host,
+                                             page_offset(first_page),
+                                             bio->bi_iter.bi_size);
+}
+
 /*
  * I/O completion handler for multipage BIOs.
  *
@@ -103,6 +115,9 @@ static void mpage_end_io(struct bio *bio)
        struct bio_vec *bv;
        int i;
 
+       if (trace_android_fs_dataread_start_enabled())
+               ext4_trace_read_completion(bio);
+
        if (ext4_bio_encrypted(bio)) {
                struct ext4_crypto_ctx *ctx = bio->bi_private;
 
@@ -130,6 +145,24 @@ static void mpage_end_io(struct bio *bio)
        bio_put(bio);
 }
 
+static void
+ext4_submit_bio_read(struct bio *bio)
+{
+       if (trace_android_fs_dataread_start_enabled()) {
+               struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+               if (first_page != NULL) {
+                       trace_android_fs_dataread_start(
+                               first_page->mapping->host,
+                               page_offset(first_page),
+                               bio->bi_iter.bi_size,
+                               current->pid,
+                               current->comm);
+               }
+       }
+       submit_bio(READ, bio);
+}
+
 int ext4_mpage_readpages(struct address_space *mapping,
                         struct list_head *pages, struct page *page,
                         unsigned nr_pages)
@@ -271,7 +304,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
                 */
                if (bio && (last_block_in_bio != blocks[0] - 1)) {
                submit_and_realloc:
-                       submit_bio(READ, bio);
+                       ext4_submit_bio_read(bio);
                        bio = NULL;
                }
                if (bio == NULL) {
@@ -303,14 +336,14 @@ int ext4_mpage_readpages(struct address_space *mapping,
                if (((map.m_flags & EXT4_MAP_BOUNDARY) &&
                     (relative_block == map.m_len)) ||
                    (first_hole != blocks_per_page)) {
-                       submit_bio(READ, bio);
+                       ext4_submit_bio_read(bio);
                        bio = NULL;
                } else
                        last_block_in_bio = blocks[blocks_per_page - 1];
                goto next_page;
        confused:
                if (bio) {
-                       submit_bio(READ, bio);
+                       ext4_submit_bio_read(bio);
                        bio = NULL;
                }
                if (!PageUptodate(page))
@@ -323,6 +356,6 @@ int ext4_mpage_readpages(struct address_space *mapping,
        }
        BUG_ON(pages && !list_empty(pages));
        if (bio)
-               submit_bio(READ, bio);
+               ext4_submit_bio_read(bio);
        return 0;
 }
index 852c26806af275a1f3894c0a990c341540f23c06..5bab28caa9d4a882f1da662f8efb145e88cf1a09 100644 (file)
@@ -2030,23 +2030,25 @@ failed:
 static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
                                   struct ext4_group_desc *gdp)
 {
-       int offset;
+       int offset = offsetof(struct ext4_group_desc, bg_checksum);
        __u16 crc = 0;
        __le32 le_group = cpu_to_le32(block_group);
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (ext4_has_metadata_csum(sbi->s_sb)) {
                /* Use new metadata_csum algorithm */
-               __le16 save_csum;
                __u32 csum32;
+               __u16 dummy_csum = 0;
 
-               save_csum = gdp->bg_checksum;
-               gdp->bg_checksum = 0;
                csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
                                     sizeof(le_group));
-               csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp,
-                                    sbi->s_desc_size);
-               gdp->bg_checksum = save_csum;
+               csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset);
+               csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum,
+                                    sizeof(dummy_csum));
+               offset += sizeof(dummy_csum);
+               if (offset < sbi->s_desc_size)
+                       csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset,
+                                            sbi->s_desc_size - offset);
 
                crc = csum32 & 0xFFFF;
                goto out;
@@ -2056,8 +2058,6 @@ static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
        if (!ext4_has_feature_gdt_csum(sb))
                return 0;
 
-       offset = offsetof(struct ext4_group_desc, bg_checksum);
-
        crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
        crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
        crc = crc16(crc, (__u8 *)gdp, offset);
@@ -2093,6 +2093,7 @@ void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
 
 /* Called at mount-time, super-block is locked */
 static int ext4_check_descriptors(struct super_block *sb,
+                                 ext4_fsblk_t sb_block,
                                  ext4_group_t *first_not_zeroed)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2123,6 +2124,11 @@ static int ext4_check_descriptors(struct super_block *sb,
                        grp = i;
 
                block_bitmap = ext4_block_bitmap(sb, gdp);
+               if (block_bitmap == sb_block) {
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Block bitmap for group %u overlaps "
+                                "superblock", i);
+               }
                if (block_bitmap < first_block || block_bitmap > last_block) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                               "Block bitmap for group %u not in group "
@@ -2130,6 +2136,11 @@ static int ext4_check_descriptors(struct super_block *sb,
                        return 0;
                }
                inode_bitmap = ext4_inode_bitmap(sb, gdp);
+               if (inode_bitmap == sb_block) {
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Inode bitmap for group %u overlaps "
+                                "superblock", i);
+               }
                if (inode_bitmap < first_block || inode_bitmap > last_block) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                               "Inode bitmap for group %u not in group "
@@ -2137,6 +2148,11 @@ static int ext4_check_descriptors(struct super_block *sb,
                        return 0;
                }
                inode_table = ext4_inode_table(sb, gdp);
+               if (inode_table == sb_block) {
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Inode table for group %u overlaps "
+                                "superblock", i);
+               }
                if (inode_table < first_block ||
                    inode_table + sbi->s_itb_per_group - 1 > last_block) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2240,6 +2256,16 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        while (es->s_last_orphan) {
                struct inode *inode;
 
+               /*
+                * We may have encountered an error during cleanup; if
+                * so, skip the rest.
+                */
+               if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
+                       jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
+                       es->s_last_orphan = 0;
+                       break;
+               }
+
                inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
                if (IS_ERR(inode)) {
                        es->s_last_orphan = 0;
@@ -3372,6 +3398,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
+       if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) {
+               ext4_msg(sb, KERN_ERR,
+                        "Number of reserved GDT blocks insanely large: %d",
+                        le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks));
+               goto failed_mount;
+       }
+
        if (sbi->s_mount_opt & EXT4_MOUNT_DAX) {
                if (blocksize != PAGE_SIZE) {
                        ext4_msg(sb, KERN_ERR,
@@ -3623,7 +3656,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        goto failed_mount2;
                }
        }
-       if (!ext4_check_descriptors(sb, &first_not_zeroed)) {
+       if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) {
                ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
                ret = -EFSCORRUPTED;
                goto failed_mount2;
index 1420a3c614afb1a4c06e87471163acf01b3b98d8..5d09ea585840a316257394b193f84e66d8fc5546 100644 (file)
@@ -223,14 +223,18 @@ static struct attribute *ext4_attrs[] = {
 EXT4_ATTR_FEATURE(lazy_itable_init);
 EXT4_ATTR_FEATURE(batched_discard);
 EXT4_ATTR_FEATURE(meta_bg_resize);
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
 EXT4_ATTR_FEATURE(encryption);
+#endif
 EXT4_ATTR_FEATURE(metadata_csum_seed);
 
 static struct attribute *ext4_feat_attrs[] = {
        ATTR_LIST(lazy_itable_init),
        ATTR_LIST(batched_discard),
        ATTR_LIST(meta_bg_resize),
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
        ATTR_LIST(encryption),
+#endif
        ATTR_LIST(metadata_csum_seed),
        NULL,
 };
index 6b6b3e751f8c77ebc9089c412f9019b4774a4301..263002f0389df6d25995b1ed07c7e71ff0aa7585 100644 (file)
@@ -123,17 +123,18 @@ static __le32 ext4_xattr_block_csum(struct inode *inode,
 {
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        __u32 csum;
-       __le32 save_csum;
        __le64 dsk_block_nr = cpu_to_le64(block_nr);
+       __u32 dummy_csum = 0;
+       int offset = offsetof(struct ext4_xattr_header, h_checksum);
 
-       save_csum = hdr->h_checksum;
-       hdr->h_checksum = 0;
        csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,
                           sizeof(dsk_block_nr));
-       csum = ext4_chksum(sbi, csum, (__u8 *)hdr,
-                          EXT4_BLOCK_SIZE(inode->i_sb));
+       csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset);
+       csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
+       offset += sizeof(dummy_csum);
+       csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset,
+                          EXT4_BLOCK_SIZE(inode->i_sb) - offset);
 
-       hdr->h_checksum = save_csum;
        return cpu_to_le32(csum);
 }
 
@@ -1264,15 +1265,19 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
        size_t min_offs, free;
        int total_ino;
        void *base, *start, *end;
-       int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
+       int error = 0, tried_min_extra_isize = 0;
        int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize);
+       int isize_diff; /* How much do we need to grow i_extra_isize */
 
        down_write(&EXT4_I(inode)->xattr_sem);
+       /*
+        * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty
+        */
+       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
 retry:
-       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
-               up_write(&EXT4_I(inode)->xattr_sem);
-               return 0;
-       }
+       isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize;
+       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+               goto out;
 
        header = IHDR(inode, raw_inode);
        entry = IFIRST(header);
@@ -1289,7 +1294,7 @@ retry:
        total_ino = sizeof(struct ext4_xattr_ibody_header);
 
        free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
-       if (free >= new_extra_isize) {
+       if (free >= isize_diff) {
                entry = IFIRST(header);
                ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
                                - new_extra_isize, (void *)raw_inode +
@@ -1297,8 +1302,7 @@ retry:
                                (void *)header, total_ino,
                                inode->i_sb->s_blocksize);
                EXT4_I(inode)->i_extra_isize = new_extra_isize;
-               error = 0;
-               goto cleanup;
+               goto out;
        }
 
        /*
@@ -1321,7 +1325,7 @@ retry:
                end = bh->b_data + bh->b_size;
                min_offs = end - base;
                free = ext4_xattr_free_space(first, &min_offs, base, NULL);
-               if (free < new_extra_isize) {
+               if (free < isize_diff) {
                        if (!tried_min_extra_isize && s_min_extra_isize) {
                                tried_min_extra_isize++;
                                new_extra_isize = s_min_extra_isize;
@@ -1335,7 +1339,7 @@ retry:
                free = inode->i_sb->s_blocksize;
        }
 
-       while (new_extra_isize > 0) {
+       while (isize_diff > 0) {
                size_t offs, size, entry_size;
                struct ext4_xattr_entry *small_entry = NULL;
                struct ext4_xattr_info i = {
@@ -1366,7 +1370,7 @@ retry:
                        EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
                                        EXT4_XATTR_LEN(last->e_name_len);
                        if (total_size <= free && total_size < min_total_size) {
-                               if (total_size < new_extra_isize) {
+                               if (total_size < isize_diff) {
                                        small_entry = last;
                                } else {
                                        entry = last;
@@ -1421,22 +1425,22 @@ retry:
                error = ext4_xattr_ibody_set(handle, inode, &i, is);
                if (error)
                        goto cleanup;
+               total_ino -= entry_size;
 
                entry = IFIRST(header);
-               if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
-                       shift_bytes = new_extra_isize;
+               if (entry_size + EXT4_XATTR_SIZE(size) >= isize_diff)
+                       shift_bytes = isize_diff;
                else
-                       shift_bytes = entry_size + size;
+                       shift_bytes = entry_size + EXT4_XATTR_SIZE(size);
                /* Adjust the offsets and shift the remaining entries ahead */
-               ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
-                       shift_bytes, (void *)raw_inode +
-                       EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
-                       (void *)header, total_ino - entry_size,
-                       inode->i_sb->s_blocksize);
+               ext4_xattr_shift_entries(entry, -shift_bytes,
+                       (void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
+                       EXT4_I(inode)->i_extra_isize + shift_bytes,
+                       (void *)header, total_ino, inode->i_sb->s_blocksize);
 
-               extra_isize += shift_bytes;
-               new_extra_isize -= shift_bytes;
-               EXT4_I(inode)->i_extra_isize = extra_isize;
+               isize_diff -= shift_bytes;
+               EXT4_I(inode)->i_extra_isize += shift_bytes;
+               header = IHDR(inode, raw_inode);
 
                i.name = b_entry_name;
                i.value = buffer;
@@ -1458,6 +1462,8 @@ retry:
                kfree(bs);
        }
        brelse(bh);
+out:
+       ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
        up_write(&EXT4_I(inode)->xattr_sem);
        return 0;
 
@@ -1469,6 +1475,10 @@ cleanup:
        kfree(is);
        kfree(bs);
        brelse(bh);
+       /*
+        * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
+        * size expansion failed.
+        */
        up_write(&EXT4_I(inode)->xattr_sem);
        return error;
 }
index c8f25f7241f06a96c3d99ebf5c82e53a6099ed60..e9a8d676c6bc53df1a238e9d07f3948f51ebe56e 100644 (file)
@@ -214,12 +214,10 @@ static int __f2fs_set_acl(struct inode *inode, int type,
        case ACL_TYPE_ACCESS:
                name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
                if (acl) {
-                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (error < 0)
+                       error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                       if (error)
                                return error;
                        set_acl_inode(fi, inode->i_mode);
-                       if (error == 0)
-                               acl = NULL;
                }
                break;
 
index d4a96af513c22f28ea1242496286d4ff1a606567..e504f548b64e3045177ae884b3352ac34bd7466e 100644 (file)
@@ -89,6 +89,9 @@ static int f2fs_create_encryption_context_from_policy(
 int f2fs_process_policy(const struct f2fs_encryption_policy *policy,
                        struct inode *inode)
 {
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
        if (policy->version != 0)
                return -EINVAL;
 
index 972eab7ac07193da485df3efc6b6c11c99dacd97..e692958d6e7859995d970d0364fbd36b1a7abd08 100644 (file)
@@ -26,6 +26,7 @@
 #include "segment.h"
 #include "trace.h"
 #include <trace/events/f2fs.h>
+#include <trace/events/android_fs.h>
 
 static void f2fs_read_end_io(struct bio *bio)
 {
@@ -1401,6 +1402,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        struct dnode_of_data dn;
        int err = 0;
 
+       trace_android_fs_datawrite_start(inode, pos, len,
+                                        current->pid, current->comm);
        trace_f2fs_write_begin(inode, pos, len, flags);
 
        f2fs_balance_fs(sbi);
@@ -1529,6 +1532,7 @@ static int f2fs_write_end(struct file *file,
 {
        struct inode *inode = page->mapping->host;
 
+       trace_android_fs_datawrite_end(inode, pos, len);
        trace_f2fs_write_end(inode, pos, len, copied);
 
        set_page_dirty(page);
@@ -1582,6 +1586,16 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
 
        trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
 
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_start(inode, offset,
+                                               count, current->pid,
+                                               current->comm);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_start(inode, offset, count,
+                                                current->pid, current->comm);
+
        if (iov_iter_rw(iter) == WRITE) {
                __allocate_data_blocks(inode, offset, count);
                if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
@@ -1595,6 +1609,13 @@ out:
        if (err < 0 && iov_iter_rw(iter) == WRITE)
                f2fs_write_failed(mapping, offset + count);
 
+       if (trace_android_fs_dataread_start_enabled() &&
+           (iov_iter_rw(iter) == READ))
+               trace_android_fs_dataread_end(inode, offset, count);
+       if (trace_android_fs_datawrite_start_enabled() &&
+           (iov_iter_rw(iter) == WRITE))
+               trace_android_fs_datawrite_end(inode, offset, count);
+
        trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err);
 
        return err;
index bda7126466c09f9b16f4d275cac5b287a06c9142..d2c5d69ba0b146bd2bd3a9b3a507f4e2655765ce 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "f2fs.h"
 #include "node.h"
+#include <trace/events/android_fs.h>
 
 bool f2fs_may_inline_data(struct inode *inode)
 {
@@ -84,14 +85,22 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
 {
        struct page *ipage;
 
+       trace_android_fs_dataread_start(inode, page_offset(page),
+                                       PAGE_SIZE, current->pid,
+                                       current->comm);
+
        ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
        if (IS_ERR(ipage)) {
+               trace_android_fs_dataread_end(inode, page_offset(page),
+                                             PAGE_SIZE);
                unlock_page(page);
                return PTR_ERR(ipage);
        }
 
        if (!f2fs_has_inline_data(inode)) {
                f2fs_put_page(ipage, 1);
+               trace_android_fs_dataread_end(inode, page_offset(page),
+                                             PAGE_SIZE);
                return -EAGAIN;
        }
 
@@ -102,6 +111,8 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
 
        SetPageUptodate(page);
        f2fs_put_page(ipage, 1);
+       trace_android_fs_dataread_end(inode, page_offset(page),
+                                     PAGE_SIZE);
        unlock_page(page);
        return 0;
 }
index 24df0a5df675957d1e3242e7287075163bcb57c5..278caed7c36776426adc96d5f1e0274366470ed9 100644 (file)
@@ -1742,14 +1742,46 @@ error:
 static int fuse_setattr(struct dentry *entry, struct iattr *attr)
 {
        struct inode *inode = d_inode(entry);
+       struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
+       int ret;
 
        if (!fuse_allow_current_process(get_fuse_conn(inode)))
                return -EACCES;
 
-       if (attr->ia_valid & ATTR_FILE)
-               return fuse_do_setattr(inode, attr, attr->ia_file);
-       else
-               return fuse_do_setattr(inode, attr, NULL);
+       if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) {
+               int kill;
+
+               attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID |
+                                   ATTR_MODE);
+               /*
+                * ia_mode calculation may have used stale i_mode.  Refresh and
+                * recalculate.
+                */
+               ret = fuse_do_getattr(inode, NULL, file);
+               if (ret)
+                       return ret;
+
+               attr->ia_mode = inode->i_mode;
+               kill = should_remove_suid(entry);
+               if (kill & ATTR_KILL_SUID) {
+                       attr->ia_valid |= ATTR_MODE;
+                       attr->ia_mode &= ~S_ISUID;
+               }
+               if (kill & ATTR_KILL_SGID) {
+                       attr->ia_valid |= ATTR_MODE;
+                       attr->ia_mode &= ~S_ISGID;
+               }
+       }
+       if (!attr->ia_valid)
+               return 0;
+
+       ret = fuse_do_setattr(inode, attr, file);
+       if (!ret) {
+               /* Directory mode changed, may need to revalidate access */
+               if (d_is_dir(entry) && (attr->ia_valid & ATTR_MODE))
+                       fuse_invalidate_entry_cache(entry);
+       }
+       return ret;
 }
 
 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
@@ -1842,6 +1874,23 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
        return ret;
 }
 
+static int fuse_verify_xattr_list(char *list, size_t size)
+{
+       size_t origsize = size;
+
+       while (size) {
+               size_t thislen = strnlen(list, size);
+
+               if (!thislen || thislen == size)
+                       return -EIO;
+
+               size -= thislen + 1;
+               list += thislen + 1;
+       }
+
+       return origsize;
+}
+
 static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
 {
        struct inode *inode = d_inode(entry);
@@ -1877,6 +1926,8 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
        ret = fuse_simple_request(fc, &args);
        if (!ret && !size)
                ret = outarg.size;
+       if (ret > 0 && size)
+               ret = fuse_verify_xattr_list(list, ret);
        if (ret == -ENOSYS) {
                fc->no_listxattr = 1;
                ret = -EOPNOTSUPP;
index c2e340d6ec6e8fc179721f2c61483f2aa1034b70..682e79965c164663a94bac2c46b9303f21a1eba8 100644 (file)
@@ -417,6 +417,15 @@ static int fuse_flush(struct file *file, fl_owner_t id)
        fuse_sync_writes(inode);
        mutex_unlock(&inode->i_mutex);
 
+       if (test_bit(AS_ENOSPC, &file->f_mapping->flags) &&
+           test_and_clear_bit(AS_ENOSPC, &file->f_mapping->flags))
+               err = -ENOSPC;
+       if (test_bit(AS_EIO, &file->f_mapping->flags) &&
+           test_and_clear_bit(AS_EIO, &file->f_mapping->flags))
+               err = -EIO;
+       if (err)
+               return err;
+
        req = fuse_get_req_nofail_nopages(fc, file);
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
@@ -462,6 +471,21 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
                goto out;
 
        fuse_sync_writes(inode);
+
+       /*
+        * Due to implementation of fuse writeback
+        * filemap_write_and_wait_range() does not catch errors.
+        * We have to do this directly after fuse_sync_writes()
+        */
+       if (test_bit(AS_ENOSPC, &file->f_mapping->flags) &&
+           test_and_clear_bit(AS_ENOSPC, &file->f_mapping->flags))
+               err = -ENOSPC;
+       if (test_bit(AS_EIO, &file->f_mapping->flags) &&
+           test_and_clear_bit(AS_EIO, &file->f_mapping->flags))
+               err = -EIO;
+       if (err)
+               goto out;
+
        err = sync_inode_metadata(inode, 1);
        if (err)
                goto out;
@@ -516,13 +540,13 @@ void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
        req->out.args[0].size = count;
 }
 
-static void fuse_release_user_pages(struct fuse_req *req, int write)
+static void fuse_release_user_pages(struct fuse_req *req, bool should_dirty)
 {
        unsigned i;
 
        for (i = 0; i < req->num_pages; i++) {
                struct page *page = req->pages[i];
-               if (write)
+               if (should_dirty)
                        set_page_dirty_lock(page);
                put_page(page);
        }
@@ -1307,6 +1331,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
                       loff_t *ppos, int flags)
 {
        int write = flags & FUSE_DIO_WRITE;
+       bool should_dirty = !write && iter_is_iovec(iter);
        int cuse = flags & FUSE_DIO_CUSE;
        struct file *file = io->file;
        struct inode *inode = file->f_mapping->host;
@@ -1351,7 +1376,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
                        nres = fuse_send_read(req, io, pos, nbytes, owner);
 
                if (!io->async)
-                       fuse_release_user_pages(req, !write);
+                       fuse_release_user_pages(req, should_dirty);
                if (req->out.h.error) {
                        if (!res)
                                res = req->out.h.error;
index 2913db2a5b99bee2b01b79d07b1451f752f0ec01..0d5e8e59b390e93397910c16755d854f4d67a984 100644 (file)
@@ -926,7 +926,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
                FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
-               FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
+               FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
                FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
                FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT;
        req->in.h.opcode = FUSE_INIT;
index 1be3b061c05c921f60ddfebcce809875fe8de662..ff0ac96a8e7bd6eea557541e47ec90a9eb8555ff 100644 (file)
@@ -79,17 +79,11 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        if (type == ACL_TYPE_ACCESS) {
                umode_t mode = inode->i_mode;
 
-               error = posix_acl_equiv_mode(acl, &mode);
-               if (error < 0)
+               error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+               if (error)
                        return error;
-
-               if (error == 0)
-                       acl = NULL;
-
-               if (mode != inode->i_mode) {
-                       inode->i_mode = mode;
+               if (mode != inode->i_mode)
                        mark_inode_dirty(inode);
-               }
        }
 
        if (acl) {
index df0c9af68d05ef0df5a127d53562677bc8a2d882..71b3087b7e327db93192252daa9b3cb15a2ef8c1 100644 (file)
@@ -68,8 +68,8 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
        case ACL_TYPE_ACCESS:
                xattr_name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       err = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (err < 0)
+                       err = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                       if (err)
                                return err;
                }
                err = 0;
index 5a7b3229b956ea99fe57b1e88f7d8234b5fee690..f34d6f5a5aca38d01043f9c94f67359f9cf84528 100644 (file)
@@ -959,10 +959,11 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
 
        if (S_ISLNK(root_inode->i_mode)) {
                char *name = follow_link(host_root_path);
-               if (IS_ERR(name))
+               if (IS_ERR(name)) {
                        err = PTR_ERR(name);
-               else
-                       err = read_name(root_inode, name);
+                       goto out_put;
+               }
+               err = read_name(root_inode, name);
                kfree(name);
                if (err)
                        goto out_put;
index 1be5f9003eb38852f68957fcd287cdd5b820b310..b0edef500590c3e49cd5f632640add63426a39d5 100644 (file)
@@ -1733,8 +1733,8 @@ static int __remove_privs(struct dentry *dentry, int kill)
  */
 int file_remove_privs(struct file *file)
 {
-       struct dentry *dentry = file->f_path.dentry;
-       struct inode *inode = d_inode(dentry);
+       struct dentry *dentry = file_dentry(file);
+       struct inode *inode = file_inode(file);
        int kill;
        int error = 0;
 
@@ -1742,7 +1742,7 @@ int file_remove_privs(struct file *file)
        if (IS_NOSEC(inode))
                return 0;
 
-       kill = file_needs_remove_privs(file);
+       kill = dentry_needs_remove_privs(dentry);
        if (kill < 0)
                return kill;
        if (kill)
index d67a16f2a45df8fcce56b9ff3ec56f334d951c9c..350f67fb5b9c0da64ebbe87e106e6ef7d236f4da 100644 (file)
@@ -690,6 +690,11 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
        pri_bh = NULL;
 
 root_found:
+       /* We don't support read-write mounts */
+       if (!(s->s_flags & MS_RDONLY)) {
+               error = -EACCES;
+               goto out_freebh;
+       }
 
        if (joliet_level && (pri == NULL || !opt.rock)) {
                /* This is the case of Joliet with the norock mount flag.
@@ -1503,9 +1508,6 @@ struct inode *__isofs_iget(struct super_block *sb,
 static struct dentry *isofs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       /* We don't support read-write mounts */
-       if (!(flags & MS_RDONLY))
-               return ERR_PTR(-EACCES);
        return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
 }
 
index 36345fefa3ffee1f66e56c908cca50b282abeba5..2d964ce4560609778c8d88e9d1d6e4ce7539d3a8 100644 (file)
@@ -124,7 +124,7 @@ static int journal_submit_commit_record(journal_t *journal,
        struct commit_header *tmp;
        struct buffer_head *bh;
        int ret;
-       struct timespec now = current_kernel_time();
+       struct timespec64 now = current_kernel_time64();
 
        *cbh = NULL;
 
index ca181e81c765518d4a599025c914adbac626e739..fa1b8e0dcacfc22ebe42c753767295eca5876e24 100644 (file)
@@ -1156,6 +1156,7 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
                JBUFFER_TRACE(jh, "file as BJ_Reserved");
                spin_lock(&journal->j_list_lock);
                __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
+               spin_unlock(&journal->j_list_lock);
        } else if (jh->b_transaction == journal->j_committing_transaction) {
                /* first access by this transaction */
                jh->b_modified = 0;
@@ -1163,8 +1164,8 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
                JBUFFER_TRACE(jh, "set next transaction");
                spin_lock(&journal->j_list_lock);
                jh->b_next_transaction = transaction;
+               spin_unlock(&journal->j_list_lock);
        }
-       spin_unlock(&journal->j_list_lock);
        jbd_unlock_bh_state(bh);
 
        /*
index 2f7a3c09048999f4365c3e5612ffdf18e9c65d54..f9f86f87d32b82ddb7b78ba30c4270f3caac9a8a 100644 (file)
@@ -235,9 +235,10 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        case ACL_TYPE_ACCESS:
                xprefix = JFFS2_XPREFIX_ACL_ACCESS;
                if (acl) {
-                       umode_t mode = inode->i_mode;
-                       rc = posix_acl_equiv_mode(acl, &mode);
-                       if (rc < 0)
+                       umode_t mode;
+
+                       rc = posix_acl_update_mode(inode, &mode, &acl);
+                       if (rc)
                                return rc;
                        if (inode->i_mode != mode) {
                                struct iattr attr;
@@ -249,8 +250,6 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                                if (rc < 0)
                                        return rc;
                        }
-                       if (rc == 0)
-                               acl = NULL;
                }
                break;
        case ACL_TYPE_DEFAULT:
index 0c8ca830b113e62246d3f2629846958bdee32775..9fad9f4fe8830f02dcb9ebe02d8052ab307f97e0 100644 (file)
@@ -84,13 +84,11 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
        case ACL_TYPE_ACCESS:
                ea_name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       rc = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (rc < 0)
+                       rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                       if (rc)
                                return rc;
                        inode->i_ctime = CURRENT_TIME;
                        mark_inode_dirty(inode);
-                       if (rc == 0)
-                               acl = NULL;
                }
                break;
        case ACL_TYPE_DEFAULT:
index 7247252ee9b1beffa3c624cb54db676a707fffe2..6e9a912d394c93c203d5ae19488ccbe598988cfe 100644 (file)
@@ -833,21 +833,35 @@ repeat:
        mutex_lock(&kernfs_mutex);
 
        list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
+               struct kernfs_node *parent;
                struct inode *inode;
-               struct dentry *dentry;
 
+               /*
+                * We want fsnotify_modify() on @kn but as the
+                * modifications aren't originating from userland don't
+                * have the matching @file available.  Look up the inodes
+                * and generate the events manually.
+                */
                inode = ilookup(info->sb, kn->ino);
                if (!inode)
                        continue;
 
-               dentry = d_find_any_alias(inode);
-               if (dentry) {
-                       fsnotify_parent(NULL, dentry, FS_MODIFY);
-                       fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
-                                NULL, 0);
-                       dput(dentry);
+               parent = kernfs_get_parent(kn);
+               if (parent) {
+                       struct inode *p_inode;
+
+                       p_inode = ilookup(info->sb, parent->ino);
+                       if (p_inode) {
+                               fsnotify(p_inode, FS_MODIFY | FS_EVENT_ON_CHILD,
+                                        inode, FSNOTIFY_EVENT_INODE, kn->name, 0);
+                               iput(p_inode);
+                       }
+
+                       kernfs_put(parent);
                }
 
+               fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
+                        kn->name, 0);
                iput(inode);
        }
 
index 6333263b7bc86a975f1d9fd5487276a15991bfb4..8eddae23e10bed47430704cfd897b8e3a491f88b 100644 (file)
@@ -1602,7 +1602,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
 {
        struct file_lock *fl, *my_fl = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file_inode(filp);
        struct file_lock_context *ctx;
        bool is_deleg = (*flp)->fl_flags & FL_DELEG;
        int error;
index 1480d3a180370fe3922a7724e613d09b896f9d00..5c65d8942692fd468558c9cac0052216af75a2bb 100644 (file)
 #include <linux/cleancache.h>
 #include "internal.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/android_fs.h>
+
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_end);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_end);
+
 /*
  * I/O completion handler for multipage BIOs.
  *
@@ -47,6 +55,16 @@ static void mpage_end_io(struct bio *bio)
        struct bio_vec *bv;
        int i;
 
+       if (trace_android_fs_dataread_end_enabled() &&
+           (bio_data_dir(bio) == READ)) {
+               struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+               if (first_page != NULL)
+                       trace_android_fs_dataread_end(first_page->mapping->host,
+                                                     page_offset(first_page),
+                                                     bio->bi_iter.bi_size);
+       }
+
        bio_for_each_segment_all(bv, bio, i) {
                struct page *page = bv->bv_page;
                page_endio(page, bio_data_dir(bio), bio->bi_error);
@@ -57,6 +75,18 @@ static void mpage_end_io(struct bio *bio)
 
 static struct bio *mpage_bio_submit(int rw, struct bio *bio)
 {
+       if (trace_android_fs_dataread_start_enabled() && (rw == READ)) {
+               struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+               if (first_page != NULL) {
+                       trace_android_fs_dataread_start(
+                               first_page->mapping->host,
+                               page_offset(first_page),
+                               bio->bi_iter.bi_size,
+                               current->pid,
+                               current->comm);
+               }
+       }
        bio->bi_end_io = mpage_end_io;
        guard_bio_eod(rw, bio);
        submit_bio(rw, bio);
index 209ca7737cb2207ef020e90d159ae8f605c7de0a..0b0acba72a715aaa4ba22c6241c2ed3b10183121 100644 (file)
@@ -887,6 +887,7 @@ static inline int may_follow_link(struct nameidata *nd)
 {
        const struct inode *inode;
        const struct inode *parent;
+       kuid_t puid;
 
        if (!sysctl_protected_symlinks)
                return 0;
@@ -902,7 +903,8 @@ static inline int may_follow_link(struct nameidata *nd)
                return 0;
 
        /* Allowed if parent directory and link owner match. */
-       if (uid_eq(parent->i_uid, inode->i_uid))
+       puid = parent->i_uid;
+       if (uid_valid(puid) && uid_eq(puid, inode->i_uid))
                return 0;
 
        if (nd->flags & LOOKUP_RCU)
index 33064fcbfff94e50ab642662684f122888e144b6..5be02a0635be0e1e84e5a88bed1a5b2ceb5ef6af 100644 (file)
@@ -1562,6 +1562,7 @@ void __detach_mounts(struct dentry *dentry)
                goto out_unlock;
 
        lock_mount_hash();
+       event++;
        while (!hlist_empty(&mp->m_list)) {
                mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
                if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
index a7f2e6e3330525c1069c524f8b56960e780f7f4b..52a28311e2a4b2d72063cf36ac9e4296481211b7 100644 (file)
@@ -275,6 +275,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
 err_socks:
        svc_rpcb_cleanup(serv, net);
 err_bind:
+       nn->cb_users[minorversion]--;
        dprintk("NFS: Couldn't create callback socket: err = %d; "
                        "net = %p\n", ret, net);
        return ret;
index 646cdac73488e96041f2bcad33b4220b096da684..e2e857affbf2a6666be5e0818bb8b52f87e621c4 100644 (file)
@@ -912,7 +912,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
        if (hdr_arg.minorversion == 0) {
                cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
                if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
-                       return rpc_drop_reply;
+                       goto out_invalidcred;
        }
 
        cps.minorversion = hdr_arg.minorversion;
@@ -940,6 +940,10 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
        nfs_put_client(cps.clp);
        dprintk("%s: done, status = %u\n", __func__, ntohl(status));
        return rpc_success;
+
+out_invalidcred:
+       pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
+       return rpc_autherr_badcred;
 }
 
 /*
index 5166adcfc0fb2379ed75c37b0aa09c8da7550607..7af5eeabc80e1cabb6d695a72cfb8076d82cb879 100644 (file)
@@ -41,6 +41,17 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
        set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
 }
 
+static bool
+nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
+               fmode_t flags)
+{
+       if (delegation != NULL && (delegation->type & flags) == flags &&
+           !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
+           !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
+               return true;
+       return false;
+}
+
 static int
 nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
 {
@@ -50,8 +61,7 @@ nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
        flags &= FMODE_READ|FMODE_WRITE;
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
-       if (delegation != NULL && (delegation->type & flags) == flags &&
-           !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
+       if (nfs4_is_valid_delegation(delegation, flags)) {
                if (mark)
                        nfs_mark_delegation_referenced(delegation);
                ret = 1;
@@ -892,7 +902,7 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
        flags &= FMODE_READ|FMODE_WRITE;
        rcu_read_lock();
        delegation = rcu_dereference(nfsi->delegation);
-       ret = (delegation != NULL && (delegation->type & flags) == flags);
+       ret = nfs4_is_valid_delegation(delegation, flags);
        if (ret) {
                nfs4_stateid_copy(dst, &delegation->stateid);
                nfs_mark_delegation_referenced(delegation);
index 02ec07973bc43003bb76b5aaeb8a950094c9ac60..fd8da630fd22edc442e6ad8c0974726759065bb7 100644 (file)
@@ -374,8 +374,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
                return -EAGAIN;
        }
 
-       if (data->verf.committed == NFS_UNSTABLE)
-               pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
+       pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
 
        return 0;
 }
index 2a2e2d8ddee52e0e0473864e4e05cbd5215a37b5..54313322ee5bba934f2f1cb76cd9280c8e22ce8b 100644 (file)
@@ -1414,8 +1414,7 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
                return -EAGAIN;
        }
 
-       if (data->verf.committed == NFS_UNSTABLE
-           && ff_layout_need_layoutcommit(data->lseg))
+       if (ff_layout_need_layoutcommit(data->lseg))
                pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
 
        return 0;
index 6b1ce9825430c7c9659b49ac9bff545b620bd7bb..7f1a0fb8c49351685d18aef2e22f5d630c892f35 100644 (file)
@@ -269,6 +269,7 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *server,
        task = rpc_run_task(&task_setup);
        if (IS_ERR(task))
                return PTR_ERR(task);
+       rpc_put_task(task);
        return 0;
 }
 
index fc215ab4dcd51a6d879da5dbcabf3710b4dd281e..3c69299c01abe567eb2c1947ab6818c80897fa5c 100644 (file)
@@ -7424,12 +7424,20 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        trace_nfs4_create_session(clp, status);
 
+       switch (status) {
+       case -NFS4ERR_STALE_CLIENTID:
+       case -NFS4ERR_DELAY:
+       case -ETIMEDOUT:
+       case -EACCES:
+       case -EAGAIN:
+               goto out;
+       };
+
+       clp->cl_seqid++;
        if (!status) {
                /* Verify the session's negotiated channel_attrs values */
                status = nfs4_verify_channel_attrs(&args, &res);
                /* Increment the clientid slot sequence id */
-               if (clp->cl_seqid == res.seqid)
-                       clp->cl_seqid++;
                if (status)
                        goto out;
                nfs4_update_session(session, &res);
index d854693a15b0e2443779986552d29d9db3f6cdc2..82dc3035ea45f088ec726eda6b18d3131957c0d0 100644 (file)
@@ -1493,6 +1493,9 @@ restart:
                                        __func__, status);
                        case -ENOENT:
                        case -ENOMEM:
+                       case -EACCES:
+                       case -EROFS:
+                       case -EIO:
                        case -ESTALE:
                                /* Open state on this file cannot be recovered */
                                nfs4_state_mark_recovery_failed(state, status);
index bec0384499f76dd1acc8fb13bbf34c2ee17e6a9b..5cd3568eea063a42812c03324acddfb5833975fd 100644 (file)
@@ -365,6 +365,9 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
 static bool
 pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
 {
+       /* Serialise LAYOUTGET/LAYOUTRETURN */
+       if (atomic_read(&lo->plh_outstanding) != 0)
+               return false;
        if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
                return false;
        lo->plh_return_iomode = 0;
@@ -1530,6 +1533,7 @@ pnfs_update_layout(struct inode *ino,
                goto out;
 
 lookup_again:
+       nfs4_client_recover_expired_lease(clp);
        first = false;
        spin_lock(&ino->i_lock);
        lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
index 7b93164069307346ea43f130e3883959ae6576b6..7a9b6e347249e0426abf7ec35745feceecab446d 100644 (file)
@@ -1261,6 +1261,9 @@ int nfs_updatepage(struct file *file, struct page *page,
        dprintk("NFS:       nfs_updatepage(%pD2 %d@%lld)\n",
                file, count, (long long)(page_file_offset(page) + offset));
 
+       if (!count)
+               goto out;
+
        if (nfs_can_extend_write(file, page, inode)) {
                count = max(count + offset, nfs_page_length(page));
                offset = 0;
@@ -1271,7 +1274,7 @@ int nfs_updatepage(struct file *file, struct page *page,
                nfs_set_pageerror(page);
        else
                __set_page_dirty_nobuffers(page);
-
+out:
        dprintk("NFS:       nfs_updatepage returns %d (isize %lld)\n",
                        status, (long long)i_size_read(inode));
        return status;
index ed2f64ca49dec8f0d750ae52f301418a31b2038e..55638110cb0605f05a3fe034a8cc73918b9abec2 100644 (file)
@@ -1200,27 +1200,6 @@ free_ol_stateid_reaplist(struct list_head *reaplist)
        }
 }
 
-static void release_lockowner(struct nfs4_lockowner *lo)
-{
-       struct nfs4_client *clp = lo->lo_owner.so_client;
-       struct nfs4_ol_stateid *stp;
-       struct list_head reaplist;
-
-       INIT_LIST_HEAD(&reaplist);
-
-       spin_lock(&clp->cl_lock);
-       unhash_lockowner_locked(lo);
-       while (!list_empty(&lo->lo_owner.so_stateids)) {
-               stp = list_first_entry(&lo->lo_owner.so_stateids,
-                               struct nfs4_ol_stateid, st_perstateowner);
-               WARN_ON(!unhash_lock_stateid(stp));
-               put_ol_stateid_locked(stp, &reaplist);
-       }
-       spin_unlock(&clp->cl_lock);
-       free_ol_stateid_reaplist(&reaplist);
-       nfs4_put_stateowner(&lo->lo_owner);
-}
-
 static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
                                       struct list_head *reaplist)
 {
@@ -4882,6 +4861,32 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        return nfs_ok;
 }
 
+static __be32
+nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
+{
+       struct nfs4_ol_stateid *stp = openlockstateid(s);
+       __be32 ret;
+
+       mutex_lock(&stp->st_mutex);
+
+       ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
+       if (ret)
+               goto out;
+
+       ret = nfserr_locks_held;
+       if (check_for_locks(stp->st_stid.sc_file,
+                           lockowner(stp->st_stateowner)))
+               goto out;
+
+       release_lock_stateid(stp);
+       ret = nfs_ok;
+
+out:
+       mutex_unlock(&stp->st_mutex);
+       nfs4_put_stid(s);
+       return ret;
+}
+
 __be32
 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                   struct nfsd4_free_stateid *free_stateid)
@@ -4889,7 +4894,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        stateid_t *stateid = &free_stateid->fr_stateid;
        struct nfs4_stid *s;
        struct nfs4_delegation *dp;
-       struct nfs4_ol_stateid *stp;
        struct nfs4_client *cl = cstate->session->se_client;
        __be32 ret = nfserr_bad_stateid;
 
@@ -4908,18 +4912,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                ret = nfserr_locks_held;
                break;
        case NFS4_LOCK_STID:
-               ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
-               if (ret)
-                       break;
-               stp = openlockstateid(s);
-               ret = nfserr_locks_held;
-               if (check_for_locks(stp->st_stid.sc_file,
-                                   lockowner(stp->st_stateowner)))
-                       break;
-               WARN_ON(!unhash_lock_stateid(stp));
+               atomic_inc(&s->sc_count);
                spin_unlock(&cl->cl_lock);
-               nfs4_put_stid(s);
-               ret = nfs_ok;
+               ret = nfsd4_free_lock_stateid(stateid, s);
                goto out;
        case NFS4_REVOKED_DELEG_STID:
                dp = delegstateid(s);
@@ -5486,7 +5481,7 @@ static __be32
 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
                            struct nfs4_ol_stateid *ost,
                            struct nfsd4_lock *lock,
-                           struct nfs4_ol_stateid **lst, bool *new)
+                           struct nfs4_ol_stateid **plst, bool *new)
 {
        __be32 status;
        struct nfs4_file *fi = ost->st_stid.sc_file;
@@ -5494,7 +5489,9 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
        struct nfs4_client *cl = oo->oo_owner.so_client;
        struct inode *inode = d_inode(cstate->current_fh.fh_dentry);
        struct nfs4_lockowner *lo;
+       struct nfs4_ol_stateid *lst;
        unsigned int strhashval;
+       bool hashed;
 
        lo = find_lockowner_str(cl, &lock->lk_new_owner);
        if (!lo) {
@@ -5510,12 +5507,27 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
                        goto out;
        }
 
-       *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
-       if (*lst == NULL) {
+retry:
+       lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
+       if (lst == NULL) {
                status = nfserr_jukebox;
                goto out;
        }
+
+       mutex_lock(&lst->st_mutex);
+
+       /* See if it's still hashed to avoid race with FREE_STATEID */
+       spin_lock(&cl->cl_lock);
+       hashed = !list_empty(&lst->st_perfile);
+       spin_unlock(&cl->cl_lock);
+
+       if (!hashed) {
+               mutex_unlock(&lst->st_mutex);
+               nfs4_put_stid(&lst->st_stid);
+               goto retry;
+       }
        status = nfs_ok;
+       *plst = lst;
 out:
        nfs4_put_stateowner(&lo->lo_owner);
        return status;
@@ -5582,8 +5594,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                status = lookup_or_create_lock_state(cstate, open_stp, lock,
                                                        &lock_stp, &new);
-               if (status == nfs_ok)
-                       mutex_lock(&lock_stp->st_mutex);
        } else {
                status = nfs4_preprocess_seqid_op(cstate,
                                       lock->lk_old_lock_seqid,
@@ -5921,6 +5931,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        __be32 status;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        struct nfs4_client *clp;
+       LIST_HEAD (reaplist);
 
        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
                clid->cl_boot, clid->cl_id);
@@ -5951,9 +5962,23 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
                nfs4_get_stateowner(sop);
                break;
        }
+       if (!lo) {
+               spin_unlock(&clp->cl_lock);
+               return status;
+       }
+
+       unhash_lockowner_locked(lo);
+       while (!list_empty(&lo->lo_owner.so_stateids)) {
+               stp = list_first_entry(&lo->lo_owner.so_stateids,
+                                      struct nfs4_ol_stateid,
+                                      st_perstateowner);
+               WARN_ON(!unhash_lock_stateid(stp));
+               put_ol_stateid_locked(stp, &reaplist);
+       }
        spin_unlock(&clp->cl_lock);
-       if (lo)
-               release_lockowner(lo);
+       free_ol_stateid_reaplist(&reaplist);
+       nfs4_put_stateowner(&lo->lo_owner);
+
        return status;
 }
 
index 69bd801afb53b987ea3fa862fd2a444b41d2efdb..37e49cb2ac4c4a61d61357272a2ee168165bf793 100644 (file)
@@ -443,7 +443,7 @@ static int nilfs_valid_sb(struct nilfs_super_block *sbp)
        if (!sbp || le16_to_cpu(sbp->s_magic) != NILFS_SUPER_MAGIC)
                return 0;
        bytes = le16_to_cpu(sbp->s_bytes);
-       if (bytes > BLOCK_SIZE)
+       if (bytes < sumoff + 4 || bytes > BLOCK_SIZE)
                return 0;
        crc = crc32_le(le32_to_cpu(sbp->s_crc_seed), (unsigned char *)sbp,
                       sumoff);
index d2f97ecca6a5dfe6091d56da09871449574524bf..e0e5f7c3c99fe076d11dc5d907b543d5e5376671 100644 (file)
@@ -67,18 +67,7 @@ static int fanotify_get_response(struct fsnotify_group *group,
 
        pr_debug("%s: group=%p event=%p\n", __func__, group, event);
 
-       wait_event(group->fanotify_data.access_waitq, event->response ||
-                               atomic_read(&group->fanotify_data.bypass_perm));
-
-       if (!event->response) { /* bypass_perm set */
-               /*
-                * Event was canceled because group is being destroyed. Remove
-                * it from group's event list because we are responsible for
-                * freeing the permission event.
-                */
-               fsnotify_remove_event(group, &event->fae.fse);
-               return 0;
-       }
+       wait_event(group->fanotify_data.access_waitq, event->response);
 
        /* userspace responded, convert to something usable */
        switch (event->response) {
index 8e8e6bcd1d43d266346bac16dbb12ff8c893bae2..a64313868d3a15cefca72b5e228e798d98a43a1e 100644 (file)
@@ -358,16 +358,20 @@ static int fanotify_release(struct inode *ignored, struct file *file)
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
        struct fanotify_perm_event_info *event, *next;
+       struct fsnotify_event *fsn_event;
 
        /*
-        * There may be still new events arriving in the notification queue
-        * but since userspace cannot use fanotify fd anymore, no event can
-        * enter or leave access_list by now.
+        * Stop new events from arriving in the notification queue. since
+        * userspace cannot use fanotify fd anymore, no event can enter or
+        * leave access_list by now either.
         */
-       spin_lock(&group->fanotify_data.access_lock);
-
-       atomic_inc(&group->fanotify_data.bypass_perm);
+       fsnotify_group_stop_queueing(group);
 
+       /*
+        * Process all permission events on access_list and notification queue
+        * and simulate reply from userspace.
+        */
+       spin_lock(&group->fanotify_data.access_lock);
        list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
                                 fae.fse.list) {
                pr_debug("%s: found group=%p event=%p\n", __func__, group,
@@ -379,12 +383,21 @@ static int fanotify_release(struct inode *ignored, struct file *file)
        spin_unlock(&group->fanotify_data.access_lock);
 
        /*
-        * Since bypass_perm is set, newly queued events will not wait for
-        * access response. Wake up the already sleeping ones now.
-        * synchronize_srcu() in fsnotify_destroy_group() will wait for all
-        * processes sleeping in fanotify_handle_event() waiting for access
-        * response and thus also for all permission events to be freed.
+        * Destroy all non-permission events. For permission events just
+        * dequeue them and set the response. They will be freed once the
+        * response is consumed and fanotify_get_response() returns.
         */
+       mutex_lock(&group->notification_mutex);
+       while (!fsnotify_notify_queue_is_empty(group)) {
+               fsn_event = fsnotify_remove_first_event(group);
+               if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS))
+                       fsnotify_destroy_event(group, fsn_event);
+               else
+                       FANOTIFY_PE(fsn_event)->response = FAN_ALLOW;
+       }
+       mutex_unlock(&group->notification_mutex);
+
+       /* Response for all permission events it set, wakeup waiters */
        wake_up(&group->fanotify_data.access_waitq);
 #endif
 
@@ -755,7 +768,6 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        spin_lock_init(&group->fanotify_data.access_lock);
        init_waitqueue_head(&group->fanotify_data.access_waitq);
        INIT_LIST_HEAD(&group->fanotify_data.access_list);
-       atomic_set(&group->fanotify_data.bypass_perm, 0);
 #endif
        switch (flags & FAN_ALL_CLASS_BITS) {
        case FAN_CLASS_NOTIF:
index d16b62cb28544a147183c3780e3a61ffa246c8bb..18eb30c6bd8fcc6dddc130941fa43182295e6907 100644 (file)
@@ -39,6 +39,17 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
        kfree(group);
 }
 
+/*
+ * Stop queueing new events for this group. Once this function returns
+ * fsnotify_add_event() will not add any new events to the group's queue.
+ */
+void fsnotify_group_stop_queueing(struct fsnotify_group *group)
+{
+       mutex_lock(&group->notification_mutex);
+       group->shutdown = true;
+       mutex_unlock(&group->notification_mutex);
+}
+
 /*
  * Trying to get rid of a group. Remove all marks, flush all events and release
  * the group reference.
@@ -47,6 +58,14 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
  */
 void fsnotify_destroy_group(struct fsnotify_group *group)
 {
+       /*
+        * Stop queueing new events. The code below is careful enough to not
+        * require this but fanotify needs to stop queuing events even before
+        * fsnotify_destroy_group() is called and this makes the other callers
+        * of fsnotify_destroy_group() to see the same behavior.
+        */
+       fsnotify_group_stop_queueing(group);
+
        /* clear all inode marks for this group */
        fsnotify_clear_marks_by_group(group);
 
index a95d8e037aebe24ba36421861d3abaad6f7dfc89..e455e83ceeebc9ea5cb0b3166e10bd505cec43f1 100644 (file)
@@ -82,7 +82,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
  * Add an event to the group notification queue.  The group can later pull this
  * event off the queue to deal with.  The function returns 0 if the event was
  * added to the queue, 1 if the event was merged with some other queued event,
- * 2 if the queue of events has overflown.
+ * 2 if the event was not queued - either the queue of events has overflown
+ * or the group is shutting down.
  */
 int fsnotify_add_event(struct fsnotify_group *group,
                       struct fsnotify_event *event,
@@ -96,6 +97,11 @@ int fsnotify_add_event(struct fsnotify_group *group,
 
        mutex_lock(&group->notification_mutex);
 
+       if (group->shutdown) {
+               mutex_unlock(&group->notification_mutex);
+               return 2;
+       }
+
        if (group->q_len >= group->max_events) {
                ret = 2;
                /* Queue overflow event only if it isn't already queued */
@@ -125,21 +131,6 @@ queue:
        return ret;
 }
 
-/*
- * Remove @event from group's notification queue. It is the responsibility of
- * the caller to destroy the event.
- */
-void fsnotify_remove_event(struct fsnotify_group *group,
-                          struct fsnotify_event *event)
-{
-       mutex_lock(&group->notification_mutex);
-       if (!list_empty(&event->list)) {
-               list_del_init(&event->list);
-               group->q_len--;
-       }
-       mutex_unlock(&group->notification_mutex);
-}
-
 /*
  * Remove and return the first event from the notification list.  It is the
  * responsibility of the caller to destroy the obtained event
index 2162434728c022ab4651904b778c21d958ca802d..164307b994052cb658b08cb8c28da524dedfe644 100644 (file)
@@ -241,13 +241,11 @@ int ocfs2_set_acl(handle_t *handle,
        case ACL_TYPE_ACCESS:
                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
                if (acl) {
-                       umode_t mode = inode->i_mode;
-                       ret = posix_acl_equiv_mode(acl, &mode);
-                       if (ret < 0)
-                               return ret;
+                       umode_t mode;
 
-                       if (ret == 0)
-                               acl = NULL;
+                       ret = posix_acl_update_mode(inode, &mode, &acl);
+                       if (ret)
+                               return ret;
 
                        ret = ocfs2_acl_set_mode(inode, di_bh,
                                                 handle, mode);
index f90931335c6b28af89cc0537b8d3fec48a089300..2e11658676eb2145fbd7de33e25872c0778532cb 100644 (file)
@@ -262,7 +262,6 @@ 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);
@@ -329,7 +328,6 @@ 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 master returns DLM_NORMAL and then down before sending ast,
         * it may have already been moved to granted queue, reset to
@@ -338,12 +336,14 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm,
                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);
+       } else if (!lock->convert_pending) {
+               mlog(0, "%s: res %.*s, owner died and lock has been moved back "
+                               "to granted list, retry convert.\n",
+                               dlm->name, res->lockname.len, res->lockname.name);
                status = DLM_RECOVERING;
        }
+
+       lock->convert_pending = 0;
 bail:
        spin_unlock(&res->spinlock);
 
index 77d30cbd944d7c7d834456469677032fdb3d55a1..56dd3957cc91c058e41dea9b9936f4dcf871d623 100644 (file)
@@ -1536,7 +1536,8 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
                                       u64 start, u64 len)
 {
        int ret = 0;
-       u64 tmpend, end = start + len;
+       u64 tmpend = 0;
+       u64 end = start + len;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        unsigned int csize = osb->s_clustersize;
        handle_t *handle;
@@ -1568,18 +1569,31 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
        }
 
        /*
-        * We want to get the byte offset of the end of the 1st cluster.
+        * If start is on a cluster boundary and end is somewhere in another
+        * cluster, we have not COWed the cluster starting at start, unless
+        * end is also within the same cluster. So, in this case, we skip this
+        * first call to ocfs2_zero_range_for_truncate() truncate and move on
+        * to the next one.
         */
-       tmpend = (u64)osb->s_clustersize + (start & ~(osb->s_clustersize - 1));
-       if (tmpend > end)
-               tmpend = end;
+       if ((start & (csize - 1)) != 0) {
+               /*
+                * We want to get the byte offset of the end of the 1st
+                * cluster.
+                */
+               tmpend = (u64)osb->s_clustersize +
+                       (start & ~(osb->s_clustersize - 1));
+               if (tmpend > end)
+                       tmpend = end;
 
-       trace_ocfs2_zero_partial_clusters_range1((unsigned long long)start,
-                                                (unsigned long long)tmpend);
+               trace_ocfs2_zero_partial_clusters_range1(
+                       (unsigned long long)start,
+                       (unsigned long long)tmpend);
 
-       ret = ocfs2_zero_range_for_truncate(inode, handle, start, tmpend);
-       if (ret)
-               mlog_errno(ret);
+               ret = ocfs2_zero_range_for_truncate(inode, handle, start,
+                                                   tmpend);
+               if (ret)
+                       mlog_errno(ret);
+       }
 
        if (tmpend < end) {
                /*
index eff6319d50373c05d4d829b0fd83fa784d5f187b..ea0dd9ee138d2209cdd2017ff52070faf5116754 100644 (file)
@@ -25,6 +25,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
        ssize_t list_size, size, value_size = 0;
        char *buf, *name, *value = NULL;
        int uninitialized_var(error);
+       size_t slen;
 
        if (!old->d_inode->i_op->getxattr ||
            !new->d_inode->i_op->getxattr)
@@ -47,7 +48,18 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
                goto out;
        }
 
-       for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
+       for (name = buf; list_size; name += slen) {
+               slen = strnlen(name, list_size) + 1;
+
+               /* underlying fs providing us with an broken xattr list? */
+               if (WARN_ON(slen > list_size)) {
+                       error = -EIO;
+                       break;
+               }
+               list_size -= slen;
+
+               if (ovl_is_private_xattr(name))
+                       continue;
 retry:
                size = vfs_getxattr(old, name, value, value_size);
                if (size == -ERANGE)
index ba5ef733951fdc42ed55d7847d749da0b33e9de9..327177df03a5ca00b1f3839034622eca3eb1aacf 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/xattr.h>
 #include <linux/security.h>
 #include <linux/cred.h>
+#include <linux/atomic.h>
 #include "overlayfs.h"
 
 void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
@@ -35,8 +36,10 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir, struct dentry *dentry)
 {
        struct dentry *temp;
        char name[20];
+       static atomic_t temp_id = ATOMIC_INIT(0);
 
-       snprintf(name, sizeof(name), "#%lx", (unsigned long) dentry);
+       /* counter is allowed to wrap, since temp dentries are ephemeral */
+       snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id));
 
        temp = lookup_one_len(name, workdir, strlen(name));
        if (!IS_ERR(temp) && temp->d_inode) {
index 0597820f5d9d72f19fbaa185cbde5249bf0fb2a9..220b04f045234514e344eda63da5a60e0b584087 100644 (file)
@@ -63,6 +63,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
        if (!err) {
                upperdentry = ovl_dentry_upper(dentry);
 
+               if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
+                       attr->ia_valid &= ~ATTR_MODE;
+
                mutex_lock(&upperdentry->d_inode->i_mutex);
                err = notify_change(upperdentry, attr, NULL);
                if (!err)
@@ -216,7 +219,7 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 }
 
 
-static bool ovl_is_private_xattr(const char *name)
+bool ovl_is_private_xattr(const char *name)
 {
        return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
 }
@@ -274,7 +277,8 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
        struct path realpath;
        enum ovl_path_type type = ovl_path_real(dentry, &realpath);
        ssize_t res;
-       int off;
+       size_t len;
+       char *s;
 
        res = vfs_listxattr(realpath.dentry, list, size);
        if (res <= 0 || size == 0)
@@ -284,17 +288,19 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
                return res;
 
        /* filter out private xattrs */
-       for (off = 0; off < res;) {
-               char *s = list + off;
-               size_t slen = strlen(s) + 1;
+       for (s = list, len = res; len;) {
+               size_t slen = strnlen(s, len) + 1;
 
-               BUG_ON(off + slen > res);
+               /* underlying fs providing us with an broken xattr list? */
+               if (WARN_ON(slen > len))
+                       return -EIO;
 
+               len -= slen;
                if (ovl_is_private_xattr(s)) {
                        res -= slen;
-                       memmove(s, s + slen, res - off);
+                       memmove(s, s + slen, len);
                } else {
-                       off += slen;
+                       s += slen;
                }
        }
 
index 735e1d49b30116ad049e011f8b9fb1d6e4649710..c319d5eaabcfaaf8332ff8deea71db1048fa4647 100644 (file)
@@ -174,6 +174,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 int ovl_removexattr(struct dentry *dentry, const char *name);
 struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
+bool ovl_is_private_xattr(const char *name);
 
 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
                            struct ovl_entry *oe);
index a1acc6004a91ddf3a175bdc3d94e57f5c4384484..d70208c0de84b888c6ac7b92640c2d6f40d1c24f 100644 (file)
@@ -376,7 +376,8 @@ static struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
 static bool ovl_dentry_remote(struct dentry *dentry)
 {
        return dentry->d_flags &
-               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
+               (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE |
+                DCACHE_OP_REAL);
 }
 
 static bool ovl_dentry_weird(struct dentry *dentry)
@@ -762,6 +763,10 @@ retry:
                struct kstat stat = {
                        .mode = S_IFDIR | 0,
                };
+               struct iattr attr = {
+                       .ia_valid = ATTR_MODE,
+                       .ia_mode = stat.mode,
+               };
 
                if (work->d_inode) {
                        err = -EEXIST;
@@ -777,6 +782,21 @@ retry:
                err = ovl_create_real(dir, work, &stat, NULL, NULL, true);
                if (err)
                        goto out_dput;
+
+               err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
+               if (err && err != -ENODATA && err != -EOPNOTSUPP)
+                       goto out_dput;
+
+               err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_ACCESS);
+               if (err && err != -ENODATA && err != -EOPNOTSUPP)
+                       goto out_dput;
+
+               /* Clear any inherited mode bits */
+               inode_lock(work->d_inode);
+               err = notify_change(work, &attr, NULL);
+               inode_unlock(work->d_inode);
+               if (err)
+                       goto out_dput;
        }
 out_unlock:
        mutex_unlock(&dir->i_mutex);
index 34bd1bd354e63c3812c1ecbbf84abdc49a06e63b..a60d3cc5b55d9190539d07e6869206c986d8a6de 100644 (file)
@@ -592,6 +592,37 @@ no_mem:
 }
 EXPORT_SYMBOL_GPL(posix_acl_create);
 
+/**
+ * posix_acl_update_mode  -  update mode in set_acl
+ *
+ * Update the file mode when setting an ACL: compute the new file permission
+ * bits based on the ACL.  In addition, if the ACL is equivalent to the new
+ * file mode, set *acl to NULL to indicate that no ACL should be set.
+ *
+ * As with chmod, clear the setgit bit if the caller is not in the owning group
+ * or capable of CAP_FSETID (see inode_change_ok).
+ *
+ * Called from set_acl inode operations.
+ */
+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
+                         struct posix_acl **acl)
+{
+       umode_t mode = inode->i_mode;
+       int error;
+
+       error = posix_acl_equiv_mode(*acl, &mode);
+       if (error < 0)
+               return error;
+       if (error == 0)
+               *acl = NULL;
+       if (!in_group_p(inode->i_gid) &&
+           !capable_wrt_inode_uidgid(inode, CAP_FSETID))
+               mode &= ~S_ISGID;
+       *mode_p = mode;
+       return 0;
+}
+EXPORT_SYMBOL(posix_acl_update_mode);
+
 /*
  * Fix up the uids and gids in posix acl extended attributes in place.
  */
index 67b6d7e2313f3d3b3dd9e19a032affcb93433df3..0c9ea52ab3995829bd4b076bc6eba82297669ec8 100644 (file)
@@ -1545,18 +1545,13 @@ static const struct file_operations proc_pid_set_comm_operations = {
 static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
 {
        struct task_struct *task;
-       struct mm_struct *mm;
        struct file *exe_file;
 
        task = get_proc_task(d_inode(dentry));
        if (!task)
                return -ENOENT;
-       mm = get_task_mm(task);
+       exe_file = get_task_exe_file(task);
        put_task_struct(task);
-       if (!mm)
-               return -ENOENT;
-       exe_file = get_mm_exe_file(mm);
-       mmput(mm);
        if (exe_file) {
                *exe_path = exe_file->f_path;
                path_get(&exe_file->f_path);
@@ -2261,16 +2256,27 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
        if (!p)
                return -ESRCH;
 
-       if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) {
-               task_lock(p);
-               if (slack_ns == 0)
-                       p->timer_slack_ns = p->default_timer_slack_ns;
-               else
-                       p->timer_slack_ns = slack_ns;
-               task_unlock(p);
-       } else
-               count = -EPERM;
+       if (p != current) {
+               if (!capable(CAP_SYS_NICE)) {
+                       count = -EPERM;
+                       goto out;
+               }
+
+               err = security_task_setscheduler(p);
+               if (err) {
+                       count = err;
+                       goto out;
+               }
+       }
+
+       task_lock(p);
+       if (slack_ns == 0)
+               p->timer_slack_ns = p->default_timer_slack_ns;
+       else
+               p->timer_slack_ns = slack_ns;
+       task_unlock(p);
 
+out:
        put_task_struct(p);
 
        return count;
@@ -2280,19 +2286,28 @@ static int timerslack_ns_show(struct seq_file *m, void *v)
 {
        struct inode *inode = m->private;
        struct task_struct *p;
-       int err =  0;
+       int err = 0;
 
        p = get_proc_task(inode);
        if (!p)
                return -ESRCH;
 
-       if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) {
-               task_lock(p);
-               seq_printf(m, "%llu\n", p->timer_slack_ns);
-               task_unlock(p);
-       } else
-               err = -EPERM;
+       if (p != current) {
+
+               if (!capable(CAP_SYS_NICE)) {
+                       err = -EPERM;
+                       goto out;
+               }
+               err = security_task_getscheduler(p);
+               if (err)
+                       goto out;
+       }
+
+       task_lock(p);
+       seq_printf(m, "%llu\n", p->timer_slack_ns);
+       task_unlock(p);
 
+out:
        put_task_struct(p);
 
        return err;
index 92e6726f6e3732573bd9a64f3b313cc3508ce519..21f198aa0961967f724d8601efb139fe79f6c34b 100644 (file)
@@ -430,6 +430,7 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
 static ssize_t
 read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
 {
+       char *buf = file->private_data;
        ssize_t acc = 0;
        size_t size, tsz;
        size_t elf_buflen;
@@ -500,23 +501,20 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                        if (clear_user(buffer, tsz))
                                return -EFAULT;
                } else if (is_vmalloc_or_module_addr((void *)start)) {
-                       char * elf_buf;
-
-                       elf_buf = kzalloc(tsz, GFP_KERNEL);
-                       if (!elf_buf)
-                               return -ENOMEM;
-                       vread(elf_buf, (char *)start, tsz);
+                       vread(buf, (char *)start, tsz);
                        /* we have to zero-fill user buffer even if no read */
-                       if (copy_to_user(buffer, elf_buf, tsz)) {
-                               kfree(elf_buf);
+                       if (copy_to_user(buffer, buf, tsz))
                                return -EFAULT;
-                       }
-                       kfree(elf_buf);
                } else {
                        if (kern_addr_valid(start)) {
                                unsigned long n;
 
-                               n = copy_to_user(buffer, (char *)start, tsz);
+                               /*
+                                * Using bounce buffer to bypass the
+                                * hardened user copy kernel text checks.
+                                */
+                               memcpy(buf, (char *) start, tsz);
+                               n = copy_to_user(buffer, buf, tsz);
                                /*
                                 * We cannot distinguish between fault on source
                                 * and fault on destination. When this happens
@@ -549,6 +547,11 @@ static int open_kcore(struct inode *inode, struct file *filp)
 {
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
+
+       filp->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!filp->private_data)
+               return -ENOMEM;
+
        if (kcore_need_update)
                kcore_update_ram();
        if (i_size_read(inode) != proc_root_kcore->size) {
@@ -559,10 +562,16 @@ static int open_kcore(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static int release_kcore(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
 
 static const struct file_operations proc_kcore_operations = {
        .read           = read_kcore,
        .open           = open_kcore,
+       .release        = release_kcore,
        .llseek         = default_llseek,
 };
 
index 3e97da37b67c1d18522de52a616c0c76c1efc25e..200e3b29aa22d535a37b17e1d51f194a68e21c1e 100644 (file)
@@ -298,23 +298,29 @@ static int do_maps_open(struct inode *inode, struct file *file,
                                sizeof(struct proc_maps_private));
 }
 
-static pid_t pid_of_stack(struct proc_maps_private *priv,
-                               struct vm_area_struct *vma, bool is_pid)
+/*
+ * Indicate if the VMA is a stack for the given task; for
+ * /proc/PID/maps that is the stack of the main task.
+ */
+static int is_stack(struct proc_maps_private *priv,
+                   struct vm_area_struct *vma, int is_pid)
 {
-       struct inode *inode = priv->inode;
-       struct task_struct *task;
-       pid_t ret = 0;
+       int stack = 0;
+
+       if (is_pid) {
+               stack = vma->vm_start <= vma->vm_mm->start_stack &&
+                       vma->vm_end >= vma->vm_mm->start_stack;
+       } else {
+               struct inode *inode = priv->inode;
+               struct task_struct *task;
 
-       rcu_read_lock();
-       task = pid_task(proc_pid(inode), PIDTYPE_PID);
-       if (task) {
-               task = task_of_stack(task, vma, is_pid);
+               rcu_read_lock();
+               task = pid_task(proc_pid(inode), PIDTYPE_PID);
                if (task)
-                       ret = task_pid_nr_ns(task, inode->i_sb->s_fs_info);
+                       stack = vma_is_stack_for_task(vma, task);
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
-
-       return ret;
+       return stack;
 }
 
 static void
@@ -374,8 +380,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 
        name = arch_vma_name(vma);
        if (!name) {
-               pid_t tid;
-
                if (!mm) {
                        name = "[vdso]";
                        goto done;
@@ -387,23 +391,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
                        goto done;
                }
 
-               tid = pid_of_stack(priv, vma, is_pid);
-               if (tid != 0) {
-                       /*
-                        * Thread stack in /proc/PID/task/TID/maps or
-                        * the main process stack.
-                        */
-                       if (!is_pid || (vma->vm_start <= mm->start_stack &&
-                           vma->vm_end >= mm->start_stack)) {
-                               name = "[stack]";
-                       } else {
-                               /* Thread stack in /proc/PID/maps */
-                               seq_pad(m, ' ');
-                               seq_printf(m, "[stack:%d]", tid);
-                       }
+               if (is_stack(priv, vma, is_pid)) {
+                       name = "[stack]";
                        goto done;
                }
-
                if (vma_get_anon_name(vma)) {
                        seq_pad(m, ' ');
                        seq_print_vma_name(m, vma);
@@ -1628,19 +1619,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
                seq_file_path(m, file, "\n\t= ");
        } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
                seq_puts(m, " heap");
-       } else {
-               pid_t tid = pid_of_stack(proc_priv, vma, is_pid);
-               if (tid != 0) {
-                       /*
-                        * Thread stack in /proc/PID/task/TID/maps or
-                        * the main process stack.
-                        */
-                       if (!is_pid || (vma->vm_start <= mm->start_stack &&
-                           vma->vm_end >= mm->start_stack))
-                               seq_puts(m, " stack");
-                       else
-                               seq_printf(m, " stack:%d", tid);
-               }
+       } else if (is_stack(proc_priv, vma, is_pid)) {
+               seq_puts(m, " stack");
        }
 
        if (is_vm_hugetlb_page(vma))
index e0d64c92e4f6576c38a8a4a7cc9b8d13a2b3362e..faacb0c0d857602111bfc04f2e374c451059c358 100644 (file)
@@ -123,23 +123,26 @@ unsigned long task_statm(struct mm_struct *mm,
        return size;
 }
 
-static pid_t pid_of_stack(struct proc_maps_private *priv,
-                               struct vm_area_struct *vma, bool is_pid)
+static int is_stack(struct proc_maps_private *priv,
+                   struct vm_area_struct *vma, int is_pid)
 {
-       struct inode *inode = priv->inode;
-       struct task_struct *task;
-       pid_t ret = 0;
-
-       rcu_read_lock();
-       task = pid_task(proc_pid(inode), PIDTYPE_PID);
-       if (task) {
-               task = task_of_stack(task, vma, is_pid);
+       struct mm_struct *mm = vma->vm_mm;
+       int stack = 0;
+
+       if (is_pid) {
+               stack = vma->vm_start <= mm->start_stack &&
+                       vma->vm_end >= mm->start_stack;
+       } else {
+               struct inode *inode = priv->inode;
+               struct task_struct *task;
+
+               rcu_read_lock();
+               task = pid_task(proc_pid(inode), PIDTYPE_PID);
                if (task)
-                       ret = task_pid_nr_ns(task, inode->i_sb->s_fs_info);
+                       stack = vma_is_stack_for_task(vma, task);
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
-
-       return ret;
+       return stack;
 }
 
 /*
@@ -181,21 +184,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
        if (file) {
                seq_pad(m, ' ');
                seq_file_path(m, file, "");
-       } else if (mm) {
-               pid_t tid = pid_of_stack(priv, vma, is_pid);
-
-               if (tid != 0) {
-                       seq_pad(m, ' ');
-                       /*
-                        * Thread stack in /proc/PID/task/TID/maps or
-                        * the main process stack.
-                        */
-                       if (!is_pid || (vma->vm_start <= mm->start_stack &&
-                           vma->vm_end >= mm->start_stack))
-                               seq_printf(m, "[stack]");
-                       else
-                               seq_printf(m, "[stack:%d]", tid);
-               }
+       } else if (mm && is_stack(priv, vma, is_pid)) {
+               seq_pad(m, ' ');
+               seq_printf(m, "[stack]");
        }
 
        seq_putc(m, '\n');
index d8c439d813ce1bd0a415fd09a8407c6c6192d49b..ac6c78fe19cfa85ed526eb23506444d3a519c29a 100644 (file)
@@ -178,7 +178,6 @@ static loff_t pstore_file_llseek(struct file *file, loff_t off, int whence)
 }
 
 static const struct file_operations pstore_file_operations = {
-       .owner          = THIS_MODULE,
        .open           = pstore_file_open,
        .read           = pstore_file_read,
        .llseek         = pstore_file_llseek,
index 588461bb2dd482bc7906cb284c57b1e6ff92de87..40a0fe0a4e053abcc83a1195cb8a482f9b061811 100644 (file)
@@ -431,6 +431,40 @@ static int pstore_write_compat(enum pstore_type_id type,
                             size, psi);
 }
 
+static int pstore_write_buf_user_compat(enum pstore_type_id type,
+                              enum kmsg_dump_reason reason,
+                              u64 *id, unsigned int part,
+                              const char __user *buf,
+                              bool compressed, size_t size,
+                              struct pstore_info *psi)
+{
+       unsigned long flags = 0;
+       size_t i, bufsize = size;
+       long ret = 0;
+
+       if (unlikely(!access_ok(VERIFY_READ, buf, size)))
+               return -EFAULT;
+       if (bufsize > psinfo->bufsize)
+               bufsize = psinfo->bufsize;
+       spin_lock_irqsave(&psinfo->buf_lock, flags);
+       for (i = 0; i < size; ) {
+               size_t c = min(size - i, bufsize);
+
+               ret = __copy_from_user(psinfo->buf, buf + i, c);
+               if (unlikely(ret != 0)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = psi->write_buf(type, reason, id, part, psinfo->buf,
+                                    compressed, c, psi);
+               if (unlikely(ret < 0))
+                       break;
+               i += c;
+       }
+       spin_unlock_irqrestore(&psinfo->buf_lock, flags);
+       return unlikely(ret < 0) ? ret : size;
+}
+
 /*
  * platform specific persistent storage driver registers with
  * us here. If pstore is already mounted, call the platform
@@ -453,6 +487,8 @@ int pstore_register(struct pstore_info *psi)
 
        if (!psi->write)
                psi->write = pstore_write_compat;
+       if (!psi->write_buf_user)
+               psi->write_buf_user = pstore_write_buf_user_compat;
        psinfo = psi;
        mutex_init(&psinfo->read_mutex);
        spin_unlock(&pstore_lock);
index 7de20cd3797f1d3929f4abe2f9741c756259c7bd..78f6176c020f8256dad089221af85d9560e5ac2f 100644 (file)
 #include "internal.h"
 
 static DEFINE_MUTEX(pmsg_lock);
-#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE)
 
 static ssize_t write_pmsg(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
-       size_t i, buffer_size;
-       char *buffer;
+       u64 id;
+       int ret;
 
        if (!count)
                return 0;
 
+       /* check outside lock, page in any data. write_buf_user also checks */
        if (!access_ok(VERIFY_READ, buf, count))
                return -EFAULT;
 
-       buffer_size = count;
-       if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE)
-               buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE;
-       buffer = vmalloc(buffer_size);
-       if (!buffer)
-               return -ENOMEM;
-
        mutex_lock(&pmsg_lock);
-       for (i = 0; i < count; ) {
-               size_t c = min(count - i, buffer_size);
-               u64 id;
-               long ret;
-
-               ret = __copy_from_user(buffer, buf + i, c);
-               if (unlikely(ret != 0)) {
-                       mutex_unlock(&pmsg_lock);
-                       vfree(buffer);
-                       return -EFAULT;
-               }
-               psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c,
-                                 psinfo);
-
-               i += c;
-       }
-
+       ret = psinfo->write_buf_user(PSTORE_TYPE_PMSG, 0, &id, 0, buf, 0, count,
+                                    psinfo);
        mutex_unlock(&pmsg_lock);
-       vfree(buffer);
-       return count;
+       return ret ? ret : count;
 }
 
 static const struct file_operations pmsg_fops = {
index 414041342a998d659c621320e86daa6dc3d57f32..8d1e5e2db6a1a772daeb6d923a25a189c5c3b6a5 100644 (file)
@@ -331,6 +331,24 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
        return 0;
 }
 
+static int notrace ramoops_pstore_write_buf_user(enum pstore_type_id type,
+                                                enum kmsg_dump_reason reason,
+                                                u64 *id, unsigned int part,
+                                                const char __user *buf,
+                                                bool compressed, size_t size,
+                                                struct pstore_info *psi)
+{
+       if (type == PSTORE_TYPE_PMSG) {
+               struct ramoops_context *cxt = psi->data;
+
+               if (!cxt->mprz)
+                       return -ENOMEM;
+               return persistent_ram_write_user(cxt->mprz, buf, size);
+       }
+
+       return -EINVAL;
+}
+
 static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
                                struct timespec time, struct pstore_info *psi)
 {
@@ -369,6 +387,7 @@ static struct ramoops_context oops_cxt = {
                .open   = ramoops_pstore_open,
                .read   = ramoops_pstore_read,
                .write_buf      = ramoops_pstore_write_buf,
+               .write_buf_user = ramoops_pstore_write_buf_user,
                .erase  = ramoops_pstore_erase,
        },
 };
@@ -377,13 +396,14 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
 {
        int i;
 
-       cxt->max_dump_cnt = 0;
        if (!cxt->przs)
                return;
 
-       for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
+       for (i = 0; i < cxt->max_dump_cnt; i++)
                persistent_ram_free(cxt->przs[i]);
+
        kfree(cxt->przs);
+       cxt->max_dump_cnt = 0;
 }
 
 static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
@@ -408,7 +428,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
                             GFP_KERNEL);
        if (!cxt->przs) {
                dev_err(dev, "failed to initialize a prz array for dumps\n");
-               goto fail_prz;
+               goto fail_mem;
        }
 
        for (i = 0; i < cxt->max_dump_cnt; i++) {
@@ -419,6 +439,11 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
                        err = PTR_ERR(cxt->przs[i]);
                        dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
                                cxt->record_size, (unsigned long long)*paddr, err);
+
+                       while (i > 0) {
+                               i--;
+                               persistent_ram_free(cxt->przs[i]);
+                       }
                        goto fail_prz;
                }
                *paddr += cxt->record_size;
@@ -426,7 +451,9 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
 
        return 0;
 fail_prz:
-       ramoops_free_przs(cxt);
+       kfree(cxt->przs);
+fail_mem:
+       cxt->max_dump_cnt = 0;
        return err;
 }
 
@@ -688,7 +715,6 @@ static int ramoops_remove(struct platform_device *pdev)
        struct ramoops_context *cxt = &oops_cxt;
 
        pstore_unregister(&cxt->pstore);
-       cxt->max_dump_cnt = 0;
 
        kfree(cxt->pstore.buf);
        cxt->pstore.bufsize = 0;
index 76c3f80efdfa8c89cafac242e3fc3eec2f37601d..3975deec02f8ca9202c42662cba69f9783605158 100644 (file)
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/memblock.h>
+#include <linux/pstore_ram.h>
 #include <linux/rslib.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
-#include <linux/pstore_ram.h>
 #include <asm/page.h>
 
 struct persistent_ram_buffer {
@@ -47,43 +48,10 @@ static inline size_t buffer_start(struct persistent_ram_zone *prz)
        return atomic_read(&prz->buffer->start);
 }
 
-/* increase and wrap the start pointer, returning the old value */
-static size_t buffer_start_add_atomic(struct persistent_ram_zone *prz, size_t a)
-{
-       int old;
-       int new;
-
-       do {
-               old = atomic_read(&prz->buffer->start);
-               new = old + a;
-               while (unlikely(new >= prz->buffer_size))
-                       new -= prz->buffer_size;
-       } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
-
-       return old;
-}
-
-/* increase the size counter until it hits the max size */
-static void buffer_size_add_atomic(struct persistent_ram_zone *prz, size_t a)
-{
-       size_t old;
-       size_t new;
-
-       if (atomic_read(&prz->buffer->size) == prz->buffer_size)
-               return;
-
-       do {
-               old = atomic_read(&prz->buffer->size);
-               new = old + a;
-               if (new > prz->buffer_size)
-                       new = prz->buffer_size;
-       } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-}
-
 static DEFINE_RAW_SPINLOCK(buffer_lock);
 
 /* increase and wrap the start pointer, returning the old value */
-static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a)
+static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
 {
        int old;
        int new;
@@ -103,7 +71,7 @@ static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a)
 }
 
 /* increase the size counter until it hits the max size */
-static void buffer_size_add_locked(struct persistent_ram_zone *prz, size_t a)
+static void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
 {
        size_t old;
        size_t new;
@@ -124,9 +92,6 @@ exit:
        raw_spin_unlock_irqrestore(&buffer_lock, flags);
 }
 
-static size_t (*buffer_start_add)(struct persistent_ram_zone *, size_t) = buffer_start_add_atomic;
-static void (*buffer_size_add)(struct persistent_ram_zone *, size_t) = buffer_size_add_atomic;
-
 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
        uint8_t *data, size_t len, uint8_t *ecc)
 {
@@ -299,10 +264,20 @@ static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
        const void *s, unsigned int start, unsigned int count)
 {
        struct persistent_ram_buffer *buffer = prz->buffer;
-       memcpy(buffer->data + start, s, count);
+       memcpy_toio(buffer->data + start, s, count);
        persistent_ram_update_ecc(prz, start, count);
 }
 
+static int notrace persistent_ram_update_user(struct persistent_ram_zone *prz,
+       const void __user *s, unsigned int start, unsigned int count)
+{
+       struct persistent_ram_buffer *buffer = prz->buffer;
+       int ret = unlikely(__copy_from_user(buffer->data + start, s, count)) ?
+               -EFAULT : 0;
+       persistent_ram_update_ecc(prz, start, count);
+       return ret;
+}
+
 void persistent_ram_save_old(struct persistent_ram_zone *prz)
 {
        struct persistent_ram_buffer *buffer = prz->buffer;
@@ -322,8 +297,8 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz)
        }
 
        prz->old_log_size = size;
-       memcpy(prz->old_log, &buffer->data[start], size - start);
-       memcpy(prz->old_log + size - start, &buffer->data[0], start);
+       memcpy_fromio(prz->old_log, &buffer->data[start], size - start);
+       memcpy_fromio(prz->old_log + size - start, &buffer->data[0], start);
 }
 
 int notrace persistent_ram_write(struct persistent_ram_zone *prz,
@@ -356,6 +331,38 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz,
        return count;
 }
 
+int notrace persistent_ram_write_user(struct persistent_ram_zone *prz,
+       const void __user *s, unsigned int count)
+{
+       int rem, ret = 0, c = count;
+       size_t start;
+
+       if (unlikely(!access_ok(VERIFY_READ, s, count)))
+               return -EFAULT;
+       if (unlikely(c > prz->buffer_size)) {
+               s += c - prz->buffer_size;
+               c = prz->buffer_size;
+       }
+
+       buffer_size_add(prz, c);
+
+       start = buffer_start_add(prz, c);
+
+       rem = prz->buffer_size - start;
+       if (unlikely(rem < c)) {
+               ret = persistent_ram_update_user(prz, s, start, rem);
+               s += rem;
+               c -= rem;
+               start = 0;
+       }
+       if (likely(!ret))
+               ret = persistent_ram_update_user(prz, s, start, c);
+
+       persistent_ram_update_header_ecc(prz);
+
+       return unlikely(ret) ? ret : count;
+}
+
 size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
 {
        return prz->old_log_size;
@@ -426,9 +433,6 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size,
                return NULL;
        }
 
-       buffer_start_add = buffer_start_add_locked;
-       buffer_size_add = buffer_size_add_locked;
-
        if (memtype)
                va = ioremap(start, size);
        else
index 96a1bcf33db4435098baa153f807a71274543aaf..8f5ccdf81c252f9d9eddc24ed301f9bacac9901b 100644 (file)
@@ -260,10 +260,10 @@ const struct file_operations reiserfs_file_operations = {
 
 const struct inode_operations reiserfs_file_inode_operations = {
        .setattr = reiserfs_setattr,
-       .setxattr = reiserfs_setxattr,
-       .getxattr = reiserfs_getxattr,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
        .listxattr = reiserfs_listxattr,
-       .removexattr = reiserfs_removexattr,
+       .removexattr = generic_removexattr,
        .permission = reiserfs_permission,
        .get_acl = reiserfs_get_acl,
        .set_acl = reiserfs_set_acl,
index b751eea32e20733f496a16a52c37cd0f8c2d06a4..5db6f45b3fed64cf58034dea3efc3a09a0f4c497 100644 (file)
@@ -1153,8 +1153,9 @@ int balance_internal(struct tree_balance *tb,
                                       insert_ptr);
        }
 
-       memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
        insert_ptr[0] = new_insert_ptr;
+       if (new_insert_ptr)
+               memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
 
        return order;
 }
index 47f96988fdd478dbc6ce325232d38754258864cc..3ebc70167e416f649b4e9ff5110fb24c857719fd 100644 (file)
@@ -1649,10 +1649,10 @@ const struct inode_operations reiserfs_dir_inode_operations = {
        .mknod = reiserfs_mknod,
        .rename = reiserfs_rename,
        .setattr = reiserfs_setattr,
-       .setxattr = reiserfs_setxattr,
-       .getxattr = reiserfs_getxattr,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
        .listxattr = reiserfs_listxattr,
-       .removexattr = reiserfs_removexattr,
+       .removexattr = generic_removexattr,
        .permission = reiserfs_permission,
        .get_acl = reiserfs_get_acl,
        .set_acl = reiserfs_set_acl,
@@ -1667,10 +1667,10 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
        .follow_link = page_follow_link_light,
        .put_link = page_put_link,
        .setattr = reiserfs_setattr,
-       .setxattr = reiserfs_setxattr,
-       .getxattr = reiserfs_getxattr,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
        .listxattr = reiserfs_listxattr,
-       .removexattr = reiserfs_removexattr,
+       .removexattr = generic_removexattr,
        .permission = reiserfs_permission,
 };
 
@@ -1679,10 +1679,10 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
  */
 const struct inode_operations reiserfs_special_inode_operations = {
        .setattr = reiserfs_setattr,
-       .setxattr = reiserfs_setxattr,
-       .getxattr = reiserfs_getxattr,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
        .listxattr = reiserfs_listxattr,
-       .removexattr = reiserfs_removexattr,
+       .removexattr = generic_removexattr,
        .permission = reiserfs_permission,
        .get_acl = reiserfs_get_acl,
        .set_acl = reiserfs_set_acl,
index 4a62fe8cc3bff619516fbe15d62a8cfaa1aaa581..f9f3be50081a3c719a589f92479d274be82e9772 100644 (file)
@@ -190,7 +190,15 @@ static int remove_save_link_only(struct super_block *s,
 static int reiserfs_quota_on_mount(struct super_block *, int);
 #endif
 
-/* look for uncompleted unlinks and truncates and complete them */
+/*
+ * Look for uncompleted unlinks and truncates and complete them
+ *
+ * Called with superblock write locked.  If quotas are enabled, we have to
+ * release/retake lest we call dquot_quota_on_mount(), proceed to
+ * schedule_on_each_cpu() in invalidate_bdev() and deadlock waiting for the per
+ * cpu worklets to complete flush_async_commits() that in turn wait for the
+ * superblock write lock.
+ */
 static int finish_unfinished(struct super_block *s)
 {
        INITIALIZE_PATH(path);
@@ -237,7 +245,9 @@ static int finish_unfinished(struct super_block *s)
                                quota_enabled[i] = 0;
                                continue;
                        }
+                       reiserfs_write_unlock(s);
                        ret = reiserfs_quota_on_mount(s, i);
+                       reiserfs_write_lock(s);
                        if (ret < 0)
                                reiserfs_warning(s, "reiserfs-2500",
                                                 "cannot turn on journaled "
index 66b26fdfff8d6de51082b48b0f9a61fba9567466..a8dbc93e45eb3757cbd3bc7d886802af37d41c22 100644 (file)
@@ -763,60 +763,6 @@ find_xattr_handler_prefix(const struct xattr_handler **handlers,
        return xah;
 }
 
-
-/*
- * Inode operation getxattr()
- */
-ssize_t
-reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
-                 size_t size)
-{
-       const struct xattr_handler *handler;
-
-       handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
-
-       if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
-               return -EOPNOTSUPP;
-
-       return handler->get(handler, dentry, name, buffer, size);
-}
-
-/*
- * Inode operation setxattr()
- *
- * d_inode(dentry)->i_mutex down
- */
-int
-reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
-                 size_t size, int flags)
-{
-       const struct xattr_handler *handler;
-
-       handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
-
-       if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
-               return -EOPNOTSUPP;
-
-       return handler->set(handler, dentry, name, value, size, flags);
-}
-
-/*
- * Inode operation removexattr()
- *
- * d_inode(dentry)->i_mutex down
- */
-int reiserfs_removexattr(struct dentry *dentry, const char *name)
-{
-       const struct xattr_handler *handler;
-
-       handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
-
-       if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
-               return -EOPNOTSUPP;
-
-       return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE);
-}
-
 struct listxattr_buf {
        struct dir_context ctx;
        size_t size;
index 15dde6262c00e3d93b765f79198d93bfe79c3646..613ff5aef94ea014caa87d52ae8c03d9c88e5bdd 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/rwsem.h>
+#include <linux/xattr.h>
 
 struct inode;
 struct dentry;
@@ -18,12 +19,7 @@ int reiserfs_permission(struct inode *inode, int mask);
 
 #ifdef CONFIG_REISERFS_FS_XATTR
 #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
-ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
-                         void *buffer, size_t size);
-int reiserfs_setxattr(struct dentry *dentry, const char *name,
-                     const void *value, size_t size, int flags);
 ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-int reiserfs_removexattr(struct dentry *dentry, const char *name);
 
 int reiserfs_xattr_get(struct inode *, const char *, void *, size_t);
 int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
@@ -92,10 +88,7 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
 
 #else
 
-#define reiserfs_getxattr NULL
-#define reiserfs_setxattr NULL
 #define reiserfs_listxattr NULL
-#define reiserfs_removexattr NULL
 
 static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
 {
index 4b34b9dc03dda9fffd8da5d3ab7221bd9ab139b7..9b1824f355016a9ab070d716ff40d75f55417837 100644 (file)
@@ -246,13 +246,9 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
                if (acl) {
-                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (error < 0)
+                       error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+                       if (error)
                                return error;
-                       else {
-                               if (error == 0)
-                                       acl = NULL;
-                       }
                }
                break;
        case ACL_TYPE_DEFAULT:
index ac659af431aec83d5ba7b85e7b69c1ac49e7b4c0..60de069225ba33a087f02de406eda2725a159e8e 100644 (file)
@@ -12,26 +12,24 @@ static int
 security_get(const struct xattr_handler *handler, struct dentry *dentry,
             const char *name, void *buffer, size_t size)
 {
-       if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
-               return -EINVAL;
-
        if (IS_PRIVATE(d_inode(dentry)))
                return -EPERM;
 
-       return reiserfs_xattr_get(d_inode(dentry), name, buffer, size);
+       return reiserfs_xattr_get(d_inode(dentry),
+                                 xattr_full_name(handler, name),
+                                 buffer, size);
 }
 
 static int
 security_set(const struct xattr_handler *handler, struct dentry *dentry,
             const char *name, const void *buffer, size_t size, int flags)
 {
-       if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
-               return -EINVAL;
-
        if (IS_PRIVATE(d_inode(dentry)))
                return -EPERM;
 
-       return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
+       return reiserfs_xattr_set(d_inode(dentry),
+                                 xattr_full_name(handler, name),
+                                 buffer, size, flags);
 }
 
 static size_t security_list(const struct xattr_handler *handler,
index a338adf1b8b4816c19ca84557a0142179f93b9a7..ebba1ebf28addb36a1ee3c3d30feab5c7199cc27 100644 (file)
@@ -11,26 +11,24 @@ static int
 trusted_get(const struct xattr_handler *handler, struct dentry *dentry,
            const char *name, void *buffer, size_t size)
 {
-       if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
-               return -EINVAL;
-
        if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
                return -EPERM;
 
-       return reiserfs_xattr_get(d_inode(dentry), name, buffer, size);
+       return reiserfs_xattr_get(d_inode(dentry),
+                                 xattr_full_name(handler, name),
+                                 buffer, size);
 }
 
 static int
 trusted_set(const struct xattr_handler *handler, struct dentry *dentry,
            const char *name, const void *buffer, size_t size, int flags)
 {
-       if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
-               return -EINVAL;
-
        if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
                return -EPERM;
 
-       return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
+       return reiserfs_xattr_set(d_inode(dentry),
+                                 xattr_full_name(handler, name),
+                                 buffer, size, flags);
 }
 
 static size_t trusted_list(const struct xattr_handler *handler,
index 39c9667191c5db5b3c930e538d81799b96bea6fb..6ac8a8c8bd9cd1052055c1269006c4a62ccbc9cc 100644 (file)
@@ -10,24 +10,22 @@ static int
 user_get(const struct xattr_handler *handler, struct dentry *dentry,
         const char *name, void *buffer, size_t size)
 {
-
-       if (strlen(name) < sizeof(XATTR_USER_PREFIX))
-               return -EINVAL;
        if (!reiserfs_xattrs_user(dentry->d_sb))
                return -EOPNOTSUPP;
-       return reiserfs_xattr_get(d_inode(dentry), name, buffer, size);
+       return reiserfs_xattr_get(d_inode(dentry),
+                                 xattr_full_name(handler, name),
+                                 buffer, size);
 }
 
 static int
 user_set(const struct xattr_handler *handler, struct dentry *dentry,
         const char *name, const void *buffer, size_t size, int flags)
 {
-       if (strlen(name) < sizeof(XATTR_USER_PREFIX))
-               return -EINVAL;
-
        if (!reiserfs_xattrs_user(dentry->d_sb))
                return -EOPNOTSUPP;
-       return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
+       return reiserfs_xattr_set(d_inode(dentry),
+                                 xattr_full_name(handler, name),
+                                 buffer, size, flags);
 }
 
 static size_t user_list(const struct xattr_handler *handler,
index 128b3e56851fbff4f822ea0b9206271edccd8e12..41e0e11b3c35808900ebf3e5e1ee629f0948074a 100644 (file)
@@ -112,7 +112,7 @@ void get_derived_permission(struct dentry *parent, struct dentry *dentry)
 void get_derive_permissions_recursive(struct dentry *parent) {
        struct dentry *dentry;
        list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
-               if (dentry && dentry->d_inode) {
+               if (dentry->d_inode) {
                        mutex_lock(&dentry->d_inode->i_mutex);
                        get_derived_permission(parent, dentry);
                        fix_derived_permission(dentry->d_inode);
index e85664b7c7d963522fd7efc938a3d96a27edc651..d672e2fec459116cfe67688fd679e30187e80f70 100644 (file)
@@ -222,8 +222,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
                size -= n;
                buf += n;
                copied += n;
-               if (!m->count)
+               if (!m->count) {
+                       m->from = 0;
                        m->index++;
+               }
                if (!size)
                        goto Done;
        }
index 8d99a7b948ff087380ca2b2d5988885c22360553..b938b14f6041b97a8f8b2681016dcb08a8438ce6 100644 (file)
@@ -1326,8 +1326,8 @@ int freeze_super(struct super_block *sb)
                }
        }
        /*
-        * This is just for debugging purposes so that fs can warn if it
-        * sees write activity when frozen is set to SB_FREEZE_COMPLETE.
+        * For debugging purposes so that fs can warn if it sees write activity
+        * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super().
         */
        sb->s_writers.frozen = SB_FREEZE_COMPLETE;
        up_write(&sb->s_umount);
@@ -1346,7 +1346,7 @@ int thaw_super(struct super_block *sb)
        int error;
 
        down_write(&sb->s_umount);
-       if (sb->s_writers.frozen == SB_UNFROZEN) {
+       if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
                up_write(&sb->s_umount);
                return -EINVAL;
        }
index f35523d4fa3a6d657260e7b04d5273db2dcd53b1..b803213d1307e9137c3bfe5e04ee4ac5bd396cce 100644 (file)
@@ -114,9 +114,15 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
         * If buf != of->prealloc_buf, we don't know how
         * large it is, so cannot safely pass it to ->show
         */
-       if (pos || WARN_ON_ONCE(buf != of->prealloc_buf))
+       if (WARN_ON_ONCE(buf != of->prealloc_buf))
                return 0;
        len = ops->show(kobj, of->kn->priv, buf);
+       if (pos) {
+               if (len <= pos)
+                       return 0;
+               len -= pos;
+               memmove(buf, buf + pos, len);
+       }
        return min(count, len);
 }
 
index b45345d701e77fea809144009e3a46fa05560533..51157da3f76ed87a2a0c7f34c7c2240db116ed00 100644 (file)
@@ -370,7 +370,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
 
        p = c->gap_lebs;
        do {
-               ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs);
+               ubifs_assert(p < c->gap_lebs + c->lst.idx_lebs);
                written = layout_leb_in_gaps(c, p);
                if (written < 0) {
                        err = written;
index e8b01b721e99d3954e344686fc615c9455e4246c..b5bf23b34241820a3c26551baa5f97062b8d76b8 100644 (file)
@@ -173,6 +173,7 @@ out_cancel:
        host_ui->xattr_cnt -= 1;
        host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
        host_ui->xattr_size -= CALC_XATTR_BYTES(size);
+       host_ui->xattr_names -= nm->len;
        mutex_unlock(&host_ui->ui_mutex);
 out_free:
        make_bad_inode(inode);
@@ -533,6 +534,7 @@ out_cancel:
        host_ui->xattr_cnt += 1;
        host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
        host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
+       host_ui->xattr_names += nm->len;
        mutex_unlock(&host_ui->ui_mutex);
        ubifs_release_budget(c, &req);
        make_bad_inode(inode);
index aa138d64560a6a3c2133bc70d57e367cc8c1476d..cb771c30d10231186d405b63155d02abadb0ce7e 100644 (file)
@@ -87,20 +87,7 @@ static int utimes_common(struct path *path, struct timespec *times)
                 */
                newattrs.ia_valid |= ATTR_TIMES_SET;
        } else {
-               /*
-                * If times is NULL (or both times are UTIME_NOW),
-                * then we need to check permissions, because
-                * inode_change_ok() won't do it.
-                */
-               error = -EACCES;
-                if (IS_IMMUTABLE(inode))
-                       goto mnt_drop_write_and_out;
-
-               if (!inode_owner_or_capable(inode)) {
-                       error = inode_permission(inode, MAY_WRITE);
-                       if (error)
-                               goto mnt_drop_write_and_out;
-               }
+               newattrs.ia_valid |= ATTR_TOUCH;
        }
 retry_deleg:
        mutex_lock(&inode->i_mutex);
@@ -112,7 +99,6 @@ retry_deleg:
                        goto retry_deleg;
        }
 
-mnt_drop_write_and_out:
        mnt_drop_write(path->mnt);
 out:
        return error;
index 8a53eaa349f44884354139fcde0a9c17b35e741a..7088be6afb3ce2d91ffb1f9200ad51488a136cf5 100644 (file)
@@ -581,7 +581,8 @@ xfs_sb_verify(
         * Only check the in progress field for the primary superblock as
         * mkfs.xfs doesn't clear it from secondary superblocks.
         */
-       return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR,
+       return xfs_mount_validate_sb(mp, &sb,
+                                    bp->b_maps[0].bm_bn == XFS_SB_DADDR,
                                     check_version);
 }
 
index 6bb470fbb8e8ff3567abfb23b774607c7eab2dda..c5101a3295d83253599861370736535b44310963 100644 (file)
@@ -288,16 +288,11 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                return error;
 
        if (type == ACL_TYPE_ACCESS) {
-               umode_t mode = inode->i_mode;
-               error = posix_acl_equiv_mode(acl, &mode);
-
-               if (error <= 0) {
-                       acl = NULL;
-
-                       if (error < 0)
-                               return error;
-               }
+               umode_t mode;
 
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error)
+                       return error;
                error = xfs_set_mode(inode, mode);
                if (error)
                        return error;
index 39090fc56f0943dddffc4faa12c810ceb7d25c58..eb1b8c8acfcbe25c8f11ee7b36f2d0ed5f9f0558 100644 (file)
@@ -1535,7 +1535,7 @@ xfs_wait_buftarg(
         * ensure here that all reference counts have been dropped before we
         * start walking the LRU list.
         */
-       drain_workqueue(btp->bt_mount->m_buf_workqueue);
+       flush_workqueue(btp->bt_mount->m_buf_workqueue);
 
        /* loop until there is nothing left on the lru list. */
        while (list_lru_count(&btp->bt_lru)) {
index 1bfa602958f2a2f7beb16fab8f98263d198c652b..32901d11f8c46fd3746e80a1c485d3c131e90fac 100644 (file)
@@ -230,14 +230,18 @@ extern int __put_user_bad(void) __attribute__((noreturn));
        might_fault();                                          \
        access_ok(VERIFY_READ, __p, sizeof(*ptr)) ?             \
                __get_user((x), (__typeof__(*(ptr)) *)__p) :    \
-               -EFAULT;                                        \
+               ((x) = (__typeof__(*(ptr)))0,-EFAULT);          \
 })
 
 #ifndef __get_user_fn
 static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
 {
-       size = __copy_from_user(x, ptr, size);
-       return size ? -EFAULT : size;
+       size_t n = __copy_from_user(x, ptr, size);
+       if (unlikely(n)) {
+               memset(x + (size - n), 0, n);
+               return -EFAULT;
+       }
+       return 0;
 }
 
 #define __get_user_fn(sz, u, k)        __get_user_fn(sz, u, k)
@@ -257,11 +261,13 @@ extern int __get_user_bad(void) __attribute__((noreturn));
 static inline long copy_from_user(void *to,
                const void __user * from, unsigned long n)
 {
+       unsigned long res = n;
        might_fault();
-       if (access_ok(VERIFY_READ, from, n))
-               return __copy_from_user(to, from, n);
-       else
-               return n;
+       if (likely(access_ok(VERIFY_READ, from, n)))
+               res = __copy_from_user(to, from, n);
+       if (unlikely(res))
+               memset(to + (n - res), 0, res);
+       return res;
 }
 
 static inline long copy_to_user(void __user *to,
index 772c784ba76301dbceca9f3c0991c626a893e076..a65eedc15e939fd5f4cbf729bfa2df5cf7ffc779 100644 (file)
        . = ALIGN(align);                                               \
        *(.data..init_task)
 
+/*
+ * Allow architectures to handle ro_after_init data on their
+ * own by defining an empty RO_AFTER_INIT_DATA.
+ */
+#ifndef RO_AFTER_INIT_DATA
+#define RO_AFTER_INIT_DATA *(.data..ro_after_init)
+#endif
+
 /*
  * Read only Data
  */
        .rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {           \
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
                *(.rodata) *(.rodata.*)                                 \
-               *(.data..ro_after_init) /* Read only after init */      \
+               RO_AFTER_INIT_DATA      /* Read only after init */      \
                *(__vermagic)           /* Kernel version magic */      \
                . = ALIGN(8);                                           \
                VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .;         \
 
 #define INIT_TEXT                                                      \
        *(.init.text)                                                   \
+       *(.text.startup)                                                \
        MEM_DISCARD(init.text)
 
 #define EXIT_DATA                                                      \
        *(.exit.data)                                                   \
+       *(.fini_array)                                                  \
+       *(.dtors)                                                       \
        MEM_DISCARD(exit.data)                                          \
        MEM_DISCARD(exit.rodata)
 
 #define EXIT_TEXT                                                      \
        *(.exit.text)                                                   \
+       *(.text.exit)                                                   \
        MEM_DISCARD(exit.text)
 
 #define EXIT_CALL                                                      \
diff --git a/include/crypto/ghash.h b/include/crypto/ghash.h
new file mode 100644 (file)
index 0000000..2a61c9b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Common values for GHASH algorithms
+ */
+
+#ifndef __CRYPTO_GHASH_H__
+#define __CRYPTO_GHASH_H__
+
+#include <linux/types.h>
+#include <crypto/gf128mul.h>
+
+#define GHASH_BLOCK_SIZE       16
+#define GHASH_DIGEST_SIZE      16
+
+struct ghash_ctx {
+       struct gf128mul_4k *gf128;
+};
+
+struct ghash_desc_ctx {
+       u8 buffer[GHASH_BLOCK_SIZE];
+       u32 bytes;
+};
+
+#endif
index 6f664f49a7ab5f13a6ed7eba5bd02db6cf265167..d0fb88499350b37e448e5e234ad9c329f1cf1682 100644 (file)
@@ -1034,7 +1034,8 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
 #endif
 
 extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
-               struct drm_gem_object *obj, int flags);
+                                           struct drm_gem_object *obj,
+                                           int flags);
 extern int drm_gem_prime_handle_to_fd(struct drm_device *dev,
                struct drm_file *file_priv, uint32_t handle, uint32_t flags,
                int *prime_fd);
index 17c445612e0107646f54d407d70169465ff12776..2cdc723d750fe301b8b10ca4c6132d8f9f3edbee 100644 (file)
        INTEL_VGA_DEVICE(0x191D, info)  /* WKS GT2 */
 
 #define INTEL_SKL_GT3_IDS(info) \
+       INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \
        INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
+       INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \
        INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
        INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \
 
 #define INTEL_BXT_IDS(info) \
        INTEL_VGA_DEVICE(0x0A84, info), \
        INTEL_VGA_DEVICE(0x1A84, info), \
-       INTEL_VGA_DEVICE(0x5A84, info)
+       INTEL_VGA_DEVICE(0x1A85, info), \
+       INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \
+       INTEL_VGA_DEVICE(0x5A85, info)  /* APL HD Graphics 500 */
 
 #endif /* _I915_PCIIDS_H */
index 1991aea2ec4cff401b84db2841ac60fe28f00080..3672893b275ed226263f7143ca7ec4f0b5362f5d 100644 (file)
@@ -920,7 +920,7 @@ static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
        return NULL;
 }
 
-#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, validate, data, fn) \
+#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
        static const void * __acpi_table_##name[]                       \
                __attribute__((unused))                                 \
                 = { (void *) table_id,                                 \
index 1b4d69f68c33cc73ad99a1136b2408c71e763fb8..140c29635069ee3bce05c9499b659340864eed1d 100644 (file)
@@ -163,6 +163,7 @@ struct backing_dev_info {
        wait_queue_head_t wb_waitq;
 
        struct device *dev;
+       struct device *owner;
 
        struct timer_list laptop_mode_wb_timer;
 
index c82794f20110420582d496ae478bc600f9400233..89d3de3e096b62b7dcac66feb7e972d045eeecff 100644 (file)
@@ -24,6 +24,7 @@ __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner);
 void bdi_unregister(struct backing_dev_info *bdi);
 
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
index 3feb1b2d75d87b83febb605a86720b06a8132d3f..14cd6f77e284fc6ad19a5fad6115c13c84518e65 100644 (file)
@@ -156,6 +156,7 @@ struct bcma_host_ops {
 #define BCMA_CORE_DEFAULT              0xFFF
 
 #define BCMA_MAX_NR_CORES              16
+#define BCMA_CORE_SIZE                 0x1000
 
 /* Chip IDs of PCIe devices */
 #define BCMA_CHIP_ID_BCM4313   0x4313
index fbe47bc700bd014ca647b7b1d872c8e5ddd04618..42e4e3cbb001951dd7a52dfd4b0b0857db4f93bf 100644 (file)
@@ -527,11 +527,14 @@ extern unsigned int bvec_nr_vecs(unsigned short idx);
 int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css);
 int bio_associate_current(struct bio *bio);
 void bio_disassociate_task(struct bio *bio);
+void bio_clone_blkcg_association(struct bio *dst, struct bio *src);
 #else  /* CONFIG_BLK_CGROUP */
 static inline int bio_associate_blkcg(struct bio *bio,
                        struct cgroup_subsys_state *blkcg_css) { return 0; }
 static inline int bio_associate_current(struct bio *bio) { return -ENOENT; }
 static inline void bio_disassociate_task(struct bio *bio) { }
+static inline void bio_clone_blkcg_association(struct bio *dst,
+                       struct bio *src) { }
 #endif /* CONFIG_BLK_CGROUP */
 
 #ifdef CONFIG_HIGHMEM
index 168755791ec88ac895c4cc0eb267638ba459e39e..a9562bb029d00ad3dddd551ec35ef9f361c44872 100644 (file)
@@ -197,6 +197,9 @@ struct request {
 
        /* for bidi */
        struct request *next_rq;
+
+       ktime_t                 lat_hist_io_start;
+       int                     lat_hist_enabled;
 };
 
 static inline unsigned short req_get_ioprio(struct request *req)
@@ -890,7 +893,7 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq)
 {
        struct request_queue *q = rq->q;
 
-       if (unlikely(rq->cmd_type == REQ_TYPE_BLOCK_PC))
+       if (unlikely(rq->cmd_type != REQ_TYPE_FS))
                return q->limits.max_hw_sectors;
 
        if (!q->limits.chunk_sectors || (rq->cmd_flags & REQ_DISCARD))
@@ -1656,6 +1659,79 @@ extern int bdev_write_page(struct block_device *, sector_t, struct page *,
                                                struct writeback_control *);
 extern long bdev_direct_access(struct block_device *, sector_t,
                void __pmem **addr, unsigned long *pfn, long size);
+
+/*
+ * X-axis for IO latency histogram support.
+ */
+static const u_int64_t latency_x_axis_us[] = {
+       100,
+       200,
+       300,
+       400,
+       500,
+       600,
+       700,
+       800,
+       900,
+       1000,
+       1200,
+       1400,
+       1600,
+       1800,
+       2000,
+       2500,
+       3000,
+       4000,
+       5000,
+       6000,
+       7000,
+       9000,
+       10000
+};
+
+#define BLK_IO_LAT_HIST_DISABLE         0
+#define BLK_IO_LAT_HIST_ENABLE          1
+#define BLK_IO_LAT_HIST_ZERO            2
+
+struct io_latency_state {
+       u_int64_t       latency_y_axis_read[ARRAY_SIZE(latency_x_axis_us) + 1];
+       u_int64_t       latency_reads_elems;
+       u_int64_t       latency_y_axis_write[ARRAY_SIZE(latency_x_axis_us) + 1];
+       u_int64_t       latency_writes_elems;
+};
+
+static inline void
+blk_update_latency_hist(struct io_latency_state *s,
+                       int read,
+                       u_int64_t delta_us)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(latency_x_axis_us); i++) {
+               if (delta_us < (u_int64_t)latency_x_axis_us[i]) {
+                       if (read)
+                               s->latency_y_axis_read[i]++;
+                       else
+                               s->latency_y_axis_write[i]++;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(latency_x_axis_us)) {
+               /* Overflowed the histogram */
+               if (read)
+                       s->latency_y_axis_read[i]++;
+               else
+                       s->latency_y_axis_write[i]++;
+       }
+       if (read)
+               s->latency_reads_elems++;
+       else
+               s->latency_writes_elems++;
+}
+
+void blk_zero_latency_hist(struct io_latency_state *s);
+ssize_t blk_latency_hist_show(struct io_latency_state *s, char *buf);
+
 #else /* CONFIG_BLOCK */
 
 struct block_device;
index 5261751f6bd4dec116516691cbc40a6763a6d12b..5f5270941ba02ae78a81129dfff17d647ef3099c 100644 (file)
@@ -32,6 +32,7 @@ enum can_mode {
  * CAN common private data
  */
 struct can_priv {
+       struct net_device *dev;
        struct can_device_stats can_stats;
 
        struct can_bittiming bittiming, data_bittiming;
@@ -47,7 +48,7 @@ struct can_priv {
        u32 ctrlmode_static;    /* static enabled options for driver/hardware */
 
        int restart_ms;
-       struct timer_list restart_timer;
+       struct delayed_work restart_work;
 
        int (*do_set_bittiming)(struct net_device *dev);
        int (*do_set_data_bittiming)(struct net_device *dev);
index af9f0b9e80e61060420d3ff968856fd8da9e78c4..5f8249d378a237445cdf678a2fc3e567cbc00217 100644 (file)
@@ -214,6 +214,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
                                      struct user_namespace *ns, int cap);
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
+extern bool ns_capable_noaudit(struct user_namespace *ns, int cap);
 #else
 static inline bool has_capability(struct task_struct *t, int cap)
 {
@@ -241,6 +242,10 @@ static inline bool ns_capable(struct user_namespace *ns, int cap)
 {
        return true;
 }
+static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap)
+{
+       return true;
+}
 #endif /* CONFIG_MULTIUSER */
 extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
 extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
index 788c7c49a673cab6beab1f19fac0cc60fed795de..8da26329975429c8895afcceab874d11e3326471 100644 (file)
@@ -431,7 +431,6 @@ struct cgroup_subsys {
        void (*css_reset)(struct cgroup_subsys_state *css);
        void (*css_e_css_changed)(struct cgroup_subsys_state *css);
 
-       int (*allow_attach)(struct cgroup_taskset *tset);
        int (*can_attach)(struct cgroup_taskset *tset);
        void (*cancel_attach)(struct cgroup_taskset *tset);
        void (*attach)(struct cgroup_taskset *tset);
index 70358b9f5a7ab809be0dd1e6d5310c7588166ba7..cb91b44f5f7877d5899403b26ca1d9231c1ac9b6 100644 (file)
@@ -528,16 +528,6 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp)
        pr_cont_kernfs_path(cgrp->kn);
 }
 
-/*
- * Default Android check for whether the current process is allowed to move a
- * task across cgroups, either because CAP_SYS_NICE is set or because the uid
- * of the calling process is the same as the moved task or because we are
- * running as root.
- * Returns 0 if this is allowed, or -EACCES otherwise.
- */
-int subsys_cgroup_allow_attach(struct cgroup_taskset *tset);
-
-
 #else /* !CONFIG_CGROUPS */
 
 struct cgroup_subsys_state;
@@ -562,10 +552,6 @@ static inline void cgroup_free(struct task_struct *p) {}
 static inline int cgroup_init_early(void) { return 0; }
 static inline int cgroup_init(void) { return 0; }
 
-static inline int subsys_cgroup_allow_attach(void *tset)
-{
-       return -EINVAL;
-}
 #endif /* !CONFIG_CGROUPS */
 
 #endif /* _LINUX_CGROUP_H */
index 899ab9f8549e2bd489f36db0c47c855e5c92e19d..b874d5b61ffce6eefcc9dfbaef4ab907dac3d735 100644 (file)
@@ -382,6 +382,12 @@ void dm_put(struct mapped_device *md);
 void dm_set_mdptr(struct mapped_device *md, void *ptr);
 void *dm_get_mdptr(struct mapped_device *md);
 
+/*
+ * Export the device via the ioctl interface (uses mdptr).
+ */
+int dm_ioctl_export(struct mapped_device *md, const char *name,
+                   const char *uuid);
+
 /*
  * A device can still be used while suspended, but I/O is deferred.
  */
index e0ee0b3000b2da107c975137165fc989777d8a58..358a4db72a27d76e4df8cf41802cce72c8477c92 100644 (file)
 
 #include <linux/errno.h>
 
+struct pts_fs_info;
+
 #ifdef CONFIG_UNIX98_PTYS
 
-int devpts_new_index(struct inode *ptmx_inode);
-void devpts_kill_index(struct inode *ptmx_inode, int idx);
-void devpts_add_ref(struct inode *ptmx_inode);
-void devpts_del_ref(struct inode *ptmx_inode);
+/* Look up a pts fs info and get a ref to it */
+struct pts_fs_info *devpts_get_ref(struct inode *, struct file *);
+void devpts_put_ref(struct pts_fs_info *);
+
+int devpts_new_index(struct pts_fs_info *);
+void devpts_kill_index(struct pts_fs_info *, int);
+
 /* mknod in devpts */
-struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
-               void *priv);
+struct inode *devpts_pty_new(struct pts_fs_info *, dev_t, int, void *);
 /* get private structure */
 void *devpts_get_priv(struct inode *pts_inode);
 /* unlink */
 void devpts_pty_kill(struct inode *inode);
 
-#else
-
-/* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
-static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
-static inline void devpts_add_ref(struct inode *ptmx_inode) { }
-static inline void devpts_del_ref(struct inode *ptmx_inode) { }
-static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
-               dev_t device, int index, void *priv)
-{
-       return ERR_PTR(-EINVAL);
-}
-static inline void *devpts_get_priv(struct inode *pts_inode)
-{
-       return NULL;
-}
-static inline void devpts_pty_kill(struct inode *inode) { }
-
 #endif
 
 
index ab3d8d9bb3efc0061fb2168b069b47947ee38109..e1a123760dbfce85fd796a20a1c66427d71126b8 100644 (file)
@@ -226,6 +226,7 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate);
 #define ATTR_KILL_PRIV (1 << 14)
 #define ATTR_OPEN      (1 << 15) /* Truncating from open(O_TRUNC) */
 #define ATTR_TIMES_SET (1 << 16)
+#define ATTR_TOUCH     (1 << 17)
 
 /*
  * Whiteout is represented by a char device.  The following constants define the
@@ -710,6 +711,31 @@ enum inode_i_mutex_lock_class
        I_MUTEX_PARENT2,
 };
 
+static inline void inode_lock(struct inode *inode)
+{
+       mutex_lock(&inode->i_mutex);
+}
+
+static inline void inode_unlock(struct inode *inode)
+{
+       mutex_unlock(&inode->i_mutex);
+}
+
+static inline int inode_trylock(struct inode *inode)
+{
+       return mutex_trylock(&inode->i_mutex);
+}
+
+static inline int inode_is_locked(struct inode *inode)
+{
+       return mutex_is_locked(&inode->i_mutex);
+}
+
+static inline void inode_lock_nested(struct inode *inode, unsigned subclass)
+{
+       mutex_lock_nested(&inode->i_mutex, subclass);
+}
+
 void lock_two_nondirectories(struct inode *, struct inode*);
 void unlock_two_nondirectories(struct inode *, struct inode*);
 
@@ -3029,8 +3055,8 @@ static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx)
 }
 static inline bool dir_relax(struct inode *inode)
 {
-       mutex_unlock(&inode->i_mutex);
-       mutex_lock(&inode->i_mutex);
+       inode_unlock(inode);
+       inode_lock(inode);
        return !IS_DEADDIR(inode);
 }
 
index 533c4408529a19819570c5dc40d917aa10ac2d26..850d8822e8ff8be3fb53b57801c87c90f73b4589 100644 (file)
@@ -148,6 +148,7 @@ struct fsnotify_group {
        #define FS_PRIO_1       1 /* fanotify content based access control */
        #define FS_PRIO_2       2 /* fanotify pre-content access */
        unsigned int priority;
+       bool shutdown;          /* group is being shut down, don't queue more events */
 
        /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
        struct mutex mark_mutex;        /* protect marks_list */
@@ -179,7 +180,6 @@ struct fsnotify_group {
                        spinlock_t access_lock;
                        struct list_head access_list;
                        wait_queue_head_t access_waitq;
-                       atomic_t bypass_perm;
 #endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
                        int f_flags;
                        unsigned int max_marks;
@@ -308,6 +308,8 @@ extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *op
 extern void fsnotify_get_group(struct fsnotify_group *group);
 /* drop reference on a group from fsnotify_alloc_group */
 extern void fsnotify_put_group(struct fsnotify_group *group);
+/* group destruction begins, stop queuing new events */
+extern void fsnotify_group_stop_queueing(struct fsnotify_group *group);
 /* destroy group */
 extern void fsnotify_destroy_group(struct fsnotify_group *group);
 /* fasync handler function */
@@ -320,8 +322,6 @@ extern int fsnotify_add_event(struct fsnotify_group *group,
                              struct fsnotify_event *event,
                              int (*merge)(struct list_head *,
                                           struct fsnotify_event *));
-/* Remove passed event from groups notification queue */
-extern void fsnotify_remove_event(struct fsnotify_group *group, struct fsnotify_event *event);
 /* true if the group notification queue is empty */
 extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
 /* return, but do not dequeue the first event on the notification queue */
index 0f9bafa17a02dde9af7f4866ca8b9f741c83ddf1..d98780ca9604a7cae22d6c103c1b54eea2e22d0d 100644 (file)
@@ -62,7 +62,6 @@ struct serio;
 void i8042_lock_chip(void);
 void i8042_unlock_chip(void);
 int i8042_command(unsigned char *param, int command);
-bool i8042_check_port_owner(const struct serio *);
 int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
                                        struct serio *serio));
 int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
@@ -83,11 +82,6 @@ static inline int i8042_command(unsigned char *param, int command)
        return -ENODEV;
 }
 
-static inline bool i8042_check_port_owner(const struct serio *serio)
-{
-       return false;
-}
-
 static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
                                        struct serio *serio))
 {
index 7c27fa1030e873d1841f3e291e9fc806992967e3..795852dc343407520b0a273ac7cde8891d5b310b 100644 (file)
@@ -37,7 +37,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                      struct sk_buff *skb, const struct inet_diag_req_v2 *req,
                      struct user_namespace *user_ns,
                      u32 pid, u32 seq, u16 nlmsg_flags,
-                     const struct nlmsghdr *unlh);
+                     const struct nlmsghdr *unlh, bool net_admin);
 void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb,
                         struct netlink_callback *cb,
                         const struct inet_diag_req_v2 *r,
index 745986688c084009054209f568fb4a54fa50d5dd..f1f43c3bd512bb94015bf37af52ac6624a554709 100644 (file)
@@ -920,6 +920,16 @@ static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
 static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
 #endif
 
+/*
+ * The irqsave variants are for usage in non interrupt code. Do not use
+ * them in irq_chip callbacks. Use irq_gc_lock() instead.
+ */
+#define irq_gc_lock_irqsave(gc, flags) \
+       raw_spin_lock_irqsave(&(gc)->lock, flags)
+
+#define irq_gc_unlock_irqrestore(gc, flags)    \
+       raw_spin_unlock_irqrestore(&(gc)->lock, flags)
+
 static inline void irq_reg_writel(struct irq_chip_generic *gc,
                                  u32 val, int reg_offset)
 {
index e98425058f20dc6483a04ca7327409c6743d5d23..54048f336a1fa06c838c9493408efec6e35c4136 100644 (file)
 #define GITS_BASER_TYPE_SHIFT          (56)
 #define GITS_BASER_TYPE(r)             (((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT    (48)
-#define GITS_BASER_ENTRY_SIZE(r)       ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
+#define GITS_BASER_ENTRY_SIZE(r)       ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
 #define GITS_BASER_NonShareable                (0UL << 10)
 #define GITS_BASER_InnerShareable      (1UL << 10)
 #define GITS_BASER_OuterShareable      (2UL << 10)
index 2955e672391d5e41f35b1e56bdf1517ecd076e30..50220cab738c1d816f7f4117c2ae19baeb2561da 100644 (file)
@@ -202,26 +202,26 @@ extern int _cond_resched(void);
 
 /**
  * abs - return absolute value of an argument
- * @x: the value.  If it is unsigned type, it is converted to signed type first
- *   (s64, long or int depending on its size).
+ * @x: the value.  If it is unsigned type, it is converted to signed type first.
+ *     char is treated as if it was signed (regardless of whether it really is)
+ *     but the macro's return type is preserved as char.
  *
- * Return: an absolute value of x.  If x is 64-bit, macro's return type is s64,
- *   otherwise it is signed long.
+ * Return: an absolute value of x.
  */
-#define abs(x) __builtin_choose_expr(sizeof(x) == sizeof(s64), ({      \
-               s64 __x = (x);                                          \
-               (__x < 0) ? -__x : __x;                                 \
-       }), ({                                                          \
-               long ret;                                               \
-               if (sizeof(x) == sizeof(long)) {                        \
-                       long __x = (x);                                 \
-                       ret = (__x < 0) ? -__x : __x;                   \
-               } else {                                                \
-                       int __x = (x);                                  \
-                       ret = (__x < 0) ? -__x : __x;                   \
-               }                                                       \
-               ret;                                                    \
-       }))
+#define abs(x) __abs_choose_expr(x, long long,                         \
+               __abs_choose_expr(x, long,                              \
+               __abs_choose_expr(x, int,                               \
+               __abs_choose_expr(x, short,                             \
+               __abs_choose_expr(x, char,                              \
+               __builtin_choose_expr(                                  \
+                       __builtin_types_compatible_p(typeof(x), char),  \
+                       (char)({ signed char __x = (x); __x<0?-__x:__x; }), \
+                       ((void)0)))))))
+
+#define __abs_choose_expr(x, type, other) __builtin_choose_expr(       \
+       __builtin_types_compatible_p(typeof(x),   signed type) ||       \
+       __builtin_types_compatible_p(typeof(x), unsigned type),         \
+       ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
 
 /**
  * reciprocal_scale - "scale" a value into range [0, ep_ro)
@@ -356,6 +356,7 @@ int __must_check kstrtou16(const char *s, unsigned int base, u16 *res);
 int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
 int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
 int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
+int __must_check kstrtobool(const char *s, bool *res);
 
 int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
 int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
@@ -367,6 +368,7 @@ int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigne
 int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
 int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
 int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
+int __must_check kstrtobool_from_user(const char __user *s, size_t count, bool *res);
 
 static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
 {
@@ -830,8 +832,4 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
         /* OTHER_WRITABLE?  Generally considered a bad idea. */                \
         BUILD_BUG_ON_ZERO((perms) & 2) +                                       \
         (perms))
-
-/* To identify board information in panic logs, set this */
-extern char *mach_panic_string;
-
 #endif
index 034117b3be5f7d91e5e869ea9e856f51964ebac6..782d4e814e2132e4f4673255b22bec8fdcc27bba 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef NVM_H
 #define NVM_H
 
+#include <linux/types.h>
+
 enum {
        NVM_IO_OK = 0,
        NVM_IO_REQUEUE = 1,
@@ -11,10 +13,71 @@ enum {
        NVM_IOTYPE_GC = 1,
 };
 
+#define NVM_BLK_BITS (16)
+#define NVM_PG_BITS  (16)
+#define NVM_SEC_BITS (8)
+#define NVM_PL_BITS  (8)
+#define NVM_LUN_BITS (8)
+#define NVM_CH_BITS  (8)
+
+struct ppa_addr {
+       /* Generic structure for all addresses */
+       union {
+               struct {
+                       u64 blk         : NVM_BLK_BITS;
+                       u64 pg          : NVM_PG_BITS;
+                       u64 sec         : NVM_SEC_BITS;
+                       u64 pl          : NVM_PL_BITS;
+                       u64 lun         : NVM_LUN_BITS;
+                       u64 ch          : NVM_CH_BITS;
+               } g;
+
+               u64 ppa;
+       };
+};
+
+struct nvm_rq;
+struct nvm_id;
+struct nvm_dev;
+
+typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
+typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
+typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
+typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
+                               nvm_l2p_update_fn *, void *);
+typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int,
+                               nvm_bb_update_fn *, void *);
+typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
+typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
+typedef void (nvm_destroy_dma_pool_fn)(void *);
+typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t,
+                                                               dma_addr_t *);
+typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t);
+
+struct nvm_dev_ops {
+       nvm_id_fn               *identity;
+       nvm_get_l2p_tbl_fn      *get_l2p_tbl;
+       nvm_op_bb_tbl_fn        *get_bb_tbl;
+       nvm_op_set_bb_fn        *set_bb_tbl;
+
+       nvm_submit_io_fn        *submit_io;
+       nvm_erase_blk_fn        *erase_block;
+
+       nvm_create_dma_pool_fn  *create_dma_pool;
+       nvm_destroy_dma_pool_fn *destroy_dma_pool;
+       nvm_dev_dma_alloc_fn    *dev_dma_alloc;
+       nvm_dev_dma_free_fn     *dev_dma_free;
+
+       unsigned int            max_phys_sect;
+};
+
+
+
 #ifdef CONFIG_NVM
 
 #include <linux/blkdev.h>
-#include <linux/types.h>
 #include <linux/file.h>
 #include <linux/dmapool.h>
 
@@ -58,8 +121,9 @@ enum {
        /* Block Types */
        NVM_BLK_T_FREE          = 0x0,
        NVM_BLK_T_BAD           = 0x1,
-       NVM_BLK_T_DEV           = 0x2,
-       NVM_BLK_T_HOST          = 0x4,
+       NVM_BLK_T_GRWN_BAD      = 0x2,
+       NVM_BLK_T_DEV           = 0x4,
+       NVM_BLK_T_HOST          = 0x8,
 };
 
 struct nvm_id_group {
@@ -125,29 +189,6 @@ struct nvm_tgt_instance {
 #define NVM_VERSION_MINOR 0
 #define NVM_VERSION_PATCH 0
 
-#define NVM_BLK_BITS (16)
-#define NVM_PG_BITS  (16)
-#define NVM_SEC_BITS (8)
-#define NVM_PL_BITS  (8)
-#define NVM_LUN_BITS (8)
-#define NVM_CH_BITS  (8)
-
-struct ppa_addr {
-       /* Generic structure for all addresses */
-       union {
-               struct {
-                       u64 blk         : NVM_BLK_BITS;
-                       u64 pg          : NVM_PG_BITS;
-                       u64 sec         : NVM_SEC_BITS;
-                       u64 pl          : NVM_PL_BITS;
-                       u64 lun         : NVM_LUN_BITS;
-                       u64 ch          : NVM_CH_BITS;
-               } g;
-
-               u64 ppa;
-       };
-};
-
 struct nvm_rq {
        struct nvm_tgt_instance *ins;
        struct nvm_dev *dev;
@@ -181,39 +222,6 @@ static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata)
 
 struct nvm_block;
 
-typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
-typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
-typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
-typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
-                               nvm_l2p_update_fn *, void *);
-typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int,
-                               nvm_bb_update_fn *, void *);
-typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
-typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
-typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
-typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
-typedef void (nvm_destroy_dma_pool_fn)(void *);
-typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t,
-                                                               dma_addr_t *);
-typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t);
-
-struct nvm_dev_ops {
-       nvm_id_fn               *identity;
-       nvm_get_l2p_tbl_fn      *get_l2p_tbl;
-       nvm_op_bb_tbl_fn        *get_bb_tbl;
-       nvm_op_set_bb_fn        *set_bb_tbl;
-
-       nvm_submit_io_fn        *submit_io;
-       nvm_erase_blk_fn        *erase_block;
-
-       nvm_create_dma_pool_fn  *create_dma_pool;
-       nvm_destroy_dma_pool_fn *destroy_dma_pool;
-       nvm_dev_dma_alloc_fn    *dev_dma_alloc;
-       nvm_dev_dma_free_fn     *dev_dma_free;
-
-       unsigned int            max_phys_sect;
-};
-
 struct nvm_lun {
        int id;
 
index 24daf8fc4d7c71e4c36ed0063849c01a3b31d022..fec66f86eeffedbcfd8c86d6ec8f313b6859932c 100644 (file)
@@ -25,6 +25,7 @@ enum {
        MEMBLOCK_NONE           = 0x0,  /* No special request */
        MEMBLOCK_HOTPLUG        = 0x1,  /* hotpluggable region */
        MEMBLOCK_MIRROR         = 0x2,  /* mirrored region */
+       MEMBLOCK_NOMAP          = 0x4,  /* don't add to kernel direct mapping */
 };
 
 struct memblock_region {
@@ -82,6 +83,7 @@ bool memblock_overlaps_region(struct memblock_type *type,
 int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
 int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
 int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
+int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
 ulong choose_memblock_flags(void);
 
 /* Low level functions */
@@ -184,6 +186,11 @@ static inline bool memblock_is_mirror(struct memblock_region *m)
        return m->flags & MEMBLOCK_MIRROR;
 }
 
+static inline bool memblock_is_nomap(struct memblock_region *m)
+{
+       return m->flags & MEMBLOCK_NOMAP;
+}
+
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
                            unsigned long  *end_pfn);
@@ -319,6 +326,7 @@ phys_addr_t memblock_start_of_DRAM(void);
 phys_addr_t memblock_end_of_DRAM(void);
 void memblock_enforce_memory_limit(phys_addr_t memory_limit);
 int memblock_is_memory(phys_addr_t addr);
+int memblock_is_map_memory(phys_addr_t addr);
 int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
 int memblock_is_reserved(phys_addr_t addr);
 bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
index cd0e2413c358d4cf58072ebbdc2cfea2684fd245..435fd8426b8acf81967e75af13027cca14a1ea6d 100644 (file)
@@ -174,6 +174,11 @@ struct mem_cgroup_thresholds {
        struct mem_cgroup_threshold_ary *spare;
 };
 
+struct mem_cgroup_id {
+       int id;
+       atomic_t ref;
+};
+
 /*
  * The memory controller data structure. The memory controller controls both
  * page cache and RSS per cgroup. We would eventually like to provide
@@ -183,6 +188,9 @@ struct mem_cgroup_thresholds {
 struct mem_cgroup {
        struct cgroup_subsys_state css;
 
+       /* Private memcg ID. Used to ID objects that outlive the cgroup */
+       struct mem_cgroup_id id;
+
        /* Accounted resources */
        struct page_counter memory;
        struct page_counter memsw;
diff --git a/include/linux/memory-state-time.h b/include/linux/memory-state-time.h
new file mode 100644 (file)
index 0000000..d2212b0
--- /dev/null
@@ -0,0 +1,42 @@
+/* include/linux/memory-state-time.h
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/workqueue.h>
+
+#define UPDATE_MEMORY_STATE(BLOCK, VALUE) BLOCK->update_call(BLOCK, VALUE)
+
+struct memory_state_update_block;
+
+typedef void (*memory_state_update_fn_t)(struct memory_state_update_block *ub,
+               int value);
+
+/* This struct is populated when you pass it to a memory_state_register*
+ * function. The update_call function is used for an update and defined in the
+ * typedef memory_state_update_fn_t
+ */
+struct memory_state_update_block {
+       memory_state_update_fn_t update_call;
+       int id;
+};
+
+/* Register a frequency struct memory_state_update_block to provide updates to
+ * memory_state_time about frequency changes using its update_call function.
+ */
+struct memory_state_update_block *memory_state_register_frequency_source(void);
+
+/* Register a bandwidth struct memory_state_update_block to provide updates to
+ * memory_state_time about bandwidth changes using its update_call function.
+ */
+struct memory_state_update_block *memory_state_register_bandwidth_source(void);
index d409ceb2231ec1908842416a9de1ddb62bef2709..c118a7ec94d6f15b25f558dbd171336da400a9f6 100644 (file)
@@ -350,7 +350,7 @@ static inline int pm80x_dev_suspend(struct device *dev)
        int irq = platform_get_irq(pdev, 0);
 
        if (device_may_wakeup(dev))
-               set_bit((1 << irq), &chip->wu_flag);
+               set_bit(irq, &chip->wu_flag);
 
        return 0;
 }
@@ -362,7 +362,7 @@ static inline int pm80x_dev_resume(struct device *dev)
        int irq = platform_get_irq(pdev, 0);
 
        if (device_may_wakeup(dev))
-               clear_bit((1 << irq), &chip->wu_flag);
+               clear_bit(irq, &chip->wu_flag);
 
        return 0;
 }
index 494682ce4bf38b2c308dae7ad4e0bf1cab600495..3ab3cede28eac4729e345bf3868ed4de5bb727c1 100644 (file)
@@ -223,6 +223,21 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev,
 int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
                     struct cros_ec_command *msg);
 
+/**
+ * cros_ec_cmd_xfer_status - Send a command to the ChromeOS EC
+ *
+ * This function is identical to cros_ec_cmd_xfer, except it returns success
+ * status only if both the command was transmitted successfully and the EC
+ * replied with success status. It's not necessary to check msg->result when
+ * using this function.
+ *
+ * @ec_dev: EC device
+ * @msg: Message to write
+ * @return: Num. of bytes transferred on success, <0 on failure
+ */
+int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
+                           struct cros_ec_command *msg);
+
 /**
  * cros_ec_remove - Remove a ChromeOS EC
  *
index 1fd50dcfe47c629b75e9d8cfe855cad3aba8a1fa..175c82699e9d68a84e034295c6ef14aaf6e6e309 100644 (file)
 /*
  * time in us for processing a single channel, calculated as follows:
  *
- * num cycles = open delay + (sample delay + conv time) * averaging
+ * max num cycles = open delay + (sample delay + conv time) * averaging
  *
- * num cycles: 152 + (1 + 13) * 16 = 376
+ * max num cycles: 262143 + (255 + 13) * 16 = 266431
  *
  * clock frequency: 26MHz / 8 = 3.25MHz
  * clock period: 1 / 3.25MHz = 308ns
  *
- * processing time: 376 * 308ns = 116us
+ * max processing time: 266431 * 308ns = 83ms(approx)
  */
-#define IDLE_TIMEOUT 116 /* microsec */
+#define IDLE_TIMEOUT 83 /* milliseconds */
 
 #define TSCADC_CELLS           2
 
index f079fb1a31f7f7953f0bb28f6f3a145279598dc7..a8786d27ab8117b993491ba1ea5eb8411b6bcd71 100644 (file)
@@ -160,6 +160,7 @@ enum {
 enum {
        MLX5_FENCE_MODE_NONE                    = 0 << 5,
        MLX5_FENCE_MODE_INITIATOR_SMALL         = 1 << 5,
+       MLX5_FENCE_MODE_FENCE                   = 2 << 5,
        MLX5_FENCE_MODE_STRONG_ORDERING         = 3 << 5,
        MLX5_FENCE_MODE_SMALL_AND_FENCE         = 4 << 5,
 };
@@ -534,9 +535,9 @@ struct mlx5_destroy_qp_mbox_out {
 struct mlx5_modify_qp_mbox_in {
        struct mlx5_inbox_hdr   hdr;
        __be32                  qpn;
-       u8                      rsvd1[4];
-       __be32                  optparam;
        u8                      rsvd0[4];
+       __be32                  optparam;
+       u8                      rsvd1[4];
        struct mlx5_qp_context  ctx;
 };
 
index 78afe8b9862999bb1aa88d69854a575023d9a30e..f8a729751faa41bd76a088e14a5936dbbf625abc 100644 (file)
@@ -1323,8 +1323,7 @@ static inline int stack_guard_page_end(struct vm_area_struct *vma,
                !vma_growsup(vma->vm_next, addr);
 }
 
-extern struct task_struct *task_of_stack(struct task_struct *task,
-                               struct vm_area_struct *vma, bool in_group);
+int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t);
 
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
@@ -1911,6 +1910,7 @@ extern void mm_drop_all_locks(struct mm_struct *mm);
 
 extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
 extern struct file *get_mm_exe_file(struct mm_struct *mm);
+extern struct file *get_task_exe_file(struct task_struct *task);
 
 extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
 extern struct vm_area_struct *_install_special_mapping(struct mm_struct *mm,
@@ -2124,6 +2124,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,
 #define FOLL_MIGRATION 0x400   /* wait for page to replace migration entry */
 #define FOLL_TRIED     0x800   /* a retry, previous pass started an IO */
 #define FOLL_MLOCK     0x1000  /* lock present pages */
+#define FOLL_COW       0x4000  /* internal GUP flag */
 
 typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
                        void *data);
index 37967b6da03cf542d7a5762342c2089d93054b7a..0860efd6e1bedd32710f0528ee2f888111e1f528 100644 (file)
@@ -136,6 +136,10 @@ struct mmc_request {
        struct completion       completion;
        void                    (*done)(struct mmc_request *);/* completion function */
        struct mmc_host         *host;
+       ktime_t                 io_start;
+#ifdef CONFIG_BLOCK
+       int                     lat_hist_enabled;
+#endif
 };
 
 struct mmc_card;
index 3cb6858d9bb2e519b8c71cb07e8a6bc05d4a4137..3f29ba41c025e24b1c091c92a6096eafd9ca7be2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/fault-inject.h>
+#include <linux/blkdev.h>
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
@@ -391,6 +392,11 @@ struct mmc_host {
        } embedded_sdio_data;
 #endif
 
+#ifdef CONFIG_BLOCK
+       int                     latency_hist_enabled;
+       struct io_latency_state io_lat_s;
+#endif
+
        unsigned long           private[0] ____cacheline_aligned;
 };
 
index e23a9e704536278dad66bc5e5d1f9f798036b8be..bab4053fb795b0a054616d8c1dc81d2ea509e441 100644 (file)
@@ -65,8 +65,10 @@ enum {
 
 #ifdef CONFIG_CMA
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
+#  define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA)
 #else
 #  define is_migrate_cma(migratetype) false
+#  define is_migrate_cma_page(_page) false
 #endif
 
 #define for_each_migratetype_order(order, type) \
index f71a25e5fd25b574bceaf9b397b62e0913419067..f0f43ec45ee7e422fa5aae331694f45fd3012be8 100644 (file)
@@ -254,12 +254,12 @@ enum {
         * callbacks.
         */
        MSI_FLAG_USE_DEF_CHIP_OPS       = (1 << 1),
-       /* Build identity map between hwirq and irq */
-       MSI_FLAG_IDENTITY_MAP           = (1 << 2),
        /* Support multiple PCI MSI interrupts */
-       MSI_FLAG_MULTI_PCI_MSI          = (1 << 3),
+       MSI_FLAG_MULTI_PCI_MSI          = (1 << 2),
        /* Support PCI MSIX interrupts */
-       MSI_FLAG_PCI_MSIX               = (1 << 4),
+       MSI_FLAG_PCI_MSIX               = (1 << 3),
+       /* Needs early activate, required for PCI */
+       MSI_FLAG_ACTIVATE_EARLY         = (1 << 4),
 };
 
 int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
index 04c068e55353297fafc059e3dc3abcf5c0b1eab3..12b4d54a8ffaccb2616d848830c83fd025b01a2e 100644 (file)
@@ -511,7 +511,6 @@ static inline void napi_enable(struct napi_struct *n)
        clear_bit(NAPI_STATE_NPSVC, &n->state);
 }
 
-#ifdef CONFIG_SMP
 /**
  *     napi_synchronize - wait until NAPI is not running
  *     @n: napi context
@@ -522,12 +521,12 @@ static inline void napi_enable(struct napi_struct *n)
  */
 static inline void napi_synchronize(const struct napi_struct *n)
 {
-       while (test_bit(NAPI_STATE_SCHED, &n->state))
-               msleep(1);
+       if (IS_ENABLED(CONFIG_SMP))
+               while (test_bit(NAPI_STATE_SCHED, &n->state))
+                       msleep(1);
+       else
+               barrier();
 }
-#else
-# define napi_synchronize(n)   barrier()
-#endif
 
 enum netdev_queue_state_t {
        __QUEUE_STATE_DRV_XOFF,
@@ -1987,8 +1986,8 @@ struct napi_gro_cb {
        /* This is non-zero if the packet may be of the same flow. */
        u8      same_flow:1;
 
-       /* Used in udp_gro_receive */
-       u8      udp_mark:1;
+       /* Used in tunnel GRO receive */
+       u8      encap_mark:1;
 
        /* GRO checksum is valid */
        u8      csum_valid:1;
@@ -3037,6 +3036,7 @@ static inline void napi_free_frags(struct napi_struct *napi)
        napi->skb = NULL;
 }
 
+bool netdev_is_rx_handler_busy(struct net_device *dev);
 int netdev_rx_handler_register(struct net_device *dev,
                               rx_handler_func_t *rx_handler,
                               void *rx_handler_data);
index 9bb77d3ed6e0c5a35f8c77c0fb20821a237984ea..c2256d74654333b9103fab444c4e318e2c7d422a 100644 (file)
@@ -74,7 +74,7 @@ static inline void nvmem_cell_put(struct nvmem_cell *cell)
 {
 }
 
-static inline char *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
+static inline void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
 {
        return ERR_PTR(-ENOSYS);
 }
index 26eabf5ec718a457eb9cef5635f5c475cca0c48d..fbfadba81c5ac949628799c81c50f300ab907fa9 100644 (file)
@@ -601,56 +601,56 @@ static inline int fault_in_pages_readable(const char __user *uaddr, int size)
  */
 static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
 {
-       int ret = 0;
        char __user *end = uaddr + size - 1;
 
        if (unlikely(size == 0))
-               return ret;
+               return 0;
 
+       if (unlikely(uaddr > end))
+               return -EFAULT;
        /*
         * Writing zeroes into userspace here is OK, because we know that if
         * the zero gets there, we'll be overwriting it.
         */
-       while (uaddr <= end) {
-               ret = __put_user(0, uaddr);
-               if (ret != 0)
-                       return ret;
+       do {
+               if (unlikely(__put_user(0, uaddr) != 0))
+                       return -EFAULT;
                uaddr += PAGE_SIZE;
-       }
+       } while (uaddr <= end);
 
        /* Check whether the range spilled into the next page. */
        if (((unsigned long)uaddr & PAGE_MASK) ==
                        ((unsigned long)end & PAGE_MASK))
-               ret = __put_user(0, end);
+               return __put_user(0, end);
 
-       return ret;
+       return 0;
 }
 
 static inline int fault_in_multipages_readable(const char __user *uaddr,
                                               int size)
 {
        volatile char c;
-       int ret = 0;
        const char __user *end = uaddr + size - 1;
 
        if (unlikely(size == 0))
-               return ret;
+               return 0;
 
-       while (uaddr <= end) {
-               ret = __get_user(c, uaddr);
-               if (ret != 0)
-                       return ret;
+       if (unlikely(uaddr > end))
+               return -EFAULT;
+
+       do {
+               if (unlikely(__get_user(c, uaddr) != 0))
+                       return -EFAULT;
                uaddr += PAGE_SIZE;
-       }
+       } while (uaddr <= end);
 
        /* Check whether the range spilled into the next page. */
        if (((unsigned long)uaddr & PAGE_MASK) ==
                        ((unsigned long)end & PAGE_MASK)) {
-               ret = __get_user(c, end);
-               (void)c;
+               return __get_user(c, end);
        }
 
-       return ret;
+       return 0;
 }
 
 int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
index d9ba49cedc5dfe19b1391a5156d465331df8e05e..37f05cb1dfd6d93cae1ceeffc8a3de1c0fcb0529 100644 (file)
 #define PCI_DEVICE_ID_KORENIX_JETCARDF2        0x1700
 #define PCI_DEVICE_ID_KORENIX_JETCARDF3        0x17ff
 
+#define PCI_VENDOR_ID_NETRONOME                0x19ee
+#define PCI_DEVICE_ID_NETRONOME_NFP3200        0x3200
+#define PCI_DEVICE_ID_NETRONOME_NFP3240        0x3240
+#define PCI_DEVICE_ID_NETRONOME_NFP4000        0x4000
+#define PCI_DEVICE_ID_NETRONOME_NFP6000        0x6000
+#define PCI_DEVICE_ID_NETRONOME_NFP6000_VF     0x6003
+
 #define PCI_VENDOR_ID_QMI              0x1a32
 
 #define PCI_VENDOR_ID_AZWAVE           0x1a3b
index c2fa3ecb0dce57dde9ad4a92a35dc4178d7a159e..146efefde2a157008fce62fcdaa376f13e2c7682 100644 (file)
 
 struct percpu_rw_semaphore {
        struct rcu_sync         rss;
-       unsigned int __percpu   *fast_read_ctr;
+       unsigned int __percpu   *read_count;
        struct rw_semaphore     rw_sem;
-       atomic_t                slow_read_ctr;
-       wait_queue_head_t       write_waitq;
+       wait_queue_head_t       writer;
+       int                     readers_block;
 };
 
-extern void percpu_down_read(struct percpu_rw_semaphore *);
-extern int  percpu_down_read_trylock(struct percpu_rw_semaphore *);
-extern void percpu_up_read(struct percpu_rw_semaphore *);
+extern int __percpu_down_read(struct percpu_rw_semaphore *, int);
+extern void __percpu_up_read(struct percpu_rw_semaphore *);
+
+static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
+{
+       might_sleep();
+
+       rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 0, _RET_IP_);
+
+       preempt_disable();
+       /*
+        * We are in an RCU-sched read-side critical section, so the writer
+        * cannot both change sem->state from readers_fast and start checking
+        * counters while we are here. So if we see !sem->state, we know that
+        * the writer won't be checking until we're past the preempt_enable()
+        * and that one the synchronize_sched() is done, the writer will see
+        * anything we did within this RCU-sched read-size critical section.
+        */
+       __this_cpu_inc(*sem->read_count);
+       if (unlikely(!rcu_sync_is_idle(&sem->rss)))
+               __percpu_down_read(sem, false); /* Unconditional memory barrier */
+       preempt_enable();
+       /*
+        * The barrier() from preempt_enable() prevents the compiler from
+        * bleeding the critical section out.
+        */
+}
+
+static inline int percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
+{
+       int ret = 1;
+
+       preempt_disable();
+       /*
+        * Same as in percpu_down_read().
+        */
+       __this_cpu_inc(*sem->read_count);
+       if (unlikely(!rcu_sync_is_idle(&sem->rss)))
+               ret = __percpu_down_read(sem, true); /* Unconditional memory barrier */
+       preempt_enable();
+       /*
+        * The barrier() from preempt_enable() prevents the compiler from
+        * bleeding the critical section out.
+        */
+
+       if (ret)
+               rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 1, _RET_IP_);
+
+       return ret;
+}
+
+static inline void percpu_up_read(struct percpu_rw_semaphore *sem)
+{
+       /*
+        * The barrier() in preempt_disable() prevents the compiler from
+        * bleeding the critical section out.
+        */
+       preempt_disable();
+       /*
+        * Same as in percpu_down_read().
+        */
+       if (likely(rcu_sync_is_idle(&sem->rss)))
+               __this_cpu_dec(*sem->read_count);
+       else
+               __percpu_up_read(sem); /* Unconditional memory barrier */
+       preempt_enable();
+
+       rwsem_release(&sem->rw_sem.dep_map, 1, _RET_IP_);
+}
 
 extern void percpu_down_write(struct percpu_rw_semaphore *);
 extern void percpu_up_write(struct percpu_rw_semaphore *);
 
 extern int __percpu_init_rwsem(struct percpu_rw_semaphore *,
                                const char *, struct lock_class_key *);
+
 extern void percpu_free_rwsem(struct percpu_rw_semaphore *);
 
-#define percpu_init_rwsem(brw) \
+#define percpu_init_rwsem(sem)                                 \
 ({                                                             \
        static struct lock_class_key rwsem_key;                 \
-       __percpu_init_rwsem(brw, #brw, &rwsem_key);             \
+       __percpu_init_rwsem(sem, #sem, &rwsem_key);             \
 })
 
-
 #define percpu_rwsem_is_held(sem) lockdep_is_held(&(sem)->rw_sem)
 
 static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem,
index a71958135b7ed9b405d6bcb968bd665b868f24d9..9dcb00ca2ec1ffd9c3672a3f7110669c76795e89 100644 (file)
@@ -121,6 +121,7 @@ struct hw_perf_event {
                struct { /* intel_cqm */
                        int                     cqm_state;
                        u32                     cqm_rmid;
+                       int                     is_group_event;
                        struct list_head        cqm_events_entry;
                        struct list_head        cqm_groups_entry;
                        struct list_head        cqm_group_entry;
index 3e96a6a7610338ff8ddd825a21ddc9bc5fe52e8b..d1a8ad7e5ae450b38c8d83ed2e74327424cfa79f 100644 (file)
@@ -95,6 +95,7 @@ extern int set_posix_acl(struct inode *, int, struct posix_acl *);
 extern int posix_acl_chmod(struct inode *, umode_t);
 extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
                struct posix_acl **);
+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
 
 extern int simple_set_acl(struct inode *, struct posix_acl *, int);
 extern int simple_acl_create(struct inode *, struct inode *);
index 831479f8df8f1b70638d59edc3cde6fc6fdcc22f..5cae2c6c90ad3b6b2a3f0af1b729596c41b5fec3 100644 (file)
 #ifndef _LINUX_PSTORE_H
 #define _LINUX_PSTORE_H
 
-#include <linux/time.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
 #include <linux/kmsg_dump.h>
 #include <linux/mutex.h>
-#include <linux/types.h>
 #include <linux/spinlock.h>
-#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/types.h>
 
 /* types */
 enum pstore_type_id {
@@ -67,6 +68,10 @@ struct pstore_info {
                        enum kmsg_dump_reason reason, u64 *id,
                        unsigned int part, const char *buf, bool compressed,
                        size_t size, struct pstore_info *psi);
+       int             (*write_buf_user)(enum pstore_type_id type,
+                       enum kmsg_dump_reason reason, u64 *id,
+                       unsigned int part, const char __user *buf,
+                       bool compressed, size_t size, struct pstore_info *psi);
        int             (*erase)(enum pstore_type_id type, u64 id,
                        int count, struct timespec time,
                        struct pstore_info *psi);
index 712757f320a459262cb23d0c16d4651c78f4791d..45ac5a0d29eefa85b4928c4c9dbe654dcfd047ca 100644 (file)
 #ifndef __LINUX_PSTORE_RAM_H__
 #define __LINUX_PSTORE_RAM_H__
 
+#include <linux/compiler.h>
 #include <linux/device.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/types.h>
-#include <linux/init.h>
 
 struct persistent_ram_buffer;
 struct rs_control;
@@ -59,7 +60,9 @@ void persistent_ram_free(struct persistent_ram_zone *prz);
 void persistent_ram_zap(struct persistent_ram_zone *prz);
 
 int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
-       unsigned int count);
+                        unsigned int count);
+int persistent_ram_write_user(struct persistent_ram_zone *prz,
+                             const void __user *s, unsigned int count);
 
 void persistent_ram_save_old(struct persistent_ram_zone *prz);
 size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
index a63a33e6196e23905406e2dab831b17b5d883597..ece7ed9a4a7054abf6649489d53016117698fac9 100644 (file)
@@ -59,6 +59,7 @@ static inline bool rcu_sync_is_idle(struct rcu_sync *rsp)
 }
 
 extern void rcu_sync_init(struct rcu_sync *, enum rcu_sync_type);
+extern void rcu_sync_enter_start(struct rcu_sync *);
 extern void rcu_sync_enter(struct rcu_sync *);
 extern void rcu_sync_exit(struct rcu_sync *);
 extern void rcu_sync_dtor(struct rcu_sync *);
index 951422587dd91844b4a61d696d49394d9a603377..ede29e8db82ddaa03698dd9a778124b935e204fd 100644 (file)
@@ -173,6 +173,9 @@ extern bool single_task_running(void);
 extern unsigned long nr_iowait(void);
 extern unsigned long nr_iowait_cpu(int cpu);
 extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load);
+#ifdef CONFIG_CPU_QUIET
+extern u64 nr_running_integral(unsigned int cpu);
+#endif
 
 extern void calc_global_load(unsigned long ticks);
 
@@ -314,6 +317,15 @@ extern char ___assert_task_state[1 - 2*!!(
 /* Task command name length */
 #define TASK_COMM_LEN 16
 
+enum task_event {
+       PUT_PREV_TASK   = 0,
+       PICK_NEXT_TASK  = 1,
+       TASK_WAKE       = 2,
+       TASK_MIGRATE    = 3,
+       TASK_UPDATE     = 4,
+       IRQ_UPDATE      = 5,
+};
+
 #include <linux/spinlock.h>
 
 /*
@@ -1273,6 +1285,41 @@ struct sched_statistics {
 };
 #endif
 
+#ifdef CONFIG_SCHED_WALT
+#define RAVG_HIST_SIZE_MAX  5
+
+/* ravg represents frequency scaled cpu-demand of tasks */
+struct ravg {
+       /*
+        * 'mark_start' marks the beginning of an event (task waking up, task
+        * starting to execute, task being preempted) within a window
+        *
+        * 'sum' represents how runnable a task has been within current
+        * window. It incorporates both running time and wait time and is
+        * frequency scaled.
+        *
+        * 'sum_history' keeps track of history of 'sum' seen over previous
+        * RAVG_HIST_SIZE windows. Windows where task was entirely sleeping are
+        * ignored.
+        *
+        * 'demand' represents maximum sum seen over previous
+        * sysctl_sched_ravg_hist_size windows. 'demand' could drive frequency
+        * demand for tasks.
+        *
+        * 'curr_window' represents task's contribution to cpu busy time
+        * statistics (rq->curr_runnable_sum) in current window
+        *
+        * 'prev_window' represents task's contribution to cpu busy time
+        * statistics (rq->prev_runnable_sum) in previous window
+        */
+       u64 mark_start;
+       u32 sum, demand;
+       u32 sum_history[RAVG_HIST_SIZE_MAX];
+       u32 curr_window, prev_window;
+       u16 active_windows;
+};
+#endif
+
 struct sched_entity {
        struct load_weight      load;           /* for load-balancing */
        struct rb_node          run_node;
@@ -1430,6 +1477,15 @@ struct task_struct {
        const struct sched_class *sched_class;
        struct sched_entity se;
        struct sched_rt_entity rt;
+#ifdef CONFIG_SCHED_WALT
+       struct ravg ravg;
+       /*
+        * 'init_load_pct' represents the initial task load assigned to children
+        * of this task
+        */
+       u32 init_load_pct;
+#endif
+
 #ifdef CONFIG_CGROUP_SCHED
        struct task_group *sched_task_group;
 #endif
index 4479e48c7712f384493bc0fe15de8207519575b0..d68e88c9d4d7032943e65c519aaf401f4bbe16b7 100644 (file)
@@ -39,6 +39,16 @@ extern unsigned int sysctl_sched_latency;
 extern unsigned int sysctl_sched_min_granularity;
 extern unsigned int sysctl_sched_wakeup_granularity;
 extern unsigned int sysctl_sched_child_runs_first;
+extern unsigned int sysctl_sched_is_big_little;
+extern unsigned int sysctl_sched_sync_hint_enable;
+extern unsigned int sysctl_sched_initial_task_util;
+extern unsigned int sysctl_sched_cstate_aware;
+#ifdef CONFIG_SCHED_WALT
+extern unsigned int sysctl_sched_use_walt_cpu_util;
+extern unsigned int sysctl_sched_use_walt_task_util;
+extern unsigned int sysctl_sched_walt_init_task_load_pct;
+extern unsigned int sysctl_sched_walt_cpu_high_irqload;
+#endif
 
 enum sched_tunable_scaling {
        SCHED_TUNABLESCALING_NONE,
index a3f1627ac609e06891b30039cca85c7ee7e3cf2b..1daf3e1f98a75ca54ee7f9e465c10842ea2429a6 100644 (file)
 #define for_each_possible_sd_level(level)                  \
        for (level = 0; level < NR_SD_LEVELS; level++)
 
+#ifdef CONFIG_SMP
+
 extern struct sched_group_energy *sge_array[NR_CPUS][NR_SD_LEVELS];
 
 void init_sched_energy_costs(void);
 
+#else
+
+#define init_sched_energy_costs() do { } while (0)
+
+#endif /* CONFIG_SMP */
+
 #endif
index 976ce3a19f1b23646c4494029929e538f5e0204b..d0efd6e6c20a6a6a39273639dbd33f3d77c2e156 100644 (file)
@@ -21,6 +21,7 @@ struct sem_array {
        struct list_head        list_id;        /* undo requests on this array */
        int                     sem_nsems;      /* no. of semaphores in array */
        int                     complex_count;  /* pending complex operations */
+       bool                    complex_mode;   /* no parallel simple ops */
 };
 
 #ifdef CONFIG_SYSVIPC
index df4ab5de15862c7ba35fb532174db56866ffff47..c733cff44e18a74f3949032d1413356df0a9e226 100644 (file)
@@ -31,7 +31,8 @@ struct serio {
 
        struct serio_device_id id;
 
-       spinlock_t lock;                /* protects critical sections from port's interrupt handler */
+       /* Protects critical sections from port's interrupt handler */
+       spinlock_t lock;
 
        int (*write)(struct serio *, unsigned char);
        int (*open)(struct serio *);
@@ -40,16 +41,29 @@ struct serio {
        void (*stop)(struct serio *);
 
        struct serio *parent;
-       struct list_head child_node;    /* Entry in parent->children list */
+       /* Entry in parent->children list */
+       struct list_head child_node;
        struct list_head children;
-       unsigned int depth;             /* level of nesting in serio hierarchy */
+       /* Level of nesting in serio hierarchy */
+       unsigned int depth;
 
-       struct serio_driver *drv;       /* accessed from interrupt, must be protected by serio->lock and serio->sem */
-       struct mutex drv_mutex;         /* protects serio->drv so attributes can pin driver */
+       /*
+        * serio->drv is accessed from interrupt handlers; when modifying
+        * caller should acquire serio->drv_mutex and serio->lock.
+        */
+       struct serio_driver *drv;
+       /* Protects serio->drv so attributes can pin current driver */
+       struct mutex drv_mutex;
 
        struct device dev;
 
        struct list_head node;
+
+       /*
+        * For use by PS/2 layer when several ports share hardware and
+        * may get indigestion when exposed to concurrent access (i8042).
+        */
+       struct mutex *ps2_cmd_mutex;
 };
 #define to_serio_port(d)       container_of(d, struct serio, dev)
 
index 2037a861e3679910152a98ba98a667b395c6773c..4ef384b172e0e5f307edfd69abd5d100d339c913 100644 (file)
@@ -144,6 +144,18 @@ void kfree(const void *);
 void kzfree(const void *);
 size_t ksize(const void *);
 
+#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR
+const char *__check_heap_object(const void *ptr, unsigned long n,
+                               struct page *page);
+#else
+static inline const char *__check_heap_object(const void *ptr,
+                                             unsigned long n,
+                                             struct page *page)
+{
+       return NULL;
+}
+#endif
+
 /*
  * Some archs want to perform DMA into kmalloc caches and need a guaranteed
  * alignment larger than the alignment of a 64-bit integer.
index 33885118523c7ce695e2c901e42d76250a84a8da..f4e857e920cd5b9b1e8edc3d94d08704c6344ea4 100644 (file)
@@ -81,6 +81,7 @@ struct kmem_cache {
        int reserved;           /* Reserved bytes at the end of slabs */
        const char *name;       /* Name (only for display!) */
        struct list_head list;  /* List of slab caches */
+       int red_left_pad;       /* Left redzone padding size */
 #ifdef CONFIG_SYSFS
        struct kobject kobj;    /* For sysfs */
 #endif
index 76199b75d5845d21cbcfb67786dfec757e30a446..e302c447e057a98b0ba47b5bc73acd816b9dc7f7 100644 (file)
@@ -1,6 +1,16 @@
 #ifndef __SMC91X_H__
 #define __SMC91X_H__
 
+/*
+ * These bits define which access sizes a platform can support, rather
+ * than the maximal access size.  So, if your platform can do 16-bit
+ * and 32-bit accesses to the SMC91x device, but not 8-bit, set both
+ * SMC91X_USE_16BIT and SMC91X_USE_32BIT.
+ *
+ * The SMC91x driver requires at least one of SMC91X_USE_8BIT or
+ * SMC91X_USE_16BIT to be supported - just setting SMC91X_USE_32BIT is
+ * an invalid configuration.
+ */
 #define SMC91X_USE_8BIT (1 << 0)
 #define SMC91X_USE_16BIT (1 << 1)
 #define SMC91X_USE_32BIT (1 << 2)
index 9ef7795e65e40c5dfbee53726909fbcb2ce341b0..aa30789b0f65eea407dfc56c68f9817c756f281d 100644 (file)
@@ -127,7 +127,11 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
 
 extern bool sysfs_streq(const char *s1, const char *s2);
-extern int strtobool(const char *s, bool *res);
+extern int kstrtobool(const char *s, bool *res);
+static inline int strtobool(const char *s, bool *res)
+{
+       return kstrtobool(s, res);
+}
 
 #ifdef CONFIG_BINARY_PRINTF
 int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
index 7ba7dccaf0e7e1291b3489c9ece30318cb44fc6f..d8ca2eaa3a8bff3b548ecf14560643761b55e9ca 100644 (file)
@@ -266,6 +266,7 @@ static inline void workingset_node_pages_inc(struct radix_tree_node *node)
 
 static inline void workingset_node_pages_dec(struct radix_tree_node *node)
 {
+       VM_WARN_ON_ONCE(!workingset_node_pages(node));
        node->count--;
 }
 
@@ -281,6 +282,7 @@ static inline void workingset_node_shadows_inc(struct radix_tree_node *node)
 
 static inline void workingset_node_shadows_dec(struct radix_tree_node *node)
 {
+       VM_WARN_ON_ONCE(!workingset_node_shadows(node));
        node->count -= 1U << RADIX_TREE_COUNT_SHIFT;
 }
 
index fa7bc29925c929a36e0f1e53a3a7efc1a18cc9e6..ef17db6caaed837cc4ae7aed8909de54692dcf7c 100644 (file)
@@ -41,6 +41,8 @@ extern int proc_dostring(struct ctl_table *, int,
                         void __user *, size_t *, loff_t *);
 extern int proc_dointvec(struct ctl_table *, int,
                         void __user *, size_t *, loff_t *);
+extern int proc_douintvec(struct ctl_table *, int,
+                        void __user *, size_t *, loff_t *);
 extern int proc_dointvec_minmax(struct ctl_table *, int,
                                void __user *, size_t *, loff_t *);
 extern int proc_dointvec_jiffies(struct ctl_table *, int,
index ff307b548ed3c91a0f1cd05e486789305cefb43f..4cf89517783ab8e4a56a71ea6e88646427c74aa9 100644 (file)
@@ -145,6 +145,31 @@ static inline bool test_and_clear_restore_sigmask(void)
 #error "no set_restore_sigmask() provided and default one won't work"
 #endif
 
+#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES
+static inline int arch_within_stack_frames(const void * const stack,
+                                          const void * const stackend,
+                                          const void *obj, unsigned long len)
+{
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_HARDENED_USERCOPY
+extern void __check_object_size(const void *ptr, unsigned long n,
+                                       bool to_user);
+
+static __always_inline void check_object_size(const void *ptr, unsigned long n,
+                                             bool to_user)
+{
+       if (!__builtin_constant_p(n))
+               __check_object_size(ptr, n, to_user);
+}
+#else
+static inline void check_object_size(const void *ptr, unsigned long n,
+                                    bool to_user)
+{ }
+#endif /* CONFIG_HARDENED_USERCOPY */
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_THREAD_INFO_H */
index beebe3a02d43f5c527633cbd12af690c02e8288d..297f09f23896d2db41cd90a0cad37746e6ed77aa 100644 (file)
@@ -125,6 +125,32 @@ static inline bool timeval_valid(const struct timeval *tv)
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more microseconds then a second */
+       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+               return false;
+       return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+       /* We don't check the tv_sec as it can be positive or negative */
+
+       /* Can't have more nanoseconds then a second */
+       if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+               return false;
+       return true;
+}
+
 #define CURRENT_TIME           (current_kernel_time())
 #define CURRENT_TIME_SEC       ((struct timespec) { get_seconds(), 0 })
 
index 558129af828a7eb97ad64b1531ac2a4e3f71174d..f30c187ed785366231e318a7beab151e0bba64b6 100644 (file)
@@ -111,4 +111,11 @@ extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
 #define probe_kernel_address(addr, retval)             \
        probe_kernel_read(&retval, addr, sizeof(retval))
 
+#ifndef user_access_begin
+#define user_access_begin() do { } while (0)
+#define user_access_end() do { } while (0)
+#define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0)
+#define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0)
+#endif
+
 #endif         /* __LINUX_UACCESS_H__ */
index 8b01e1c3c6146623759f122b72ff6b3b869a0617..5f9c59da978bb19cf87e96526769e36a3b78e880 100644 (file)
@@ -76,7 +76,7 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
                struct iov_iter *i, unsigned long offset, size_t bytes);
 void iov_iter_advance(struct iov_iter *i, size_t bytes);
 int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
-int iov_iter_fault_in_multipages_readable(struct iov_iter *i, size_t bytes);
+#define iov_iter_fault_in_multipages_readable iov_iter_fault_in_readable
 size_t iov_iter_single_seg_count(const struct iov_iter *i);
 size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
                         struct iov_iter *i);
index 3e5d9075960f6c756ead3c60013f84f873206932..73fae8c4a5fb50d94b72f12bed28f98d170f5787 100644 (file)
@@ -189,6 +189,7 @@ extern void __inc_zone_state(struct zone *, enum zone_stat_item);
 extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
+void quiet_vmstat(void);
 void cpu_vm_stats_fold(int cpu);
 void refresh_zone_stat_thresholds(void);
 
@@ -249,6 +250,7 @@ static inline void __dec_zone_page_state(struct page *page,
 
 static inline void refresh_zone_stat_thresholds(void) { }
 static inline void cpu_vm_stats_fold(int cpu) { }
+static inline void quiet_vmstat(void) { }
 
 static inline void drain_zonestat(struct zone *zone,
                        struct per_cpu_pageset *pset) { }
index 9b4c418bebd84ae0a7debfbcc697ee92b136ec99..fd60eccb59a67969eba53416a376a3c912d62d81 100644 (file)
@@ -52,7 +52,7 @@ struct unix_sock {
        struct sock             sk;
        struct unix_address     *addr;
        struct path             path;
-       struct mutex            readlock;
+       struct mutex            iolock, bindlock;
        struct sock             *peer;
        struct list_head        link;
        atomic_long_t           inflight;
index 55b5419cb6a7909ed0723b09c6608b30d7a33843..bdd985f41022416ea04594b2a4ae7b6676d1d111 100644 (file)
@@ -89,7 +89,6 @@ struct fib_rules_ops {
        [FRA_FWMARK]    = { .type = NLA_U32 }, \
        [FRA_FWMASK]    = { .type = NLA_U32 }, \
        [FRA_TABLE]     = { .type = NLA_U32 }, \
-       [FRA_GOTO]      = { .type = NLA_U32 }, \
        [FRA_UID_START] = { .type = NLA_U32 }, \
        [FRA_UID_END]   = { .type = NLA_U32 }, \
        [FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
index af40bc586a1b6ae03ef751ce61276e58934e7406..86a7bdd61d1a90234dc84be0f48cf9fc680a4230 100644 (file)
@@ -283,6 +283,22 @@ struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
 struct sk_buff *iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum,
                                         int gso_type_mask);
 
+static inline int iptunnel_pull_offloads(struct sk_buff *skb)
+{
+       if (skb_is_gso(skb)) {
+               int err;
+
+               err = skb_unclone(skb, GFP_ATOMIC);
+               if (unlikely(err))
+                       return err;
+               skb_shinfo(skb)->gso_type &= ~(NETIF_F_GSO_ENCAP_ALL >>
+                                              NETIF_F_GSO_SHIFT);
+       }
+
+       skb->encapsulation = 0;
+       return 0;
+}
+
 static inline void iptunnel_xmit_stats(int err,
                                       struct net_device_stats *err_stats,
                                       struct pcpu_sw_netstats __percpu *stats)
index b36cebad6b2f72dcd60c50f6092306446908ee4d..6c480679423edd1353162e700b4f411d9ae351a3 100644 (file)
@@ -1513,6 +1513,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli
 {
        if (sk->sk_send_head == skb_unlinked)
                sk->sk_send_head = NULL;
+       if (tcp_sk(sk)->highest_sack == skb_unlinked)
+               tcp_sk(sk)->highest_sack = NULL;
 }
 
 static inline void tcp_init_send_head(struct sock *sk)
index 6d4ed18e14278a6091b7e1c3fa40f1b2d4796d06..e57f50258cdae779b920815216f240fa284be713 100644 (file)
@@ -238,6 +238,7 @@ int udp_get_port(struct sock *sk, unsigned short snum,
                 int (*saddr_cmp)(const struct sock *,
                                  const struct sock *));
 void udp_err(struct sk_buff *, u32);
+int udp_abort(struct sock *sk, int err);
 int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
 int udp_push_pending_frames(struct sock *sk);
 void udp_flush_pending_frames(struct sock *sk);
index 28ee5c2e6bcd7b08abeda34669cc2da17f4dcf9a..711322a8ee35ea6a3b9e6f42ce34a59b720f1fdc 100644 (file)
@@ -96,6 +96,6 @@ sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd,
 bool target_sense_desc_format(struct se_device *dev);
 sector_t target_to_linux_sector(struct se_device *dev, sector_t lb);
 bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
-                                      struct request_queue *q, int block_size);
+                                      struct request_queue *q);
 
 #endif /* TARGET_CORE_BACKEND_H */
index 689f4d2071225ab648c7e652669af57e4a9c0530..6afc6f388edf9bc1062dae96aea5abb7584c62e8 100644 (file)
@@ -139,6 +139,7 @@ enum se_cmd_flags_table {
        SCF_COMPARE_AND_WRITE_POST      = 0x00100000,
        SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000,
        SCF_ACK_KREF                    = 0x00400000,
+       SCF_TASK_ATTR_SET               = 0x01000000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -179,6 +180,7 @@ enum tcm_sense_reason_table {
        TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED    = R(0x15),
        TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED  = R(0x16),
        TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED  = R(0x17),
+       TCM_COPY_TARGET_DEVICE_NOT_REACHABLE    = R(0x18),
 #undef R
 };
 
index 7fb2557a760e432ffa054f2550acd8e8a9e7085a..ce9ea736f1d7e9c44a8cf5b892553e4881a9216c 100644 (file)
@@ -163,7 +163,6 @@ int core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
 void   core_tmr_release_req(struct se_tmr_req *);
 int    transport_generic_handle_tmr(struct se_cmd *);
 void   transport_generic_request_failure(struct se_cmd *, sense_reason_t);
-void   __target_execute_cmd(struct se_cmd *);
 int    transport_lookup_tmr_lun(struct se_cmd *, u64);
 void   core_allocate_nexus_loss_ua(struct se_node_acl *acl);
 
diff --git a/include/trace/events/android_fs.h b/include/trace/events/android_fs.h
new file mode 100644 (file)
index 0000000..531da43
--- /dev/null
@@ -0,0 +1,31 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM android_fs
+
+#if !defined(_TRACE_ANDROID_FS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_H
+
+#include <linux/tracepoint.h>
+#include <trace/events/android_fs_template.h>
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_dataread_start,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+                pid_t pid, char *command),
+       TP_ARGS(inode, offset, bytes, pid, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_dataread_end,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+       TP_ARGS(inode, offset, bytes));
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_datawrite_start,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+                pid_t pid, char *command),
+       TP_ARGS(inode, offset, bytes, pid, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_datawrite_end,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+       TP_ARGS(inode, offset, bytes));
+
+#endif /* _TRACE_ANDROID_FS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/android_fs_template.h b/include/trace/events/android_fs_template.h
new file mode 100644 (file)
index 0000000..618988b
--- /dev/null
@@ -0,0 +1,79 @@
+#if !defined(_TRACE_ANDROID_FS_TEMPLATE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_TEMPLATE_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(android_fs_data_start_template,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+                pid_t pid, char *command),
+       TP_ARGS(inode, offset, bytes, pid, command),
+       TP_STRUCT__entry(
+               __array(char, path, MAX_FILTER_STR_VAL);
+               __field(char *, pathname);
+               __field(loff_t, offset);
+               __field(int,    bytes);
+               __field(loff_t, i_size);
+               __string(cmdline, command);
+               __field(pid_t,  pid);
+               __field(ino_t,  ino);
+       ),
+       TP_fast_assign(
+               {
+                       struct dentry *d;
+
+                       /*
+                        * Grab a reference to the inode here because
+                        * d_obtain_alias() will either drop the inode
+                        * reference if it locates an existing dentry
+                        * or transfer the reference to the new dentry
+                        * created. In our case, the file is still open,
+                        * so the dentry is guaranteed to exist (connected),
+                        * so d_obtain_alias() drops the reference we
+                        * grabbed here.
+                        */
+                       ihold(inode);
+                       d = d_obtain_alias(inode);
+                       if (!IS_ERR(d)) {
+                               __entry->pathname = dentry_path(d,
+                                                       __entry->path,
+                                                       MAX_FILTER_STR_VAL);
+                               dput(d);
+                       } else
+                               __entry->pathname = ERR_PTR(-EINVAL);
+                       __entry->offset         = offset;
+                       __entry->bytes          = bytes;
+                       __entry->i_size         = i_size_read(inode);
+                       __assign_str(cmdline, command);
+                       __entry->pid            = pid;
+                       __entry->ino            = inode->i_ino;
+               }
+       ),
+       TP_printk("entry_name %s, offset %llu, bytes %d, cmdline %s,"
+                 " pid %d, i_size %llu, ino %lu",
+                 (IS_ERR(__entry->pathname) ? "ERROR" : __entry->pathname),
+                 __entry->offset, __entry->bytes, __get_str(cmdline),
+                 __entry->pid, __entry->i_size,
+                 (unsigned long) __entry->ino)
+);
+
+DECLARE_EVENT_CLASS(android_fs_data_end_template,
+       TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+       TP_ARGS(inode, offset, bytes),
+       TP_STRUCT__entry(
+               __field(ino_t,  ino);
+               __field(loff_t, offset);
+               __field(int,    bytes);
+       ),
+       TP_fast_assign(
+               {
+                       __entry->ino            = inode->i_ino;
+                       __entry->offset         = offset;
+                       __entry->bytes          = bytes;
+               }
+       ),
+       TP_printk("ino %lu, offset %llu, bytes %d",
+                 (unsigned long) __entry->ino,
+                 __entry->offset, __entry->bytes)
+);
+
+#endif /* _TRACE_ANDROID_FS_TEMPLATE_H */
index 28e71023601d1961a551d206fb3ffc48d282d475..8924cc2b4ca8c45d867d00bbb522fa3eb37e74cd 100644 (file)
@@ -120,13 +120,6 @@ DEFINE_EVENT(cpu, cpu_frequency,
        TP_ARGS(frequency, cpu_id)
 );
 
-DEFINE_EVENT(cpu, cpu_capacity,
-
-       TP_PROTO(unsigned int capacity, unsigned int cpu_id),
-
-       TP_ARGS(capacity, cpu_id)
-);
-
 TRACE_EVENT(cpu_frequency_limits,
 
        TP_PROTO(unsigned int max_freq, unsigned int min_freq,
@@ -152,6 +145,13 @@ TRACE_EVENT(cpu_frequency_limits,
                  (unsigned long)__entry->cpu_id)
 );
 
+DEFINE_EVENT(cpu, cpu_capacity,
+
+       TP_PROTO(unsigned int capacity, unsigned int cpu_id),
+
+       TP_ARGS(capacity, cpu_id)
+);
+
 TRACE_EVENT(device_pm_callback_start,
 
        TP_PROTO(struct device *dev, const char *pm_ops, int event),
index 9bb0a264ad7d26667e1982d691a157ac1f923eaf..dffaffab4bc88696b8c8d0cbb98f518341648fd7 100644 (file)
@@ -636,6 +636,8 @@ TRACE_EVENT(sched_contrib_scale_f,
                  __entry->cpu_scale_factor)
 );
 
+#ifdef CONFIG_SMP
+
 /*
  * Tracepoint for accounting sched averages for tasks.
  */
@@ -729,14 +731,14 @@ TRACE_EVENT(sched_tune_config,
  */
 TRACE_EVENT(sched_boost_cpu,
 
-       TP_PROTO(int cpu, unsigned long util, unsigned long margin),
+       TP_PROTO(int cpu, unsigned long util, long margin),
 
        TP_ARGS(cpu, util, margin),
 
        TP_STRUCT__entry(
                __field( int,           cpu                     )
                __field( unsigned long, util                    )
-               __field( unsigned long, margin                  )
+               __field(long,           margin                  )
        ),
 
        TP_fast_assign(
@@ -745,7 +747,7 @@ TRACE_EVENT(sched_boost_cpu,
                __entry->margin = margin;
        ),
 
-       TP_printk("cpu=%d util=%lu margin=%lu",
+       TP_printk("cpu=%d util=%lu margin=%ld",
                  __entry->cpu,
                  __entry->util,
                  __entry->margin)
@@ -757,7 +759,7 @@ TRACE_EVENT(sched_boost_cpu,
 TRACE_EVENT(sched_tune_tasks_update,
 
        TP_PROTO(struct task_struct *tsk, int cpu, int tasks, int idx,
-               unsigned int boost, unsigned int max_boost),
+               int boost, int max_boost),
 
        TP_ARGS(tsk, cpu, tasks, idx, boost, max_boost),
 
@@ -767,8 +769,8 @@ TRACE_EVENT(sched_tune_tasks_update,
                __field( int,           cpu             )
                __field( int,           tasks           )
                __field( int,           idx             )
-               __field( unsigned int,  boost           )
-               __field( unsigned int,  max_boost       )
+               __field( int,           boost           )
+               __field( int,           max_boost       )
        ),
 
        TP_fast_assign(
@@ -782,7 +784,7 @@ TRACE_EVENT(sched_tune_tasks_update,
        ),
 
        TP_printk("pid=%d comm=%s "
-                       "cpu=%d tasks=%d idx=%d boost=%u max_boost=%u",
+                       "cpu=%d tasks=%d idx=%d boost=%d max_boost=%d",
                __entry->pid, __entry->comm,
                __entry->cpu, __entry->tasks, __entry->idx,
                __entry->boost, __entry->max_boost)
@@ -813,6 +815,300 @@ TRACE_EVENT(sched_tune_boostgroup_update,
                __entry->cpu, __entry->variation, __entry->max_boost)
 );
 
+/*
+ * Tracepoint for accounting task boosted utilization
+ */
+TRACE_EVENT(sched_boost_task,
+
+       TP_PROTO(struct task_struct *tsk, unsigned long util, long margin),
+
+       TP_ARGS(tsk, util, margin),
+
+       TP_STRUCT__entry(
+               __array( char,  comm,   TASK_COMM_LEN           )
+               __field( pid_t,         pid                     )
+               __field( unsigned long, util                    )
+               __field( long,          margin                  )
+
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
+               __entry->pid    = tsk->pid;
+               __entry->util   = util;
+               __entry->margin = margin;
+       ),
+
+       TP_printk("comm=%s pid=%d util=%lu margin=%ld",
+                 __entry->comm, __entry->pid,
+                 __entry->util,
+                 __entry->margin)
+);
+
+/*
+ * Tracepoint for accounting sched group energy
+ */
+TRACE_EVENT(sched_energy_diff,
+
+       TP_PROTO(struct task_struct *tsk, int scpu, int dcpu, int udelta,
+               int nrgb, int nrga, int nrgd, int capb, int capa, int capd,
+               int nrgn, int nrgp),
+
+       TP_ARGS(tsk, scpu, dcpu, udelta,
+               nrgb, nrga, nrgd, capb, capa, capd,
+               nrgn, nrgp),
+
+       TP_STRUCT__entry(
+               __array( char,  comm,   TASK_COMM_LEN   )
+               __field( pid_t, pid     )
+               __field( int,   scpu    )
+               __field( int,   dcpu    )
+               __field( int,   udelta  )
+               __field( int,   nrgb    )
+               __field( int,   nrga    )
+               __field( int,   nrgd    )
+               __field( int,   capb    )
+               __field( int,   capa    )
+               __field( int,   capd    )
+               __field( int,   nrgn    )
+               __field( int,   nrgp    )
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
+               __entry->pid            = tsk->pid;
+               __entry->scpu           = scpu;
+               __entry->dcpu           = dcpu;
+               __entry->udelta         = udelta;
+               __entry->nrgb           = nrgb;
+               __entry->nrga           = nrga;
+               __entry->nrgd           = nrgd;
+               __entry->capb           = capb;
+               __entry->capa           = capa;
+               __entry->capd           = capd;
+               __entry->nrgn           = nrgn;
+               __entry->nrgp           = nrgp;
+       ),
+
+       TP_printk("pid=%d comm=%s "
+                       "src_cpu=%d dst_cpu=%d usage_delta=%d "
+                       "nrg_before=%d nrg_after=%d nrg_diff=%d "
+                       "cap_before=%d cap_after=%d cap_delta=%d "
+                       "nrg_delta=%d nrg_payoff=%d",
+               __entry->pid, __entry->comm,
+               __entry->scpu, __entry->dcpu, __entry->udelta,
+               __entry->nrgb, __entry->nrga, __entry->nrgd,
+               __entry->capb, __entry->capa, __entry->capd,
+               __entry->nrgn, __entry->nrgp)
+);
+
+/*
+ * Tracepoint for schedtune_tasks_update
+ */
+TRACE_EVENT(sched_tune_filter,
+
+       TP_PROTO(int nrg_delta, int cap_delta,
+                int nrg_gain,  int cap_gain,
+                int payoff, int region),
+
+       TP_ARGS(nrg_delta, cap_delta, nrg_gain, cap_gain, payoff, region),
+
+       TP_STRUCT__entry(
+               __field( int,   nrg_delta       )
+               __field( int,   cap_delta       )
+               __field( int,   nrg_gain        )
+               __field( int,   cap_gain        )
+               __field( int,   payoff          )
+               __field( int,   region          )
+       ),
+
+       TP_fast_assign(
+               __entry->nrg_delta      = nrg_delta;
+               __entry->cap_delta      = cap_delta;
+               __entry->nrg_gain       = nrg_gain;
+               __entry->cap_gain       = cap_gain;
+               __entry->payoff         = payoff;
+               __entry->region         = region;
+       ),
+
+       TP_printk("nrg_delta=%d cap_delta=%d nrg_gain=%d cap_gain=%d payoff=%d region=%d",
+               __entry->nrg_delta, __entry->cap_delta,
+               __entry->nrg_gain, __entry->cap_gain,
+               __entry->payoff, __entry->region)
+);
+
+/*
+ * Tracepoint for system overutilized flag
+ */
+TRACE_EVENT(sched_overutilized,
+
+       TP_PROTO(bool overutilized),
+
+       TP_ARGS(overutilized),
+
+       TP_STRUCT__entry(
+               __field( bool,  overutilized    )
+       ),
+
+       TP_fast_assign(
+               __entry->overutilized   = overutilized;
+       ),
+
+       TP_printk("overutilized=%d",
+               __entry->overutilized ? 1 : 0)
+);
+#ifdef CONFIG_SCHED_WALT
+struct rq;
+
+TRACE_EVENT(walt_update_task_ravg,
+
+       TP_PROTO(struct task_struct *p, struct rq *rq, int evt,
+                                               u64 wallclock, u64 irqtime),
+
+       TP_ARGS(p, rq, evt, wallclock, irqtime),
+
+       TP_STRUCT__entry(
+               __array(        char,   comm,   TASK_COMM_LEN   )
+               __field(        pid_t,  pid                     )
+               __field(        pid_t,  cur_pid                 )
+               __field(unsigned int,   cur_freq                )
+               __field(        u64,    wallclock               )
+               __field(        u64,    mark_start              )
+               __field(        u64,    delta_m                 )
+               __field(        u64,    win_start               )
+               __field(        u64,    delta                   )
+               __field(        u64,    irqtime                 )
+               __field(        int,    evt                     )
+               __field(unsigned int,   demand                  )
+               __field(unsigned int,   sum                     )
+               __field(         int,   cpu                     )
+               __field(        u64,    cs                      )
+               __field(        u64,    ps                      )
+               __field(        u32,    curr_window             )
+               __field(        u32,    prev_window             )
+               __field(        u64,    nt_cs                   )
+               __field(        u64,    nt_ps                   )
+               __field(        u32,    active_windows          )
+       ),
+
+       TP_fast_assign(
+               __entry->wallclock      = wallclock;
+               __entry->win_start      = rq->window_start;
+               __entry->delta          = (wallclock - rq->window_start);
+               __entry->evt            = evt;
+               __entry->cpu            = rq->cpu;
+               __entry->cur_pid        = rq->curr->pid;
+               __entry->cur_freq       = rq->cur_freq;
+               memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+               __entry->pid            = p->pid;
+               __entry->mark_start     = p->ravg.mark_start;
+               __entry->delta_m        = (wallclock - p->ravg.mark_start);
+               __entry->demand         = p->ravg.demand;
+               __entry->sum            = p->ravg.sum;
+               __entry->irqtime        = irqtime;
+               __entry->cs             = rq->curr_runnable_sum;
+               __entry->ps             = rq->prev_runnable_sum;
+               __entry->curr_window    = p->ravg.curr_window;
+               __entry->prev_window    = p->ravg.prev_window;
+               __entry->nt_cs          = rq->nt_curr_runnable_sum;
+               __entry->nt_ps          = rq->nt_prev_runnable_sum;
+               __entry->active_windows = p->ravg.active_windows;
+       ),
+
+       TP_printk("wc %llu ws %llu delta %llu event %d cpu %d cur_freq %u cur_pid %d task %d (%s) ms %llu delta %llu demand %u sum %u irqtime %llu"
+               " cs %llu ps %llu cur_window %u prev_window %u nt_cs %llu nt_ps %llu active_wins %u"
+               , __entry->wallclock, __entry->win_start, __entry->delta,
+               __entry->evt, __entry->cpu,
+               __entry->cur_freq, __entry->cur_pid,
+               __entry->pid, __entry->comm, __entry->mark_start,
+               __entry->delta_m, __entry->demand,
+               __entry->sum, __entry->irqtime,
+               __entry->cs, __entry->ps,
+               __entry->curr_window, __entry->prev_window,
+                 __entry->nt_cs, __entry->nt_ps,
+                 __entry->active_windows
+               )
+);
+
+TRACE_EVENT(walt_update_history,
+
+       TP_PROTO(struct rq *rq, struct task_struct *p, u32 runtime, int samples,
+                       int evt),
+
+       TP_ARGS(rq, p, runtime, samples, evt),
+
+       TP_STRUCT__entry(
+               __array(        char,   comm,   TASK_COMM_LEN   )
+               __field(        pid_t,  pid                     )
+               __field(unsigned int,   runtime                 )
+               __field(         int,   samples                 )
+               __field(         int,   evt                     )
+               __field(         u64,   demand                  )
+               __field(unsigned int,   walt_avg                )
+               __field(unsigned int,   pelt_avg                )
+               __array(         u32,   hist, RAVG_HIST_SIZE_MAX)
+               __field(         int,   cpu                     )
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+               __entry->pid            = p->pid;
+               __entry->runtime        = runtime;
+               __entry->samples        = samples;
+               __entry->evt            = evt;
+               __entry->demand         = p->ravg.demand;
+               __entry->walt_avg       = (__entry->demand << 10);
+               do_div(__entry->walt_avg, walt_ravg_window);
+               __entry->pelt_avg       = p->se.avg.util_avg;
+               memcpy(__entry->hist, p->ravg.sum_history,
+                                       RAVG_HIST_SIZE_MAX * sizeof(u32));
+               __entry->cpu            = rq->cpu;
+       ),
+
+       TP_printk("%d (%s): runtime %u samples %d event %d demand %llu"
+               " walt %u pelt %u (hist: %u %u %u %u %u) cpu %d",
+               __entry->pid, __entry->comm,
+               __entry->runtime, __entry->samples, __entry->evt,
+               __entry->demand,
+               __entry->walt_avg,
+               __entry->pelt_avg,
+               __entry->hist[0], __entry->hist[1],
+               __entry->hist[2], __entry->hist[3],
+               __entry->hist[4], __entry->cpu)
+);
+
+TRACE_EVENT(walt_migration_update_sum,
+
+       TP_PROTO(struct rq *rq, struct task_struct *p),
+
+       TP_ARGS(rq, p),
+
+       TP_STRUCT__entry(
+               __field(int,            cpu                     )
+               __field(int,            pid                     )
+               __field(        u64,    cs                      )
+               __field(        u64,    ps                      )
+               __field(        s64,    nt_cs                   )
+               __field(        s64,    nt_ps                   )
+       ),
+
+       TP_fast_assign(
+               __entry->cpu            = cpu_of(rq);
+               __entry->cs             = rq->curr_runnable_sum;
+               __entry->ps             = rq->prev_runnable_sum;
+               __entry->nt_cs          = (s64)rq->nt_curr_runnable_sum;
+               __entry->nt_ps          = (s64)rq->nt_prev_runnable_sum;
+               __entry->pid            = p->pid;
+       ),
+
+       TP_printk("cpu %d: cs %llu ps %llu nt_cs %lld nt_ps %lld pid %d",
+                 __entry->cpu, __entry->cs, __entry->ps,
+                 __entry->nt_cs, __entry->nt_ps, __entry->pid)
+);
+#endif /* CONFIG_SCHED_WALT */
+
+#endif /* CONFIG_SMP */
+
 #endif /* _TRACE_SCHED_H */
 
 /* This part must be outside protection */
index 003dca933803901da37efb168833b67a3a1f06ce..5664ca07c9c7d8b9634250338cfcf72094e827d7 100644 (file)
@@ -529,20 +529,27 @@ TRACE_EVENT(svc_xprt_do_enqueue,
 
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
-               __field_struct(struct sockaddr_storage, ss)
                __field(int, pid)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, xprt != NULL ?
+                       xprt->xpt_remotelen : 0)
        ),
 
        TP_fast_assign(
                __entry->xprt = xprt;
-               xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
                __entry->pid = rqst? rqst->rq_task->pid : 0;
-               __entry->flags = xprt ? xprt->xpt_flags : 0;
+               if (xprt) {
+                       memcpy(__get_dynamic_array(addr),
+                               &xprt->xpt_remote,
+                               xprt->xpt_remotelen);
+                       __entry->flags = xprt->xpt_flags;
+               } else
+                       __entry->flags = 0;
        ),
 
        TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt,
-               (struct sockaddr *)&__entry->ss,
+               __get_dynamic_array_len(addr) != 0 ?
+                       (struct sockaddr *)__get_dynamic_array(addr) : NULL,
                __entry->pid, show_svc_xprt_flags(__entry->flags))
 );
 
@@ -553,18 +560,25 @@ TRACE_EVENT(svc_xprt_dequeue,
 
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
-               __field_struct(struct sockaddr_storage, ss)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, xprt != NULL ?
+                       xprt->xpt_remotelen : 0)
        ),
 
        TP_fast_assign(
-               __entry->xprt = xprt,
-               xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
-               __entry->flags = xprt ? xprt->xpt_flags : 0;
+               __entry->xprt = xprt;
+               if (xprt) {
+                       memcpy(__get_dynamic_array(addr),
+                                       &xprt->xpt_remote,
+                                       xprt->xpt_remotelen);
+                       __entry->flags = xprt->xpt_flags;
+               } else
+                       __entry->flags = 0;
        ),
 
        TP_printk("xprt=0x%p addr=%pIScp flags=%s", __entry->xprt,
-               (struct sockaddr *)&__entry->ss,
+               __get_dynamic_array_len(addr) != 0 ?
+                       (struct sockaddr *)__get_dynamic_array(addr) : NULL,
                show_svc_xprt_flags(__entry->flags))
 );
 
@@ -592,19 +606,26 @@ TRACE_EVENT(svc_handle_xprt,
        TP_STRUCT__entry(
                __field(struct svc_xprt *, xprt)
                __field(int, len)
-               __field_struct(struct sockaddr_storage, ss)
                __field(unsigned long, flags)
+               __dynamic_array(unsigned char, addr, xprt != NULL ?
+                       xprt->xpt_remotelen : 0)
        ),
 
        TP_fast_assign(
                __entry->xprt = xprt;
-               xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss));
                __entry->len = len;
-               __entry->flags = xprt ? xprt->xpt_flags : 0;
+               if (xprt) {
+                       memcpy(__get_dynamic_array(addr),
+                                       &xprt->xpt_remote,
+                                       xprt->xpt_remotelen);
+                       __entry->flags = xprt->xpt_flags;
+               } else
+                       __entry->flags = 0;
        ),
 
        TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt,
-               (struct sockaddr *)&__entry->ss,
+               __get_dynamic_array_len(addr) != 0 ?
+                       (struct sockaddr *)__get_dynamic_array(addr) : NULL,
                __entry->len, show_svc_xprt_flags(__entry->flags))
 );
 #endif /* _TRACE_SUNRPC_H */
index e4c0a35d6417cd6a4ca0f44bdfc4900a2e2a8e11..e347b24ef9fb645cd3d74b4a0e09ca3296c7b58b 100644 (file)
@@ -313,6 +313,7 @@ enum hv_kvp_exchg_pool {
 #define HV_INVALIDARG                  0x80070057
 #define HV_GUID_NOTFOUND               0x80041002
 #define HV_ERROR_ALREADY_EXISTS                0x80070050
+#define HV_ERROR_DISK_FULL             0x80070070
 
 #define ADDR_FAMILY_NONE       0x00
 #define ADDR_FAMILY_IPV4       0x01
index 68a1f71fde9f7bcc90c21f586b57f1eab61de941..c7f189bd597997214f9c5f027562abac8ab154b1 100644 (file)
@@ -72,6 +72,8 @@ enum {
        INET_DIAG_BC_AUTO,
        INET_DIAG_BC_S_COND,
        INET_DIAG_BC_D_COND,
+       INET_DIAG_BC_DEV_COND,   /* u32 ifindex */
+       INET_DIAG_BC_MARK_COND,
 };
 
 struct inet_diag_hostcond {
@@ -81,6 +83,11 @@ struct inet_diag_hostcond {
        __be32  addr[0];
 };
 
+struct inet_diag_markcond {
+       __u32 mark;
+       __u32 mask;
+};
+
 /* Base info structure. It contains socket identity (addrs/ports/cookie)
  * and, alas, the information shown by netstat. */
 struct inet_diag_msg {
@@ -113,9 +120,13 @@ enum {
        INET_DIAG_DCTCPINFO,
        INET_DIAG_PROTOCOL,  /* response attribute only */
        INET_DIAG_SKV6ONLY,
+       INET_DIAG_LOCALS,
+       INET_DIAG_PEERS,
+       INET_DIAG_PAD,
+       INET_DIAG_MARK,
 };
 
-#define INET_DIAG_MAX INET_DIAG_SKV6ONLY
+#define INET_DIAG_MAX INET_DIAG_MARK
 
 /* INET_DIAG_MEM */
 
index 355eea225dd9b6fc7e79ea90a9a4289bc3f8990d..3eb02a1d6d8cca26f00e5d5c6399436100b172b8 100644 (file)
@@ -306,12 +306,12 @@ enum rtattr_type_t {
        RTA_TABLE,
        RTA_MARK,
        RTA_MFC_STATS,
+       RTA_UID,
        RTA_VIA,
        RTA_NEWDST,
        RTA_PREF,
        RTA_ENCAP_TYPE,
        RTA_ENCAP,
-       RTA_UID,
        __RTA_MAX
 };
 
index 4338eb7b09b3ad705f766fa1c3e1f8a100ae049e..779a62aafafe6a2d19b3c25bd9ddbef7617b0f7f 100644 (file)
@@ -954,6 +954,7 @@ enum usb_device_speed {
        USB_SPEED_HIGH,                         /* usb 2.0 */
        USB_SPEED_WIRELESS,                     /* wireless (usb 2.5) */
        USB_SPEED_SUPER,                        /* usb 3.0 */
+       USB_SPEED_SUPER_PLUS,                   /* usb 3.1 */
 };
 
 
index 43b0041288157343e2ddcf164968f680dd256206..de14cbc2a7065c14a14566f632cc2dbce6517670 100644 (file)
@@ -623,6 +623,9 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_JPGL      v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
 #define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
 #define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */
+#define V4L2_PIX_FMT_Y8I      v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
+#define V4L2_PIX_FMT_Y12I     v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
+#define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
 
 /* SDR formats - used only for Software Defined Radio devices */
 #define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
index 831351b2e66022ee66f56bc2b8fe9c2f9fd7347f..2302f3ce5f860fcc94ae2f86fd1fcaea41a6a876 100644 (file)
@@ -30,6 +30,16 @@ struct dk_cxlflash_hdr {
        __u64 return_flags;             /* Returned flags */
 };
 
+/*
+ * Return flag definitions available to all ioctls
+ *
+ * Similar to the input flags, these are grown from the bottom-up with the
+ * intention that ioctl-specific return flag definitions would grow from the
+ * top-down, allowing the two sets to co-exist. While not required/enforced
+ * at this time, this provides future flexibility.
+ */
+#define DK_CXLFLASH_ALL_PORTS_ACTIVE   0x0000000000000001ULL
+
 /*
  * Notes:
  * -----
index 5d9097e2b805fa8b97c5a91031515aaae3532e99..acb6645ffda54b44c3e8350d9b67319a98929a76 100644 (file)
@@ -392,6 +392,15 @@ config IRQ_TIME_ACCOUNTING
 
 endchoice
 
+config SCHED_WALT
+        bool "Support window based load tracking"
+        depends on SMP
+        help
+        This feature will allow the scheduler to maintain a tunable window
+       based set of metrics for tasks and runqueues. These metrics can be
+       used to guide task placement as well as task frequency requirements
+       for cpufreq governors.
+
 config BSD_PROCESS_ACCT
        bool "BSD Process Accounting"
        depends on MULTIUSER
@@ -1256,6 +1265,7 @@ config SCHED_AUTOGROUP
 
 config SCHED_TUNE
        bool "Boosting for CFS tasks (EXPERIMENTAL)"
+       depends on SMP
        help
          This option enables the system-wide support for task boosting.
          When this support is enabled a new sysctl interface is exposed to
@@ -1280,6 +1290,16 @@ config SCHED_TUNE
 
          If unsure, say N.
 
+config DEFAULT_USE_ENERGY_AWARE
+       bool "Default to enabling the Energy Aware Scheduler feature"
+       default n
+       help
+         This option defaults the ENERGY_AWARE scheduling feature to true,
+         as without SCHED_DEBUG set this feature can't be enabled or disabled
+         via sysctl.
+
+         Say N if unsure.
+
 config SYSFS_DEPRECATED
        bool "Enable deprecated sysfs features to support old userspace tools"
        depends on SYSFS
@@ -1762,6 +1782,7 @@ choice
 
 config SLAB
        bool "SLAB"
+       select HAVE_HARDENED_USERCOPY_ALLOCATOR
        help
          The regular slab allocator that is established and known to work
          well in all environments. It organizes cache hot objects in
@@ -1769,6 +1790,7 @@ config SLAB
 
 config SLUB
        bool "SLUB (Unqueued Allocator)"
+       select HAVE_HARDENED_USERCOPY_ALLOCATOR
        help
           SLUB is a slab allocator that minimizes cache line usage
           instead of managing queues of cached objects (SLAB approach).
index 692b91f1c1d4fb04e118e7fd170bf461f94aa72d..243f61de2cbabbff8943c70d2688f54d4cd18c8a 100644 (file)
@@ -15,6 +15,7 @@ mounts-y                      := do_mounts.o
 mounts-$(CONFIG_BLK_DEV_RAM)   += do_mounts_rd.o
 mounts-$(CONFIG_BLK_DEV_INITRD)        += do_mounts_initrd.o
 mounts-$(CONFIG_BLK_DEV_MD)    += do_mounts_md.o
+mounts-$(CONFIG_BLK_DEV_DM)    += do_mounts_dm.o
 
 # dependencies on generated files need to be listed explicitly
 $(obj)/version.o: include/generated/compile.h
index dea5de95c2dd23771f44e58ada2d9b1dbfa1c5df..1902a1c808319f6e84aa13944ba44ede13a9b02e 100644 (file)
@@ -566,6 +566,7 @@ void __init prepare_namespace(void)
        wait_for_device_probe();
 
        md_run_setup();
+       dm_run_setup();
 
        if (saved_root_name[0]) {
                root_device_name = saved_root_name;
index f5b978a9bb92892a5e876ae3ce1338ad8a896e04..09d22862e8c38d49339a1ea09f01288eed5b60b3 100644 (file)
@@ -74,3 +74,13 @@ void md_run_setup(void);
 static inline void md_run_setup(void) {}
 
 #endif
+
+#ifdef CONFIG_BLK_DEV_DM
+
+void dm_run_setup(void);
+
+#else
+
+static inline void dm_run_setup(void) {}
+
+#endif
diff --git a/init/do_mounts_dm.c b/init/do_mounts_dm.c
new file mode 100644 (file)
index 0000000..ecda58d
--- /dev/null
@@ -0,0 +1,426 @@
+/* do_mounts_dm.c
+ * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org>
+ *                    All Rights Reserved.
+ * Based on do_mounts_md.c
+ *
+ * This file is released under the GPL.
+ */
+#include <linux/device-mapper.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include "do_mounts.h"
+#include "../drivers/md/dm.h"
+
+#define DM_MAX_NAME 32
+#define DM_MAX_UUID 129
+#define DM_NO_UUID "none"
+
+#define DM_MSG_PREFIX "init"
+
+/* Separators used for parsing the dm= argument. */
+#define DM_FIELD_SEP ' '
+#define DM_LINE_SEP ','
+
+/*
+ * When the device-mapper and any targets are compiled into the kernel
+ * (not a module), one target may be created and used as the root device at
+ * boot time with the parameters given with the boot line dm=...
+ * The code for that is here.
+ */
+
+struct dm_setup_target {
+       sector_t begin;
+       sector_t length;
+       char *type;
+       char *params;
+       /* simple singly linked list */
+       struct dm_setup_target *next;
+};
+
+static struct {
+       int minor;
+       int ro;
+       char name[DM_MAX_NAME];
+       char uuid[DM_MAX_UUID];
+       char *targets;
+       struct dm_setup_target *target;
+       int target_count;
+} dm_setup_args __initdata;
+
+static __initdata int dm_early_setup;
+
+static size_t __init get_dm_option(char *str, char **next, char sep)
+{
+       size_t len = 0;
+       char *endp = NULL;
+
+       if (!str)
+               return 0;
+
+       endp = strchr(str, sep);
+       if (!endp) {  /* act like strchrnul */
+               len = strlen(str);
+               endp = str + len;
+       } else {
+               len = endp - str;
+       }
+
+       if (endp == str)
+               return 0;
+
+       if (!next)
+               return len;
+
+       if (*endp == 0) {
+               /* Don't advance past the nul. */
+               *next = endp;
+       } else {
+               *next = endp + 1;
+       }
+       return len;
+}
+
+static int __init dm_setup_args_init(void)
+{
+       dm_setup_args.minor = 0;
+       dm_setup_args.ro = 0;
+       dm_setup_args.target = NULL;
+       dm_setup_args.target_count = 0;
+       return 0;
+}
+
+static int __init dm_setup_cleanup(void)
+{
+       struct dm_setup_target *target = dm_setup_args.target;
+       struct dm_setup_target *old_target = NULL;
+       while (target) {
+               kfree(target->type);
+               kfree(target->params);
+               old_target = target;
+               target = target->next;
+               kfree(old_target);
+               dm_setup_args.target_count--;
+       }
+       BUG_ON(dm_setup_args.target_count);
+       return 0;
+}
+
+static char * __init dm_setup_parse_device_args(char *str)
+{
+       char *next = NULL;
+       size_t len = 0;
+
+       /* Grab the logical name of the device to be exported to udev */
+       len = get_dm_option(str, &next, DM_FIELD_SEP);
+       if (!len) {
+               DMERR("failed to parse device name");
+               goto parse_fail;
+       }
+       len = min(len + 1, sizeof(dm_setup_args.name));
+       strlcpy(dm_setup_args.name, str, len);  /* includes nul */
+       str = skip_spaces(next);
+
+       /* Grab the UUID value or "none" */
+       len = get_dm_option(str, &next, DM_FIELD_SEP);
+       if (!len) {
+               DMERR("failed to parse device uuid");
+               goto parse_fail;
+       }
+       len = min(len + 1, sizeof(dm_setup_args.uuid));
+       strlcpy(dm_setup_args.uuid, str, len);
+       str = skip_spaces(next);
+
+       /* Determine if the table/device will be read only or read-write */
+       if (!strncmp("ro,", str, 3)) {
+               dm_setup_args.ro = 1;
+       } else if (!strncmp("rw,", str, 3)) {
+               dm_setup_args.ro = 0;
+       } else {
+               DMERR("failed to parse table mode");
+               goto parse_fail;
+       }
+       str = skip_spaces(str + 3);
+
+       return str;
+
+parse_fail:
+       return NULL;
+}
+
+static void __init dm_substitute_devices(char *str, size_t str_len)
+{
+       char *candidate = str;
+       char *candidate_end = str;
+       char old_char;
+       size_t len = 0;
+       dev_t dev;
+
+       if (str_len < 3)
+               return;
+
+       while (str && *str) {
+               candidate = strchr(str, '/');
+               if (!candidate)
+                       break;
+
+               /* Avoid embedded slashes */
+               if (candidate != str && *(candidate - 1) != DM_FIELD_SEP) {
+                       str = strchr(candidate, DM_FIELD_SEP);
+                       continue;
+               }
+
+               len = get_dm_option(candidate, &candidate_end, DM_FIELD_SEP);
+               str = skip_spaces(candidate_end);
+               if (len < 3 || len > 37)  /* name_to_dev_t max; maj:mix min */
+                       continue;
+
+               /* Temporarily terminate with a nul */
+               if (*candidate_end)
+                       candidate_end--;
+               old_char = *candidate_end;
+               *candidate_end = '\0';
+
+               DMDEBUG("converting candidate device '%s' to dev_t", candidate);
+               /* Use the boot-time specific device naming */
+               dev = name_to_dev_t(candidate);
+               *candidate_end = old_char;
+
+               DMDEBUG(" -> %u", dev);
+               /* No suitable replacement found */
+               if (!dev)
+                       continue;
+
+               /* Rewrite the /dev/path as a major:minor */
+               len = snprintf(candidate, len, "%u:%u", MAJOR(dev), MINOR(dev));
+               if (!len) {
+                       DMERR("error substituting device major/minor.");
+                       break;
+               }
+               candidate += len;
+               /* Pad out with spaces (fixing our nul) */
+               while (candidate < candidate_end)
+                       *(candidate++) = DM_FIELD_SEP;
+       }
+}
+
+static int __init dm_setup_parse_targets(char *str)
+{
+       char *next = NULL;
+       size_t len = 0;
+       struct dm_setup_target **target = NULL;
+
+       /* Targets are defined as per the table format but with a
+        * comma as a newline separator. */
+       target = &dm_setup_args.target;
+       while (str && *str) {
+               *target = kzalloc(sizeof(struct dm_setup_target), GFP_KERNEL);
+               if (!*target) {
+                       DMERR("failed to allocate memory for target %d",
+                             dm_setup_args.target_count);
+                       goto parse_fail;
+               }
+               dm_setup_args.target_count++;
+
+               (*target)->begin = simple_strtoull(str, &next, 10);
+               if (!next || *next != DM_FIELD_SEP) {
+                       DMERR("failed to parse starting sector for target %d",
+                             dm_setup_args.target_count - 1);
+                       goto parse_fail;
+               }
+               str = skip_spaces(next + 1);
+
+               (*target)->length = simple_strtoull(str, &next, 10);
+               if (!next || *next != DM_FIELD_SEP) {
+                       DMERR("failed to parse length for target %d",
+                             dm_setup_args.target_count - 1);
+                       goto parse_fail;
+               }
+               str = skip_spaces(next + 1);
+
+               len = get_dm_option(str, &next, DM_FIELD_SEP);
+               if (!len ||
+                   !((*target)->type = kstrndup(str, len, GFP_KERNEL))) {
+                       DMERR("failed to parse type for target %d",
+                             dm_setup_args.target_count - 1);
+                       goto parse_fail;
+               }
+               str = skip_spaces(next);
+
+               len = get_dm_option(str, &next, DM_LINE_SEP);
+               if (!len ||
+                   !((*target)->params = kstrndup(str, len, GFP_KERNEL))) {
+                       DMERR("failed to parse params for target %d",
+                             dm_setup_args.target_count - 1);
+                       goto parse_fail;
+               }
+               str = skip_spaces(next);
+
+               /* Before moving on, walk through the copied target and
+                * attempt to replace all /dev/xxx with the major:minor number.
+                * It may not be possible to resolve them traditionally at
+                * boot-time. */
+               dm_substitute_devices((*target)->params, len);
+
+               target = &((*target)->next);
+       }
+       DMDEBUG("parsed %d targets", dm_setup_args.target_count);
+
+       return 0;
+
+parse_fail:
+       return 1;
+}
+
+/*
+ * Parse the command-line parameters given our kernel, but do not
+ * actually try to invoke the DM device now; that is handled by
+ * dm_setup_drive after the low-level disk drivers have initialised.
+ * dm format is as follows:
+ *  dm="name uuid fmode,[table line 1],[table line 2],..."
+ * May be used with root=/dev/dm-0 as it always uses the first dm minor.
+ */
+
+static int __init dm_setup(char *str)
+{
+       dm_setup_args_init();
+
+       str = dm_setup_parse_device_args(str);
+       if (!str) {
+               DMDEBUG("str is NULL");
+               goto parse_fail;
+       }
+
+       /* Target parsing is delayed until we have dynamic memory */
+       dm_setup_args.targets = str;
+
+       printk(KERN_INFO "dm: will configure '%s' on dm-%d\n",
+              dm_setup_args.name, dm_setup_args.minor);
+
+       dm_early_setup = 1;
+       return 1;
+
+parse_fail:
+       printk(KERN_WARNING "dm: Invalid arguments supplied to dm=.\n");
+       return 0;
+}
+
+
+static void __init dm_setup_drive(void)
+{
+       struct mapped_device *md = NULL;
+       struct dm_table *table = NULL;
+       struct dm_setup_target *target;
+       char *uuid = dm_setup_args.uuid;
+       fmode_t fmode = FMODE_READ;
+
+       /* Finish parsing the targets. */
+       if (dm_setup_parse_targets(dm_setup_args.targets))
+               goto parse_fail;
+
+       if (dm_create(dm_setup_args.minor, &md)) {
+               DMDEBUG("failed to create the device");
+               goto dm_create_fail;
+       }
+       DMDEBUG("created device '%s'", dm_device_name(md));
+
+       /* In addition to flagging the table below, the disk must be
+        * set explicitly ro/rw. */
+       set_disk_ro(dm_disk(md), dm_setup_args.ro);
+
+       if (!dm_setup_args.ro)
+               fmode |= FMODE_WRITE;
+       if (dm_table_create(&table, fmode, dm_setup_args.target_count, md)) {
+               DMDEBUG("failed to create the table");
+               goto dm_table_create_fail;
+       }
+
+       dm_lock_md_type(md);
+       target = dm_setup_args.target;
+       while (target) {
+               DMINFO("adding target '%llu %llu %s %s'",
+                      (unsigned long long) target->begin,
+                      (unsigned long long) target->length, target->type,
+                      target->params);
+               if (dm_table_add_target(table, target->type, target->begin,
+                                       target->length, target->params)) {
+                       DMDEBUG("failed to add the target to the table");
+                       goto add_target_fail;
+               }
+               target = target->next;
+       }
+
+       if (dm_table_complete(table)) {
+               DMDEBUG("failed to complete the table");
+               goto table_complete_fail;
+       }
+
+       if (dm_get_md_type(md) == DM_TYPE_NONE) {
+               dm_set_md_type(md, dm_table_get_type(table));
+               if (dm_setup_md_queue(md)) {
+                       DMWARN("unable to set up device queue for new table.");
+                       goto setup_md_queue_fail;
+               }
+       } else if (dm_get_md_type(md) != dm_table_get_type(table)) {
+               DMWARN("can't change device type after initial table load.");
+               goto setup_md_queue_fail;
+        }
+
+       /* Suspend the device so that we can bind it to the table. */
+       if (dm_suspend(md, 0)) {
+               DMDEBUG("failed to suspend the device pre-bind");
+               goto suspend_fail;
+       }
+
+       /* Bind the table to the device. This is the only way to associate
+        * md->map with the table and set the disk capacity directly. */
+       if (dm_swap_table(md, table)) {  /* should return NULL. */
+               DMDEBUG("failed to bind the device to the table");
+               goto table_bind_fail;
+       }
+
+       /* Finally, resume and the device should be ready. */
+       if (dm_resume(md)) {
+               DMDEBUG("failed to resume the device");
+               goto resume_fail;
+       }
+
+       /* Export the dm device via the ioctl interface */
+       if (!strcmp(DM_NO_UUID, dm_setup_args.uuid))
+               uuid = NULL;
+       if (dm_ioctl_export(md, dm_setup_args.name, uuid)) {
+               DMDEBUG("failed to export device with given name and uuid");
+               goto export_fail;
+       }
+       printk(KERN_INFO "dm: dm-%d is ready\n", dm_setup_args.minor);
+
+       dm_unlock_md_type(md);
+       dm_setup_cleanup();
+       return;
+
+export_fail:
+resume_fail:
+table_bind_fail:
+suspend_fail:
+setup_md_queue_fail:
+table_complete_fail:
+add_target_fail:
+       dm_unlock_md_type(md);
+dm_table_create_fail:
+       dm_put(md);
+dm_create_fail:
+       dm_setup_cleanup();
+parse_fail:
+       printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n",
+              dm_setup_args.minor, dm_setup_args.name);
+}
+
+__setup("dm=", dm_setup);
+
+void __init dm_run_setup(void)
+{
+       if (!dm_early_setup)
+               return;
+       printk(KERN_INFO "dm: attempting early device configuration.\n");
+       dm_setup_drive();
+}
index 1471db9a7e6112b3316ae887b50c6d8d1352f171..c6521c205cb403a81cc2bf4e6969b2a5d54620c3 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -680,7 +680,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                rcu_read_lock();
                ipc_lock_object(&msq->q_perm);
 
-               ipc_rcu_putref(msq, ipc_rcu_free);
+               ipc_rcu_putref(msq, msg_rcu_free);
                /* raced with RMID? */
                if (!ipc_valid_object(&msq->q_perm)) {
                        err = -EIDRM;
index b471e5a3863ddbca70f2bf4dee22f40df0345fbe..9862c3d1c26d294b1c281c38bec6bc59ec665c5c 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -155,14 +155,21 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
 
 /*
  * Locking:
+ * a) global sem_lock() for read/write
  *     sem_undo.id_next,
  *     sem_array.complex_count,
- *     sem_array.pending{_alter,_cont},
- *     sem_array.sem_undo: global sem_lock() for read/write
- *     sem_undo.proc_next: only "current" is allowed to read/write that field.
+ *     sem_array.complex_mode
+ *     sem_array.pending{_alter,_const},
+ *     sem_array.sem_undo
  *
+ * b) global or semaphore sem_lock() for read/write:
  *     sem_array.sem_base[i].pending_{const,alter}:
- *             global or semaphore sem_lock() for read/write
+ *     sem_array.complex_mode (for read)
+ *
+ * c) special:
+ *     sem_undo_list.list_proc:
+ *     * undo_list->lock for write
+ *     * rcu for read
  */
 
 #define sc_semmsl      sem_ctls[0]
@@ -263,24 +270,25 @@ static void sem_rcu_free(struct rcu_head *head)
 #define ipc_smp_acquire__after_spin_is_unlocked()      smp_rmb()
 
 /*
- * Wait until all currently ongoing simple ops have completed.
+ * Enter the mode suitable for non-simple operations:
  * Caller must own sem_perm.lock.
- * New simple ops cannot start, because simple ops first check
- * that sem_perm.lock is free.
- * that a) sem_perm.lock is free and b) complex_count is 0.
  */
-static void sem_wait_array(struct sem_array *sma)
+static void complexmode_enter(struct sem_array *sma)
 {
        int i;
        struct sem *sem;
 
-       if (sma->complex_count)  {
-               /* The thread that increased sma->complex_count waited on
-                * all sem->lock locks. Thus we don't need to wait again.
-                */
+       if (sma->complex_mode)  {
+               /* We are already in complex_mode. Nothing to do */
                return;
        }
 
+       /* We need a full barrier after seting complex_mode:
+        * The write to complex_mode must be visible
+        * before we read the first sem->lock spinlock state.
+        */
+       smp_store_mb(sma->complex_mode, true);
+
        for (i = 0; i < sma->sem_nsems; i++) {
                sem = sma->sem_base + i;
                spin_unlock_wait(&sem->lock);
@@ -288,6 +296,28 @@ static void sem_wait_array(struct sem_array *sma)
        ipc_smp_acquire__after_spin_is_unlocked();
 }
 
+/*
+ * Try to leave the mode that disallows simple operations:
+ * Caller must own sem_perm.lock.
+ */
+static void complexmode_tryleave(struct sem_array *sma)
+{
+       if (sma->complex_count)  {
+               /* Complex ops are sleeping.
+                * We must stay in complex mode
+                */
+               return;
+       }
+       /*
+        * Immediately after setting complex_mode to false,
+        * a simple op can start. Thus: all memory writes
+        * performed by the current operation must be visible
+        * before we set complex_mode to false.
+        */
+       smp_store_release(&sma->complex_mode, false);
+}
+
+#define SEM_GLOBAL_LOCK        (-1)
 /*
  * If the request contains only one semaphore operation, and there are
  * no complex transactions pending, lock only the semaphore involved.
@@ -304,56 +334,42 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                /* Complex operation - acquire a full lock */
                ipc_lock_object(&sma->sem_perm);
 
-               /* And wait until all simple ops that are processed
-                * right now have dropped their locks.
-                */
-               sem_wait_array(sma);
-               return -1;
+               /* Prevent parallel simple ops */
+               complexmode_enter(sma);
+               return SEM_GLOBAL_LOCK;
        }
 
        /*
         * Only one semaphore affected - try to optimize locking.
-        * The rules are:
-        * - optimized locking is possible if no complex operation
-        *   is either enqueued or processed right now.
-        * - The test for enqueued complex ops is simple:
-        *      sma->complex_count != 0
-        * - Testing for complex ops that are processed right now is
-        *   a bit more difficult. Complex ops acquire the full lock
-        *   and first wait that the running simple ops have completed.
-        *   (see above)
-        *   Thus: If we own a simple lock and the global lock is free
-        *      and complex_count is now 0, then it will stay 0 and
-        *      thus just locking sem->lock is sufficient.
+        * Optimized locking is possible if no complex operation
+        * is either enqueued or processed right now.
+        *
+        * Both facts are tracked by complex_mode.
         */
        sem = sma->sem_base + sops->sem_num;
 
-       if (sma->complex_count == 0) {
+       /*
+        * Initial check for complex_mode. Just an optimization,
+        * no locking, no memory barrier.
+        */
+       if (!sma->complex_mode) {
                /*
                 * It appears that no complex operation is around.
                 * Acquire the per-semaphore lock.
                 */
                spin_lock(&sem->lock);
 
-               /* Then check that the global lock is free */
-               if (!spin_is_locked(&sma->sem_perm.lock)) {
-                       /*
-                        * We need a memory barrier with acquire semantics,
-                        * otherwise we can race with another thread that does:
-                        *      complex_count++;
-                        *      spin_unlock(sem_perm.lock);
-                        */
-                       ipc_smp_acquire__after_spin_is_unlocked();
+               /*
+                * See 51d7d5205d33
+                * ("powerpc: Add smp_mb() to arch_spin_is_locked()"):
+                * A full barrier is required: the write of sem->lock
+                * must be visible before the read is executed
+                */
+               smp_mb();
 
-                       /*
-                        * Now repeat the test of complex_count:
-                        * It can't change anymore until we drop sem->lock.
-                        * Thus: if is now 0, then it will stay 0.
-                        */
-                       if (sma->complex_count == 0) {
-                               /* fast path successful! */
-                               return sops->sem_num;
-                       }
+               if (!smp_load_acquire(&sma->complex_mode)) {
+                       /* fast path successful! */
+                       return sops->sem_num;
                }
                spin_unlock(&sem->lock);
        }
@@ -373,15 +389,16 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                /* Not a false alarm, thus complete the sequence for a
                 * full lock.
                 */
-               sem_wait_array(sma);
-               return -1;
+               complexmode_enter(sma);
+               return SEM_GLOBAL_LOCK;
        }
 }
 
 static inline void sem_unlock(struct sem_array *sma, int locknum)
 {
-       if (locknum == -1) {
+       if (locknum == SEM_GLOBAL_LOCK) {
                unmerge_queues(sma);
+               complexmode_tryleave(sma);
                ipc_unlock_object(&sma->sem_perm);
        } else {
                struct sem *sem = sma->sem_base + locknum;
@@ -442,7 +459,7 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
        sem_lock(sma, NULL, -1);
-       ipc_rcu_putref(sma, ipc_rcu_free);
+       ipc_rcu_putref(sma, sem_rcu_free);
 }
 
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -533,6 +550,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        }
 
        sma->complex_count = 0;
+       sma->complex_mode = true; /* dropped by sem_unlock below */
        INIT_LIST_HEAD(&sma->pending_alter);
        INIT_LIST_HEAD(&sma->pending_const);
        INIT_LIST_HEAD(&sma->list_id);
@@ -1385,7 +1403,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        rcu_read_unlock();
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, ipc_rcu_free);
+                               ipc_rcu_putref(sma, sem_rcu_free);
                                return -ENOMEM;
                        }
 
@@ -1419,20 +1437,20 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                if (nsems > SEMMSL_FAST) {
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, ipc_rcu_free);
+                               ipc_rcu_putref(sma, sem_rcu_free);
                                return -ENOMEM;
                        }
                }
 
                if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
-                       ipc_rcu_putref(sma, ipc_rcu_free);
+                       ipc_rcu_putref(sma, sem_rcu_free);
                        err = -EFAULT;
                        goto out_free;
                }
 
                for (i = 0; i < nsems; i++) {
                        if (sem_io[i] > SEMVMX) {
-                               ipc_rcu_putref(sma, ipc_rcu_free);
+                               ipc_rcu_putref(sma, sem_rcu_free);
                                err = -ERANGE;
                                goto out_free;
                        }
@@ -1722,7 +1740,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 2: allocate new undo structure */
        new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
        if (!new) {
-               ipc_rcu_putref(sma, ipc_rcu_free);
+               ipc_rcu_putref(sma, sem_rcu_free);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -2186,10 +2204,10 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
        /*
         * The proc interface isn't aware of sem_lock(), it calls
         * ipc_lock_object() directly (in sysvipc_find_ipc).
-        * In order to stay compatible with sem_lock(), we must wait until
-        * all simple semop() calls have left their critical regions.
+        * In order to stay compatible with sem_lock(), we must
+        * enter / leave complex_mode.
         */
-       sem_wait_array(sma);
+       complexmode_enter(sma);
 
        sem_otime = get_semotime(sma);
 
@@ -2206,6 +2224,8 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
                   sem_otime,
                   sma->sem_ctime);
 
+       complexmode_tryleave(sma);
+
        return 0;
 }
 #endif
index 5ffcbd354a520b88781ed2d66c7839a7aaa7f86d..34f690b9213abc7f42088329f1005e0be468e111 100644 (file)
@@ -870,6 +870,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                return err;
                }
                if (s.mask & AUDIT_STATUS_PID) {
+                       /* NOTE: we are using task_tgid_vnr() below because
+                        *       the s.pid value is relative to the namespace
+                        *       of the caller; at present this doesn't matter
+                        *       much since you can really only run auditd
+                        *       from the initial pid namespace, but something
+                        *       to keep in mind if this changes */
                        int new_pid = s.pid;
 
                        if ((!new_pid) && (task_tgid_vnr(current) != audit_pid))
@@ -1896,7 +1902,7 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
                         " euid=%u suid=%u fsuid=%u"
                         " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
                         task_ppid_nr(tsk),
-                        task_pid_nr(tsk),
+                        task_tgid_nr(tsk),
                         from_kuid(&init_user_ns, audit_get_loginuid(tsk)),
                         from_kuid(&init_user_ns, cred->uid),
                         from_kgid(&init_user_ns, cred->gid),
index 656c7e93ac0d30d3e42a8f7e0dfc7dd071360d78..939945a5649c7980f871fac6829ac624683190ac 100644 (file)
@@ -19,6 +19,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/file.h>
 #include <linux/kernel.h>
 #include <linux/audit.h>
 #include <linux/kthread.h>
@@ -544,10 +545,11 @@ int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
        unsigned long ino;
        dev_t dev;
 
-       rcu_read_lock();
-       exe_file = rcu_dereference(tsk->mm->exe_file);
+       exe_file = get_task_exe_file(tsk);
+       if (!exe_file)
+               return 0;
        ino = exe_file->f_inode->i_ino;
        dev = exe_file->f_inode->i_sb->s_dev;
-       rcu_read_unlock();
+       fput(exe_file);
        return audit_mark_compare(mark, ino, dev);
 }
index b86cc04959dee64ac1972a28fd35acddae85e94b..63f0e495f5176655f16bbd998ed70ab600cbc64c 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/compat.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
+#include <linux/uaccess.h>
 #include <uapi/linux/limits.h>
 
 #include "audit.h"
@@ -82,7 +83,8 @@
 #define AUDITSC_SUCCESS 1
 #define AUDITSC_FAILURE 2
 
-/* no execve audit message should be longer than this (userspace limits) */
+/* no execve audit message should be longer than this (userspace limits),
+ * see the note near the top of audit_log_execve_info() about this value */
 #define MAX_EXECVE_AUDIT_LEN 7500
 
 /* max length to print of cmdline/proctitle value during audit */
@@ -456,7 +458,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 
                switch (f->type) {
                case AUDIT_PID:
-                       pid = task_pid_nr(tsk);
+                       pid = task_tgid_nr(tsk);
                        result = audit_comparator(pid, f->op, f->val);
                        break;
                case AUDIT_PPID:
@@ -988,184 +990,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
        return rc;
 }
 
-/*
- * to_send and len_sent accounting are very loose estimates.  We aren't
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundary)
- *
- * why snprintf?  an int is up to 12 digits long.  if we just assumed when
- * logging that a[%d]= was going to be 16 characters long we would be wasting
- * space in every audit message.  In one 7500 byte message we can log up to
- * about 1000 min size arguments.  That comes down to about 50% waste of space
- * if we didn't do the snprintf to find out how long arg_num_len was.
- */
-static int audit_log_single_execve_arg(struct audit_context *context,
-                                       struct audit_buffer **ab,
-                                       int arg_num,
-                                       size_t *len_sent,
-                                       const char __user *p,
-                                       char *buf)
+static void audit_log_execve_info(struct audit_context *context,
+                                 struct audit_buffer **ab)
 {
-       char arg_num_len_buf[12];
-       const char __user *tmp_p = p;
-       /* how many digits are in arg_num? 5 is the length of ' a=""' */
-       size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
-       size_t len, len_left, to_send;
-       size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
-       unsigned int i, has_cntl = 0, too_long = 0;
-       int ret;
-
-       /* strnlen_user includes the null we don't want to send */
-       len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
-
-       /*
-        * We just created this mm, if we can't find the strings
-        * we just copied into it something is _very_ wrong. Similar
-        * for strings that are too long, we should not have created
-        * any.
-        */
-       if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
-               send_sig(SIGKILL, current, 0);
-               return -1;
+       long len_max;
+       long len_rem;
+       long len_full;
+       long len_buf;
+       long len_abuf;
+       long len_tmp;
+       bool require_data;
+       bool encode;
+       unsigned int iter;
+       unsigned int arg;
+       char *buf_head;
+       char *buf;
+       const char __user *p = (const char __user *)current->mm->arg_start;
+
+       /* NOTE: this buffer needs to be large enough to hold all the non-arg
+        *       data we put in the audit record for this argument (see the
+        *       code below) ... at this point in time 96 is plenty */
+       char abuf[96];
+
+       /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
+        *       current value of 7500 is not as important as the fact that it
+        *       is less than 8k, a setting of 7500 gives us plenty of wiggle
+        *       room if we go over a little bit in the logging below */
+       WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
+       len_max = MAX_EXECVE_AUDIT_LEN;
+
+       /* scratch buffer to hold the userspace args */
+       buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+       if (!buf_head) {
+               audit_panic("out of memory for argv string");
+               return;
        }
+       buf = buf_head;
 
-       /* walk the whole argument looking for non-ascii chars */
+       audit_log_format(*ab, "argc=%d", context->execve.argc);
+
+       len_rem = len_max;
+       len_buf = 0;
+       len_full = 0;
+       require_data = true;
+       encode = false;
+       iter = 0;
+       arg = 0;
        do {
-               if (len_left > MAX_EXECVE_AUDIT_LEN)
-                       to_send = MAX_EXECVE_AUDIT_LEN;
-               else
-                       to_send = len_left;
-               ret = copy_from_user(buf, tmp_p, to_send);
-               /*
-                * There is no reason for this copy to be short. We just
-                * copied them here, and the mm hasn't been exposed to user-
-                * space yet.
-                */
-               if (ret) {
-                       WARN_ON(1);
-                       send_sig(SIGKILL, current, 0);
-                       return -1;
-               }
-               buf[to_send] = '\0';
-               has_cntl = audit_string_contains_control(buf, to_send);
-               if (has_cntl) {
-                       /*
-                        * hex messages get logged as 2 bytes, so we can only
-                        * send half as much in each message
-                        */
-                       max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
-                       break;
-               }
-               len_left -= to_send;
-               tmp_p += to_send;
-       } while (len_left > 0);
-
-       len_left = len;
-
-       if (len > max_execve_audit_len)
-               too_long = 1;
-
-       /* rewalk the argument actually logging the message */
-       for (i = 0; len_left > 0; i++) {
-               int room_left;
-
-               if (len_left > max_execve_audit_len)
-                       to_send = max_execve_audit_len;
-               else
-                       to_send = len_left;
-
-               /* do we have space left to send this argument in this ab? */
-               room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
-               if (has_cntl)
-                       room_left -= (to_send * 2);
-               else
-                       room_left -= to_send;
-               if (room_left < 0) {
-                       *len_sent = 0;
-                       audit_log_end(*ab);
-                       *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
-                       if (!*ab)
-                               return 0;
-               }
+               /* NOTE: we don't ever want to trust this value for anything
+                *       serious, but the audit record format insists we
+                *       provide an argument length for really long arguments,
+                *       e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
+                *       to use strncpy_from_user() to obtain this value for
+                *       recording in the log, although we don't use it
+                *       anywhere here to avoid a double-fetch problem */
+               if (len_full == 0)
+                       len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+
+               /* read more data from userspace */
+               if (require_data) {
+                       /* can we make more room in the buffer? */
+                       if (buf != buf_head) {
+                               memmove(buf_head, buf, len_buf);
+                               buf = buf_head;
+                       }
+
+                       /* fetch as much as we can of the argument */
+                       len_tmp = strncpy_from_user(&buf_head[len_buf], p,
+                                                   len_max - len_buf);
+                       if (len_tmp == -EFAULT) {
+                               /* unable to copy from userspace */
+                               send_sig(SIGKILL, current, 0);
+                               goto out;
+                       } else if (len_tmp == (len_max - len_buf)) {
+                               /* buffer is not large enough */
+                               require_data = true;
+                               /* NOTE: if we are going to span multiple
+                                *       buffers force the encoding so we stand
+                                *       a chance at a sane len_full value and
+                                *       consistent record encoding */
+                               encode = true;
+                               len_full = len_full * 2;
+                               p += len_tmp;
+                       } else {
+                               require_data = false;
+                               if (!encode)
+                                       encode = audit_string_contains_control(
+                                                               buf, len_tmp);
+                               /* try to use a trusted value for len_full */
+                               if (len_full < len_max)
+                                       len_full = (encode ?
+                                                   len_tmp * 2 : len_tmp);
+                               p += len_tmp + 1;
+                       }
+                       len_buf += len_tmp;
+                       buf_head[len_buf] = '\0';
 
-               /*
-                * first record needs to say how long the original string was
-                * so we can be sure nothing was lost.
-                */
-               if ((i == 0) && (too_long))
-                       audit_log_format(*ab, " a%d_len=%zu", arg_num,
-                                        has_cntl ? 2*len : len);
-
-               /*
-                * normally arguments are small enough to fit and we already
-                * filled buf above when we checked for control characters
-                * so don't bother with another copy_from_user
-                */
-               if (len >= max_execve_audit_len)
-                       ret = copy_from_user(buf, p, to_send);
-               else
-                       ret = 0;
-               if (ret) {
-                       WARN_ON(1);
-                       send_sig(SIGKILL, current, 0);
-                       return -1;
+                       /* length of the buffer in the audit record? */
+                       len_abuf = (encode ? len_buf * 2 : len_buf + 2);
                }
-               buf[to_send] = '\0';
-
-               /* actually log it */
-               audit_log_format(*ab, " a%d", arg_num);
-               if (too_long)
-                       audit_log_format(*ab, "[%d]", i);
-               audit_log_format(*ab, "=");
-               if (has_cntl)
-                       audit_log_n_hex(*ab, buf, to_send);
-               else
-                       audit_log_string(*ab, buf);
-
-               p += to_send;
-               len_left -= to_send;
-               *len_sent += arg_num_len;
-               if (has_cntl)
-                       *len_sent += to_send * 2;
-               else
-                       *len_sent += to_send;
-       }
-       /* include the null we didn't log */
-       return len + 1;
-}
 
-static void audit_log_execve_info(struct audit_context *context,
-                                 struct audit_buffer **ab)
-{
-       int i, len;
-       size_t len_sent = 0;
-       const char __user *p;
-       char *buf;
+               /* write as much as we can to the audit log */
+               if (len_buf > 0) {
+                       /* NOTE: some magic numbers here - basically if we
+                        *       can't fit a reasonable amount of data into the
+                        *       existing audit buffer, flush it and start with
+                        *       a new buffer */
+                       if ((sizeof(abuf) + 8) > len_rem) {
+                               len_rem = len_max;
+                               audit_log_end(*ab);
+                               *ab = audit_log_start(context,
+                                                     GFP_KERNEL, AUDIT_EXECVE);
+                               if (!*ab)
+                                       goto out;
+                       }
 
-       p = (const char __user *)current->mm->arg_start;
+                       /* create the non-arg portion of the arg record */
+                       len_tmp = 0;
+                       if (require_data || (iter > 0) ||
+                           ((len_abuf + sizeof(abuf)) > len_rem)) {
+                               if (iter == 0) {
+                                       len_tmp += snprintf(&abuf[len_tmp],
+                                                       sizeof(abuf) - len_tmp,
+                                                       " a%d_len=%lu",
+                                                       arg, len_full);
+                               }
+                               len_tmp += snprintf(&abuf[len_tmp],
+                                                   sizeof(abuf) - len_tmp,
+                                                   " a%d[%d]=", arg, iter++);
+                       } else
+                               len_tmp += snprintf(&abuf[len_tmp],
+                                                   sizeof(abuf) - len_tmp,
+                                                   " a%d=", arg);
+                       WARN_ON(len_tmp >= sizeof(abuf));
+                       abuf[sizeof(abuf) - 1] = '\0';
+
+                       /* log the arg in the audit record */
+                       audit_log_format(*ab, "%s", abuf);
+                       len_rem -= len_tmp;
+                       len_tmp = len_buf;
+                       if (encode) {
+                               if (len_abuf > len_rem)
+                                       len_tmp = len_rem / 2; /* encoding */
+                               audit_log_n_hex(*ab, buf, len_tmp);
+                               len_rem -= len_tmp * 2;
+                               len_abuf -= len_tmp * 2;
+                       } else {
+                               if (len_abuf > len_rem)
+                                       len_tmp = len_rem - 2; /* quotes */
+                               audit_log_n_string(*ab, buf, len_tmp);
+                               len_rem -= len_tmp + 2;
+                               /* don't subtract the "2" because we still need
+                                * to add quotes to the remaining string */
+                               len_abuf -= len_tmp;
+                       }
+                       len_buf -= len_tmp;
+                       buf += len_tmp;
+               }
 
-       audit_log_format(*ab, "argc=%d", context->execve.argc);
+               /* ready to move to the next argument? */
+               if ((len_buf == 0) && !require_data) {
+                       arg++;
+                       iter = 0;
+                       len_full = 0;
+                       require_data = true;
+                       encode = false;
+               }
+       } while (arg < context->execve.argc);
 
-       /*
-        * we need some kernel buffer to hold the userspace args.  Just
-        * allocate one big one rather than allocating one of the right size
-        * for every single argument inside audit_log_single_execve_arg()
-        * should be <8k allocation so should be pretty safe.
-        */
-       buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
-       if (!buf) {
-               audit_panic("out of memory for argv string");
-               return;
-       }
+       /* NOTE: the caller handles the final audit_log_end() call */
 
-       for (i = 0; i < context->execve.argc; i++) {
-               len = audit_log_single_execve_arg(context, ab, i,
-                                                 &len_sent, p, buf);
-               if (len <= 0)
-                       break;
-               p += len;
-       }
-       kfree(buf);
+out:
+       kfree(buf_head);
 }
 
 static void show_special(struct audit_context *context, int *call_panic)
@@ -1991,7 +1987,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
        if (!ab)
                return;
-       audit_log_format(ab, "pid=%d uid=%u", task_pid_nr(current), uid);
+       audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
        audit_log_task_context(ab);
        audit_log_format(ab, " old-auid=%u auid=%u old-ses=%u ses=%u res=%d",
                         oldloginuid, loginuid, oldsessionid, sessionid, !rc);
@@ -2216,7 +2212,7 @@ void __audit_ptrace(struct task_struct *t)
 {
        struct audit_context *context = current->audit_context;
 
-       context->target_pid = task_pid_nr(t);
+       context->target_pid = task_tgid_nr(t);
        context->target_auid = audit_get_loginuid(t);
        context->target_uid = task_uid(t);
        context->target_sessionid = audit_get_sessionid(t);
@@ -2241,7 +2237,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
 
        if (audit_pid && t->tgid == audit_pid) {
                if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
-                       audit_sig_pid = task_pid_nr(tsk);
+                       audit_sig_pid = task_tgid_nr(tsk);
                        if (uid_valid(tsk->loginuid))
                                audit_sig_uid = tsk->loginuid;
                        else
@@ -2341,7 +2337,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
 void __audit_log_capset(const struct cred *new, const struct cred *old)
 {
        struct audit_context *context = current->audit_context;
-       context->capset.pid = task_pid_nr(current);
+       context->capset.pid = task_tgid_nr(current);
        context->capset.cap.effective   = new->cap_effective;
        context->capset.cap.inheritable = new->cap_effective;
        context->capset.cap.permitted   = new->cap_permitted;
@@ -2373,7 +2369,7 @@ static void audit_log_task(struct audit_buffer *ab)
                         from_kgid(&init_user_ns, gid),
                         sessionid);
        audit_log_task_context(ab);
-       audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
+       audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
        audit_log_untrustedstring(ab, get_task_comm(comm, current));
        audit_log_d_path_exe(ab, current->mm);
 }
index 45432b54d5c60ca5b9cde95e480c3fae8cffae4a..00411c82dac57c4cac0254c823f9adcb2a951549 100644 (file)
@@ -361,6 +361,24 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
        return has_ns_capability_noaudit(t, &init_user_ns, cap);
 }
 
+static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
+{
+       int capable;
+
+       if (unlikely(!cap_valid(cap))) {
+               pr_crit("capable() called with invalid cap=%u\n", cap);
+               BUG();
+       }
+
+       capable = audit ? security_capable(current_cred(), ns, cap) :
+                         security_capable_noaudit(current_cred(), ns, cap);
+       if (capable == 0) {
+               current->flags |= PF_SUPERPRIV;
+               return true;
+       }
+       return false;
+}
+
 /**
  * ns_capable - Determine if the current task has a superior capability in effect
  * @ns:  The usernamespace we want the capability in
@@ -374,19 +392,27 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
  */
 bool ns_capable(struct user_namespace *ns, int cap)
 {
-       if (unlikely(!cap_valid(cap))) {
-               pr_crit("capable() called with invalid cap=%u\n", cap);
-               BUG();
-       }
-
-       if (security_capable(current_cred(), ns, cap) == 0) {
-               current->flags |= PF_SUPERPRIV;
-               return true;
-       }
-       return false;
+       return ns_capable_common(ns, cap, true);
 }
 EXPORT_SYMBOL(ns_capable);
 
+/**
+ * ns_capable_noaudit - Determine if the current task has a superior capability
+ * (unaudited) in effect
+ * @ns:  The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool ns_capable_noaudit(struct user_namespace *ns, int cap)
+{
+       return ns_capable_common(ns, cap, false);
+}
+EXPORT_SYMBOL(ns_capable_noaudit);
 
 /**
  * capable - Determine if the current task has a superior capability in effect
index 47851dbc893d1ee1e952bf6ef37792c59f1af77b..e4552a3cbf418a666a55a462707aba46b0d66960 100644 (file)
@@ -2671,45 +2671,6 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp,
        return ret;
 }
 
-int subsys_cgroup_allow_attach(struct cgroup_taskset *tset)
-{
-       const struct cred *cred = current_cred(), *tcred;
-       struct task_struct *task;
-       struct cgroup_subsys_state *css;
-
-       if (capable(CAP_SYS_NICE))
-               return 0;
-
-       cgroup_taskset_for_each(task, css, tset) {
-               tcred = __task_cred(task);
-
-               if (current != task && !uid_eq(cred->euid, tcred->uid) &&
-                   !uid_eq(cred->euid, tcred->suid))
-                       return -EACCES;
-       }
-
-       return 0;
-}
-
-static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
-{
-       struct cgroup_subsys_state *css;
-       int i;
-       int ret;
-
-       for_each_css(css, i, cgrp) {
-               if (css->ss->allow_attach) {
-                       ret = css->ss->allow_attach(tset);
-                       if (ret)
-                               return ret;
-               } else {
-                       return -EACCES;
-               }
-       }
-
-       return 0;
-}
-
 static int cgroup_procs_write_permission(struct task_struct *task,
                                         struct cgroup *dst_cgrp,
                                         struct kernfs_open_file *of)
@@ -2724,24 +2685,9 @@ static int cgroup_procs_write_permission(struct task_struct *task,
         */
        if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
            !uid_eq(cred->euid, tcred->uid) &&
-           !uid_eq(cred->euid, tcred->suid)) {
-               /*
-                * if the default permission check fails, give each
-                * cgroup a chance to extend the permission check
-                */
-               struct cgroup_taskset tset = {
-                       .src_csets = LIST_HEAD_INIT(tset.src_csets),
-                       .dst_csets = LIST_HEAD_INIT(tset.dst_csets),
-                       .csets = &tset.src_csets,
-               };
-               struct css_set *cset;
-               cset = task_css_set(task);
-               list_add(&cset->mg_node, &tset.src_csets);
-               ret = cgroup_allow_attach(dst_cgrp, &tset);
-               list_del(&tset.src_csets);
-               if (ret)
-                       ret = -EACCES;
-       }
+           !uid_eq(cred->euid, tcred->suid) &&
+           !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
+               ret = -EACCES;
 
        if (!ret && cgroup_on_dfl(dst_cgrp)) {
                struct super_block *sb = of->file->f_path.dentry->d_sb;
@@ -4848,6 +4794,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
        memset(css, 0, sizeof(*css));
        css->cgroup = cgrp;
        css->ss = ss;
+       css->id = -1;
        INIT_LIST_HEAD(&css->sibling);
        INIT_LIST_HEAD(&css->children);
        css->serial_nr = css_serial_nr_next++;
@@ -5379,6 +5326,12 @@ int __init cgroup_init(void)
        BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files));
        BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files));
 
+       /*
+        * The latency of the synchronize_sched() is too high for cgroups,
+        * avoid it at the cost of forcing all readers into the slow path.
+        */
+       rcu_sync_enter_start(&cgroup_threadgroup_rwsem.rss);
+
        mutex_lock(&cgroup_mutex);
 
        /* Add init_css_set to the hash table */
index c2de56ab0fce8b2193a2414afc2d4eb743510c74..7fa0c4ae6394f028fa09694b219314dd3d7d8731 100644 (file)
@@ -1,4 +1,12 @@
+# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
 CONFIG_KERNEL_XZ=y
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
 CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
 CONFIG_SLOB=y
index 9ced7c7516481f05549c48e6b2d3ae1bf5f36f61..c8a1751be2244233f7ebeea0db601593b3e468a3 100644 (file)
@@ -185,10 +185,17 @@ void cpu_hotplug_disable(void)
 }
 EXPORT_SYMBOL_GPL(cpu_hotplug_disable);
 
+static void __cpu_hotplug_enable(void)
+{
+       if (WARN_ONCE(!cpu_hotplug_disabled, "Unbalanced cpu hotplug enable\n"))
+               return;
+       cpu_hotplug_disabled--;
+}
+
 void cpu_hotplug_enable(void)
 {
        cpu_maps_update_begin();
-       WARN_ON(--cpu_hotplug_disabled < 0);
+       __cpu_hotplug_enable();
        cpu_maps_update_done();
 }
 EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
@@ -631,7 +638,7 @@ void enable_nonboot_cpus(void)
 
        /* Allow everyone to use the CPU hotplug again */
        cpu_maps_update_begin();
-       WARN_ON(--cpu_hotplug_disabled < 0);
+       __cpu_hotplug_enable();
        if (cpumask_empty(frozen_cpus))
                goto out;
 
index 11eaf14b52c2919b63131485d33dd2e7203aca58..3f9db31c5d043287b7e566fdaace6446ee46e6a1 100644 (file)
@@ -98,6 +98,7 @@ struct cpuset {
 
        /* user-configured CPUs and Memory Nodes allow to tasks */
        cpumask_var_t cpus_allowed;
+       cpumask_var_t cpus_requested;
        nodemask_t mems_allowed;
 
        /* effective CPUs and Memory Nodes allow to tasks */
@@ -324,8 +325,7 @@ static struct file_system_type cpuset_fs_type = {
 /*
  * Return in pmask the portion of a cpusets's cpus_allowed that
  * are online.  If none are online, walk up the cpuset hierarchy
- * until we find one that does have some online cpus.  The top
- * cpuset always has some cpus online.
+ * until we find one that does have some online cpus.
  *
  * One way or another, we guarantee to return some non-empty subset
  * of cpu_online_mask.
@@ -334,8 +334,20 @@ static struct file_system_type cpuset_fs_type = {
  */
 static void guarantee_online_cpus(struct cpuset *cs, struct cpumask *pmask)
 {
-       while (!cpumask_intersects(cs->effective_cpus, cpu_online_mask))
+       while (!cpumask_intersects(cs->effective_cpus, cpu_online_mask)) {
                cs = parent_cs(cs);
+               if (unlikely(!cs)) {
+                       /*
+                        * The top cpuset doesn't have any online cpu as a
+                        * consequence of a race between cpuset_hotplug_work
+                        * and cpu hotplug notifier.  But we know the top
+                        * cpuset's effective_cpus is on its way to to be
+                        * identical to cpu_online_mask.
+                        */
+                       cpumask_copy(pmask, cpu_online_mask);
+                       return;
+               }
+       }
        cpumask_and(pmask, cs->effective_cpus, cpu_online_mask);
 }
 
@@ -386,7 +398,7 @@ static void cpuset_update_task_spread_flag(struct cpuset *cs,
 
 static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
 {
-       return  cpumask_subset(p->cpus_allowed, q->cpus_allowed) &&
+       return  cpumask_subset(p->cpus_requested, q->cpus_requested) &&
                nodes_subset(p->mems_allowed, q->mems_allowed) &&
                is_cpu_exclusive(p) <= is_cpu_exclusive(q) &&
                is_mem_exclusive(p) <= is_mem_exclusive(q);
@@ -486,7 +498,7 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
        cpuset_for_each_child(c, css, par) {
                if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
                    c != cur &&
-                   cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
+                   cpumask_intersects(trial->cpus_requested, c->cpus_requested))
                        goto out;
                if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
                    c != cur &&
@@ -945,17 +957,18 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
        if (!*buf) {
                cpumask_clear(trialcs->cpus_allowed);
        } else {
-               retval = cpulist_parse(buf, trialcs->cpus_allowed);
+               retval = cpulist_parse(buf, trialcs->cpus_requested);
                if (retval < 0)
                        return retval;
 
-               if (!cpumask_subset(trialcs->cpus_allowed,
-                                   top_cpuset.cpus_allowed))
+               if (!cpumask_subset(trialcs->cpus_requested, cpu_present_mask))
                        return -EINVAL;
+
+               cpumask_and(trialcs->cpus_allowed, trialcs->cpus_requested, cpu_active_mask);
        }
 
        /* Nothing to do if the cpus didn't change */
-       if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed))
+       if (cpumask_equal(cs->cpus_requested, trialcs->cpus_requested))
                return 0;
 
        retval = validate_change(cs, trialcs);
@@ -964,6 +977,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
 
        spin_lock_irq(&callback_lock);
        cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
+       cpumask_copy(cs->cpus_requested, trialcs->cpus_requested);
        spin_unlock_irq(&callback_lock);
 
        /* use trialcs->cpus_allowed as a temp variable */
@@ -1754,7 +1768,7 @@ static int cpuset_common_seq_show(struct seq_file *sf, void *v)
 
        switch (type) {
        case FILE_CPULIST:
-               seq_printf(sf, "%*pbl\n", cpumask_pr_args(cs->cpus_allowed));
+               seq_printf(sf, "%*pbl\n", cpumask_pr_args(cs->cpus_requested));
                break;
        case FILE_MEMLIST:
                seq_printf(sf, "%*pbl\n", nodemask_pr_args(&cs->mems_allowed));
@@ -1943,11 +1957,14 @@ cpuset_css_alloc(struct cgroup_subsys_state *parent_css)
                return ERR_PTR(-ENOMEM);
        if (!alloc_cpumask_var(&cs->cpus_allowed, GFP_KERNEL))
                goto free_cs;
+       if (!alloc_cpumask_var(&cs->cpus_requested, GFP_KERNEL))
+               goto free_allowed;
        if (!alloc_cpumask_var(&cs->effective_cpus, GFP_KERNEL))
-               goto free_cpus;
+               goto free_requested;
 
        set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
        cpumask_clear(cs->cpus_allowed);
+       cpumask_clear(cs->cpus_requested);
        nodes_clear(cs->mems_allowed);
        cpumask_clear(cs->effective_cpus);
        nodes_clear(cs->effective_mems);
@@ -1956,7 +1973,9 @@ cpuset_css_alloc(struct cgroup_subsys_state *parent_css)
 
        return &cs->css;
 
-free_cpus:
+free_requested:
+       free_cpumask_var(cs->cpus_requested);
+free_allowed:
        free_cpumask_var(cs->cpus_allowed);
 free_cs:
        kfree(cs);
@@ -2019,6 +2038,7 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
        cs->mems_allowed = parent->mems_allowed;
        cs->effective_mems = parent->mems_allowed;
        cpumask_copy(cs->cpus_allowed, parent->cpus_allowed);
+       cpumask_copy(cs->cpus_requested, parent->cpus_requested);
        cpumask_copy(cs->effective_cpus, parent->cpus_allowed);
        spin_unlock_irq(&callback_lock);
 out_unlock:
@@ -2053,6 +2073,7 @@ static void cpuset_css_free(struct cgroup_subsys_state *css)
 
        free_cpumask_var(cs->effective_cpus);
        free_cpumask_var(cs->cpus_allowed);
+       free_cpumask_var(cs->cpus_requested);
        kfree(cs);
 }
 
@@ -2074,6 +2095,20 @@ static void cpuset_bind(struct cgroup_subsys_state *root_css)
        mutex_unlock(&cpuset_mutex);
 }
 
+/*
+ * Make sure the new task conform to the current state of its parent,
+ * which could have been changed by cpuset just after it inherits the
+ * state from the parent and before it sits on the cgroup's task list.
+ */
+void cpuset_fork(struct task_struct *task, void *priv)
+{
+       if (task_css_is_root(task, cpuset_cgrp_id))
+               return;
+
+       set_cpus_allowed_ptr(task, &current->cpus_allowed);
+       task->mems_allowed = current->mems_allowed;
+}
+
 struct cgroup_subsys cpuset_cgrp_subsys = {
        .css_alloc      = cpuset_css_alloc,
        .css_online     = cpuset_css_online,
@@ -2084,6 +2119,7 @@ struct cgroup_subsys cpuset_cgrp_subsys = {
        .attach         = cpuset_attach,
        .post_attach    = cpuset_post_attach,
        .bind           = cpuset_bind,
+       .fork           = cpuset_fork,
        .legacy_cftypes = files,
        .early_init     = 1,
 };
@@ -2102,8 +2138,11 @@ int __init cpuset_init(void)
                BUG();
        if (!alloc_cpumask_var(&top_cpuset.effective_cpus, GFP_KERNEL))
                BUG();
+       if (!alloc_cpumask_var(&top_cpuset.cpus_requested, GFP_KERNEL))
+               BUG();
 
        cpumask_setall(top_cpuset.cpus_allowed);
+       cpumask_setall(top_cpuset.cpus_requested);
        nodes_setall(top_cpuset.mems_allowed);
        cpumask_setall(top_cpuset.effective_cpus);
        nodes_setall(top_cpuset.effective_mems);
@@ -2237,7 +2276,7 @@ retry:
                goto retry;
        }
 
-       cpumask_and(&new_cpus, cs->cpus_allowed, parent_cs(cs)->effective_cpus);
+       cpumask_and(&new_cpus, cs->cpus_requested, parent_cs(cs)->effective_cpus);
        nodes_and(new_mems, cs->mems_allowed, parent_cs(cs)->effective_mems);
 
        cpus_updated = !cpumask_equal(&new_cpus, cs->effective_cpus);
index 71179a09c1d6a3240fd9c1a4ead58d89646da24e..ff8606f77d901d4ed1201d35d35feaa5066821e3 100644 (file)
@@ -689,6 +689,8 @@ EXPORT_SYMBOL(set_security_override_from_ctx);
  */
 int set_create_files_as(struct cred *new, struct inode *inode)
 {
+       if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+               return -EINVAL;
        new->fsuid = inode->i_uid;
        new->fsgid = inode->i_gid;
        return security_kernel_create_files_as(new, inode);
index 662f2b23632fbbb0b0272035efe51ce3bd60ce95..f4fdaff76f6d90a77274e37ac919baede07dcf4e 100644 (file)
@@ -1544,12 +1544,33 @@ static int __init perf_workqueue_init(void)
 
 core_initcall(perf_workqueue_init);
 
-static inline int pmu_filter_match(struct perf_event *event)
+static inline int __pmu_filter_match(struct perf_event *event)
 {
        struct pmu *pmu = event->pmu;
        return pmu->filter_match ? pmu->filter_match(event) : 1;
 }
 
+/*
+ * Check whether we should attempt to schedule an event group based on
+ * PMU-specific filtering. An event group can consist of HW and SW events,
+ * potentially with a SW leader, so we must check all the filters, to
+ * determine whether a group is schedulable:
+ */
+static inline int pmu_filter_match(struct perf_event *event)
+{
+       struct perf_event *child;
+
+       if (!__pmu_filter_match(event))
+               return 0;
+
+       list_for_each_entry(child, &event->sibling_list, group_entry) {
+               if (!__pmu_filter_match(child))
+                       return 0;
+       }
+
+       return 1;
+}
+
 static inline int
 event_filter_match(struct perf_event *event)
 {
index 7dad84913abfb06df2495fae555e7f8bcac2b104..7b1b772ab1ce4f381ce085c82e11005af3f5a2c6 100644 (file)
@@ -171,8 +171,10 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
        mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
        err = -EAGAIN;
        ptep = page_check_address(page, mm, addr, &ptl, 0);
-       if (!ptep)
+       if (!ptep) {
+               mem_cgroup_cancel_charge(kpage, memcg);
                goto unlock;
+       }
 
        get_page(kpage);
        page_add_new_anon_rmap(kpage, vma, addr);
@@ -199,7 +201,6 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
 
        err = 0;
  unlock:
-       mem_cgroup_cancel_charge(kpage, memcg);
        mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
        unlock_page(page);
        return err;
@@ -1692,8 +1693,7 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
        int result;
 
        pagefault_disable();
-       result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr,
-                                                       sizeof(opcode));
+       result = __get_user(opcode, (uprobe_opcode_t __user *)vaddr);
        pagefault_enable();
 
        if (likely(result == 0))
index ffba5df4abd54cd2dc146a09fa152ed84502e213..62c4bd4abd3a2a99aac0d4cf6fde311770cf0a0d 100644 (file)
@@ -54,6 +54,8 @@
 #include <linux/writeback.h>
 #include <linux/shm.h>
 
+#include "sched/tune.h"
+
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/pgtable.h>
@@ -699,6 +701,9 @@ void do_exit(long code)
        }
 
        exit_signals(tsk);  /* sets PF_EXITING */
+
+       schedtune_exit_task(tsk);
+
        /*
         * tsk->flags are checked in the futex code to protect against
         * an exiting task cleaning up the robust pi futexes.
index 7ec6e9939b2c97c0ee62ec8cfdf05fd74bc4f4e7..18a5cb17035a1b23c9df9323ee05da774ad6e60b 100644 (file)
@@ -763,6 +763,29 @@ struct file *get_mm_exe_file(struct mm_struct *mm)
 }
 EXPORT_SYMBOL(get_mm_exe_file);
 
+/**
+ * get_task_exe_file - acquire a reference to the task's executable file
+ *
+ * Returns %NULL if task's mm (if any) has no associated executable file or
+ * this is a kernel thread with borrowed mm (see the comment above get_task_mm).
+ * User must release file via fput().
+ */
+struct file *get_task_exe_file(struct task_struct *task)
+{
+       struct file *exe_file = NULL;
+       struct mm_struct *mm;
+
+       task_lock(task);
+       mm = task->mm;
+       if (mm) {
+               if (!(task->flags & PF_KTHREAD))
+                       exe_file = get_mm_exe_file(mm);
+       }
+       task_unlock(task);
+       return exe_file;
+}
+EXPORT_SYMBOL(get_task_exe_file);
+
 /**
  * get_task_mm - acquire a reference to the task's mm
  *
@@ -879,14 +902,12 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
        deactivate_mm(tsk, mm);
 
        /*
-        * If we're exiting normally, clear a user-space tid field if
-        * requested.  We leave this alone when dying by signal, to leave
-        * the value intact in a core dump, and to save the unnecessary
-        * trouble, say, a killed vfork parent shouldn't touch this mm.
-        * Userland only wants this done for a sys_exit.
+        * Signal userspace if we're not exiting with a core dump
+        * because we want to leave the value intact for debugging
+        * purposes.
         */
        if (tsk->clear_child_tid) {
-               if (!(tsk->flags & PF_SIGNALED) &&
+               if (!(tsk->signal->flags & SIGNAL_GROUP_COREDUMP) &&
                    atomic_read(&mm->mm_users) > 1) {
                        /*
                         * We don't check the error code - if userspace has
@@ -1370,7 +1391,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->real_start_time = ktime_get_boot_ns();
        p->io_context = NULL;
        p->audit_context = NULL;
-       threadgroup_change_begin(current);
        cgroup_fork(p);
 #ifdef CONFIG_NUMA
        p->mempolicy = mpol_dup(p->mempolicy);
@@ -1522,6 +1542,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        INIT_LIST_HEAD(&p->thread_group);
        p->task_works = NULL;
 
+       threadgroup_change_begin(current);
        /*
         * Ensure that the cgroup subsystem policies allow the new process to be
         * forked. It should be noted the the new process's css_set can be changed
@@ -1622,6 +1643,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 bad_fork_cancel_cgroup:
        cgroup_cancel_fork(p, cgrp_ss_priv);
 bad_fork_free_pid:
+       threadgroup_change_end(current);
        if (pid != &init_struct_pid)
                free_pid(pid);
 bad_fork_cleanup_io:
@@ -1652,7 +1674,6 @@ bad_fork_cleanup_policy:
        mpol_put(p->mempolicy);
 bad_fork_cleanup_threadgroup_lock:
 #endif
-       threadgroup_change_end(current);
        delayacct_tsk_free(p);
 bad_fork_cleanup_count:
        atomic_dec(&p->cred->user->processes);
index 9d8163afd87ca7605ef85d2ca64d3c4521838fae..e8af73cc51a7cd6bf453aaf03e5ccd5842aacca2 100644 (file)
@@ -681,7 +681,7 @@ static int get_futex_value_locked(u32 *dest, u32 __user *from)
        int ret;
 
        pagefault_disable();
-       ret = __copy_from_user_inatomic(dest, from, sizeof(u32));
+       ret = __get_user(*dest, from);
        pagefault_enable();
 
        return ret ? -EFAULT : 0;
index abd286afbd2732544e54a4653053a4d9ce785286..a4775f3451b92cade312a0671e8b45dcf3a1aa0f 100644 (file)
@@ -411,8 +411,29 @@ int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
 }
 EXPORT_SYMBOL_GPL(irq_map_generic_chip);
 
+static void irq_unmap_generic_chip(struct irq_domain *d, unsigned int virq)
+{
+       struct irq_data *data = irq_domain_get_irq_data(d, virq);
+       struct irq_domain_chip_generic *dgc = d->gc;
+       unsigned int hw_irq = data->hwirq;
+       struct irq_chip_generic *gc;
+       int irq_idx;
+
+       gc = irq_get_domain_generic_chip(d, hw_irq);
+       if (!gc)
+               return;
+
+       irq_idx = hw_irq % dgc->irqs_per_chip;
+
+       clear_bit(irq_idx, &gc->installed);
+       irq_domain_set_info(d, virq, hw_irq, &no_irq_chip, NULL, NULL, NULL,
+                           NULL);
+
+}
+
 struct irq_domain_ops irq_generic_chip_ops = {
        .map    = irq_map_generic_chip,
+       .unmap  = irq_unmap_generic_chip,
        .xlate  = irq_domain_xlate_onetwocell,
 };
 EXPORT_SYMBOL_GPL(irq_generic_chip_ops);
index 6b0c0b74a2a1a88c0d3f81519fea7c520b290967..cd60090065106d42ed3794908da05deab9b90040 100644 (file)
@@ -268,7 +268,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
        struct msi_domain_ops *ops = info->ops;
        msi_alloc_info_t arg;
        struct msi_desc *desc;
-       int i, ret, virq = -1;
+       int i, ret, virq;
 
        ret = ops->msi_check(domain, info, dev);
        if (ret == 0)
@@ -278,12 +278,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
 
        for_each_msi_entry(desc, dev) {
                ops->set_desc(&arg, desc);
-               if (info->flags & MSI_FLAG_IDENTITY_MAP)
-                       virq = (int)ops->get_hwirq(info, &arg);
-               else
-                       virq = -1;
 
-               virq = __irq_domain_alloc_irqs(domain, virq, desc->nvec_used,
+               virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
                                               dev_to_node(dev), &arg, false);
                if (virq < 0) {
                        ret = -ENOSPC;
@@ -302,11 +298,23 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
                ops->msi_finish(&arg, 0);
 
        for_each_msi_entry(desc, dev) {
+               virq = desc->irq;
                if (desc->nvec_used == 1)
                        dev_dbg(dev, "irq %d for MSI\n", virq);
                else
                        dev_dbg(dev, "irq [%d-%d] for MSI\n",
                                virq, virq + desc->nvec_used - 1);
+               /*
+                * This flag is set by the PCI layer as we need to activate
+                * the MSI entries before the PCI layer enables MSI in the
+                * card. Otherwise the card latches a random msi message.
+                */
+               if (info->flags & MSI_FLAG_ACTIVATE_EARLY) {
+                       struct irq_data *irq_data;
+
+                       irq_data = irq_domain_get_irq_data(domain, desc->irq);
+                       irq_domain_activate_irq(irq_data);
+               }
        }
 
        return 0;
index b70ada0028d251d7171f13b0de7e9e47e1e6086c..6030efd4a188ae0b6ae25998a496eb8ea9f5bb39 100644 (file)
@@ -934,7 +934,10 @@ int kexec_load_purgatory(struct kimage *image, unsigned long min,
        return 0;
 out:
        vfree(pi->sechdrs);
+       pi->sechdrs = NULL;
+
        vfree(pi->purgatory_buf);
+       pi->purgatory_buf = NULL;
        return ret;
 }
 
index f231e0bb311ce0827d281d34f737a3a06405c072..ce182599cf2e98b51831adbf5dca6ce545df0d7f 100644 (file)
 #include <linux/sched.h>
 #include <linux/errno.h>
 
-int __percpu_init_rwsem(struct percpu_rw_semaphore *brw,
+int __percpu_init_rwsem(struct percpu_rw_semaphore *sem,
                        const char *name, struct lock_class_key *rwsem_key)
 {
-       brw->fast_read_ctr = alloc_percpu(int);
-       if (unlikely(!brw->fast_read_ctr))
+       sem->read_count = alloc_percpu(int);
+       if (unlikely(!sem->read_count))
                return -ENOMEM;
 
        /* ->rw_sem represents the whole percpu_rw_semaphore for lockdep */
-       __init_rwsem(&brw->rw_sem, name, rwsem_key);
-       rcu_sync_init(&brw->rss, RCU_SCHED_SYNC);
-       atomic_set(&brw->slow_read_ctr, 0);
-       init_waitqueue_head(&brw->write_waitq);
+       rcu_sync_init(&sem->rss, RCU_SCHED_SYNC);
+       __init_rwsem(&sem->rw_sem, name, rwsem_key);
+       init_waitqueue_head(&sem->writer);
+       sem->readers_block = 0;
        return 0;
 }
 EXPORT_SYMBOL_GPL(__percpu_init_rwsem);
 
-void percpu_free_rwsem(struct percpu_rw_semaphore *brw)
+void percpu_free_rwsem(struct percpu_rw_semaphore *sem)
 {
        /*
         * XXX: temporary kludge. The error path in alloc_super()
         * assumes that percpu_free_rwsem() is safe after kzalloc().
         */
-       if (!brw->fast_read_ctr)
+       if (!sem->read_count)
                return;
 
-       rcu_sync_dtor(&brw->rss);
-       free_percpu(brw->fast_read_ctr);
-       brw->fast_read_ctr = NULL; /* catch use after free bugs */
+       rcu_sync_dtor(&sem->rss);
+       free_percpu(sem->read_count);
+       sem->read_count = NULL; /* catch use after free bugs */
 }
+EXPORT_SYMBOL_GPL(percpu_free_rwsem);
 
-/*
- * This is the fast-path for down_read/up_read. If it succeeds we rely
- * on the barriers provided by rcu_sync_enter/exit; see the comments in
- * percpu_down_write() and percpu_up_write().
- *
- * If this helper fails the callers rely on the normal rw_semaphore and
- * atomic_dec_and_test(), so in this case we have the necessary barriers.
- */
-static bool update_fast_ctr(struct percpu_rw_semaphore *brw, unsigned int val)
+int __percpu_down_read(struct percpu_rw_semaphore *sem, int try)
 {
-       bool success;
+       /*
+        * Due to having preemption disabled the decrement happens on
+        * the same CPU as the increment, avoiding the
+        * increment-on-one-CPU-and-decrement-on-another problem.
+        *
+        * If the reader misses the writer's assignment of readers_block, then
+        * the writer is guaranteed to see the reader's increment.
+        *
+        * Conversely, any readers that increment their sem->read_count after
+        * the writer looks are guaranteed to see the readers_block value,
+        * which in turn means that they are guaranteed to immediately
+        * decrement their sem->read_count, so that it doesn't matter that the
+        * writer missed them.
+        */
 
-       preempt_disable();
-       success = rcu_sync_is_idle(&brw->rss);
-       if (likely(success))
-               __this_cpu_add(*brw->fast_read_ctr, val);
-       preempt_enable();
+       smp_mb(); /* A matches D */
 
-       return success;
-}
+       /*
+        * If !readers_block the critical section starts here, matched by the
+        * release in percpu_up_write().
+        */
+       if (likely(!smp_load_acquire(&sem->readers_block)))
+               return 1;
 
-/*
- * Like the normal down_read() this is not recursive, the writer can
- * come after the first percpu_down_read() and create the deadlock.
- *
- * Note: returns with lock_is_held(brw->rw_sem) == T for lockdep,
- * percpu_up_read() does rwsem_release(). This pairs with the usage
- * of ->rw_sem in percpu_down/up_write().
- */
-void percpu_down_read(struct percpu_rw_semaphore *brw)
-{
-       might_sleep();
-       rwsem_acquire_read(&brw->rw_sem.dep_map, 0, 0, _RET_IP_);
+       /*
+        * Per the above comment; we still have preemption disabled and
+        * will thus decrement on the same CPU as we incremented.
+        */
+       __percpu_up_read(sem);
 
-       if (likely(update_fast_ctr(brw, +1)))
-               return;
+       if (try)
+               return 0;
 
-       /* Avoid rwsem_acquire_read() and rwsem_release() */
-       __down_read(&brw->rw_sem);
-       atomic_inc(&brw->slow_read_ctr);
-       __up_read(&brw->rw_sem);
-}
-EXPORT_SYMBOL_GPL(percpu_down_read);
+       /*
+        * We either call schedule() in the wait, or we'll fall through
+        * and reschedule on the preempt_enable() in percpu_down_read().
+        */
+       preempt_enable_no_resched();
 
-int percpu_down_read_trylock(struct percpu_rw_semaphore *brw)
-{
-       if (unlikely(!update_fast_ctr(brw, +1))) {
-               if (!__down_read_trylock(&brw->rw_sem))
-                       return 0;
-               atomic_inc(&brw->slow_read_ctr);
-               __up_read(&brw->rw_sem);
-       }
-
-       rwsem_acquire_read(&brw->rw_sem.dep_map, 0, 1, _RET_IP_);
+       /*
+        * Avoid lockdep for the down/up_read() we already have them.
+        */
+       __down_read(&sem->rw_sem);
+       this_cpu_inc(*sem->read_count);
+       __up_read(&sem->rw_sem);
+
+       preempt_disable();
        return 1;
 }
+EXPORT_SYMBOL_GPL(__percpu_down_read);
 
-void percpu_up_read(struct percpu_rw_semaphore *brw)
+void __percpu_up_read(struct percpu_rw_semaphore *sem)
 {
-       rwsem_release(&brw->rw_sem.dep_map, 1, _RET_IP_);
-
-       if (likely(update_fast_ctr(brw, -1)))
-               return;
+       smp_mb(); /* B matches C */
+       /*
+        * In other words, if they see our decrement (presumably to aggregate
+        * zero, as that is the only time it matters) they will also see our
+        * critical section.
+        */
+       __this_cpu_dec(*sem->read_count);
 
-       /* false-positive is possible but harmless */
-       if (atomic_dec_and_test(&brw->slow_read_ctr))
-               wake_up_all(&brw->write_waitq);
+       /* Prod writer to recheck readers_active */
+       wake_up(&sem->writer);
 }
-EXPORT_SYMBOL_GPL(percpu_up_read);
+EXPORT_SYMBOL_GPL(__percpu_up_read);
+
+#define per_cpu_sum(var)                                               \
+({                                                                     \
+       typeof(var) __sum = 0;                                          \
+       int cpu;                                                        \
+       compiletime_assert_atomic_type(__sum);                          \
+       for_each_possible_cpu(cpu)                                      \
+               __sum += per_cpu(var, cpu);                             \
+       __sum;                                                          \
+})
 
-static int clear_fast_ctr(struct percpu_rw_semaphore *brw)
+/*
+ * Return true if the modular sum of the sem->read_count per-CPU variable is
+ * zero.  If this sum is zero, then it is stable due to the fact that if any
+ * newly arriving readers increment a given counter, they will immediately
+ * decrement that same counter.
+ */
+static bool readers_active_check(struct percpu_rw_semaphore *sem)
 {
-       unsigned int sum = 0;
-       int cpu;
+       if (per_cpu_sum(*sem->read_count) != 0)
+               return false;
+
+       /*
+        * If we observed the decrement; ensure we see the entire critical
+        * section.
+        */
 
-       for_each_possible_cpu(cpu) {
-               sum += per_cpu(*brw->fast_read_ctr, cpu);
-               per_cpu(*brw->fast_read_ctr, cpu) = 0;
-       }
+       smp_mb(); /* C matches B */
 
-       return sum;
+       return true;
 }
 
-void percpu_down_write(struct percpu_rw_semaphore *brw)
+void percpu_down_write(struct percpu_rw_semaphore *sem)
 {
+       /* Notify readers to take the slow path. */
+       rcu_sync_enter(&sem->rss);
+
+       down_write(&sem->rw_sem);
+
        /*
-        * Make rcu_sync_is_idle() == F and thus disable the fast-path in
-        * percpu_down_read() and percpu_up_read(), and wait for gp pass.
-        *
-        * The latter synchronises us with the preceding readers which used
-        * the fast-past, so we can not miss the result of __this_cpu_add()
-        * or anything else inside their criticial sections.
+        * Notify new readers to block; up until now, and thus throughout the
+        * longish rcu_sync_enter() above, new readers could still come in.
         */
-       rcu_sync_enter(&brw->rss);
+       WRITE_ONCE(sem->readers_block, 1);
 
-       /* exclude other writers, and block the new readers completely */
-       down_write(&brw->rw_sem);
+       smp_mb(); /* D matches A */
 
-       /* nobody can use fast_read_ctr, move its sum into slow_read_ctr */
-       atomic_add(clear_fast_ctr(brw), &brw->slow_read_ctr);
+       /*
+        * If they don't see our writer of readers_block, then we are
+        * guaranteed to see their sem->read_count increment, and therefore
+        * will wait for them.
+        */
 
-       /* wait for all readers to complete their percpu_up_read() */
-       wait_event(brw->write_waitq, !atomic_read(&brw->slow_read_ctr));
+       /* Wait for all now active readers to complete. */
+       wait_event(sem->writer, readers_active_check(sem));
 }
 EXPORT_SYMBOL_GPL(percpu_down_write);
 
-void percpu_up_write(struct percpu_rw_semaphore *brw)
+void percpu_up_write(struct percpu_rw_semaphore *sem)
 {
-       /* release the lock, but the readers can't use the fast-path */
-       up_write(&brw->rw_sem);
        /*
-        * Enable the fast-path in percpu_down_read() and percpu_up_read()
-        * but only after another gp pass; this adds the necessary barrier
-        * to ensure the reader can't miss the changes done by us.
+        * Signal the writer is done, no fast path yet.
+        *
+        * One reason that we cannot just immediately flip to readers_fast is
+        * that new readers might fail to see the results of this writer's
+        * critical section.
+        *
+        * Therefore we force it through the slow path which guarantees an
+        * acquire and thereby guarantees the critical section's consistency.
+        */
+       smp_store_release(&sem->readers_block, 0);
+
+       /*
+        * Release the write lock, this will allow readers back in the game.
+        */
+       up_write(&sem->rw_sem);
+
+       /*
+        * Once this completes (at least one RCU-sched grace period hence) the
+        * reader fast path will be available again. Safe to use outside the
+        * exclusive write lock because its counting.
         */
-       rcu_sync_exit(&brw->rss);
+       rcu_sync_exit(&sem->rss);
 }
 EXPORT_SYMBOL_GPL(percpu_up_write);
index 0e5c71195f185c667f875ab54b0ac022eadd519c..b14a4f31221f36bf5af471d7dcfc7935f0f68375 100644 (file)
@@ -2606,13 +2606,18 @@ static inline void kmemleak_load_module(const struct module *mod,
 #endif
 
 #ifdef CONFIG_MODULE_SIG
-static int module_sig_check(struct load_info *info)
+static int module_sig_check(struct load_info *info, int flags)
 {
        int err = -ENOKEY;
        const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
        const void *mod = info->hdr;
 
-       if (info->len > markerlen &&
+       /*
+        * Require flags == 0, as a module with version information
+        * removed is no longer the module that was signed
+        */
+       if (flags == 0 &&
+           info->len > markerlen &&
            memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
                /* We truncate the module to discard the signature */
                info->len -= markerlen;
@@ -2631,7 +2636,7 @@ static int module_sig_check(struct load_info *info)
        return err;
 }
 #else /* !CONFIG_MODULE_SIG */
-static int module_sig_check(struct load_info *info)
+static int module_sig_check(struct load_info *info, int flags)
 {
        return 0;
 }
@@ -3444,7 +3449,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
        long err;
        char *after_dashes;
 
-       err = module_sig_check(info);
+       err = module_sig_check(info, flags);
        if (err)
                goto free_copy;
 
index 223564d3e1f8b61b9a1b8396961cd93dd426a6d7..41e2b54f36b5cdc73ecbda53a246662ba541ba57 100644 (file)
@@ -28,9 +28,6 @@
 #define PANIC_TIMER_STEP 100
 #define PANIC_BLINK_SPD 18
 
-/* Machine specific panic information string */
-char *mach_panic_string;
-
 int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE;
 static unsigned long tainted_mask;
 static int pause_on_oops;
@@ -415,11 +412,6 @@ late_initcall(init_oops_id);
 void print_oops_end_marker(void)
 {
        init_oops_id();
-
-       if (mach_panic_string)
-               printk(KERN_WARNING "Board Information: %s\n",
-                      mach_panic_string);
-
        pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id);
 }
 
index b7dd5718836e2b76c0c0700251bae66364e72da8..3124cebaec31e182e3705f4dd94fc7a33b654158 100644 (file)
@@ -299,12 +299,12 @@ static int create_image(int platform_mode)
        save_processor_state();
        trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
        error = swsusp_arch_suspend();
+       /* Restore control flow magically appears here */
+       restore_processor_state();
        trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
        if (error)
                printk(KERN_ERR "PM: Error %d creating hibernation image\n",
                        error);
-       /* Restore control flow magically appears here */
-       restore_processor_state();
        if (!in_suspend)
                events_check_enabled = false;
 
index 3a970604308ff5365f431e8190d1b82f7ac306d1..f155c62f1f2c993952597c4ba0ceb4c27a48c9d1 100644 (file)
@@ -765,9 +765,9 @@ static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn)
  */
 static bool rtree_next_node(struct memory_bitmap *bm)
 {
-       bm->cur.node = list_entry(bm->cur.node->list.next,
-                                 struct rtree_node, list);
-       if (&bm->cur.node->list != &bm->cur.zone->leaves) {
+       if (!list_is_last(&bm->cur.node->list, &bm->cur.zone->leaves)) {
+               bm->cur.node = list_entry(bm->cur.node->list.next,
+                                         struct rtree_node, list);
                bm->cur.node_pfn += BM_BITS_PER_BLOCK;
                bm->cur.node_bit  = 0;
                touch_softlockup_watchdog();
@@ -775,9 +775,9 @@ static bool rtree_next_node(struct memory_bitmap *bm)
        }
 
        /* No more nodes, goto next zone */
-       bm->cur.zone = list_entry(bm->cur.zone->list.next,
+       if (!list_is_last(&bm->cur.zone->list, &bm->zones)) {
+               bm->cur.zone = list_entry(bm->cur.zone->list.next,
                                  struct mem_zone_bm_rtree, list);
-       if (&bm->cur.zone->list != &bm->zones) {
                bm->cur.node = list_entry(bm->cur.zone->leaves.next,
                                          struct rtree_node, list);
                bm->cur.node_pfn = 0;
index 276762f3a46078141117e5810c1afc964e869ec9..d5760c42f042f4accfb65de23784bcaa877d9b00 100644 (file)
@@ -9,10 +9,10 @@
 
 char *_braille_console_setup(char **str, char **brl_options)
 {
-       if (!memcmp(*str, "brl,", 4)) {
+       if (!strncmp(*str, "brl,", 4)) {
                *brl_options = "";
                *str += 4;
-       } else if (!memcmp(str, "brl=", 4)) {
+       } else if (!strncmp(*str, "brl=", 4)) {
                *brl_options = *str + 4;
                *str = strchr(*brl_options, ',');
                if (!*str)
index be922c9f3d37256fc060d5b9ba0aaf6a2d1f085c..b49cf3ac2d475a40a0558abed478dad5908ec376 100644 (file)
@@ -68,6 +68,7 @@ void rcu_sync_lockdep_assert(struct rcu_sync *rsp)
        RCU_LOCKDEP_WARN(!gp_ops[rsp->gp_type].held(),
                         "suspicious rcu_sync_is_idle() usage");
 }
+EXPORT_SYMBOL_GPL(rcu_sync_lockdep_assert);
 #endif
 
 /**
@@ -82,6 +83,18 @@ void rcu_sync_init(struct rcu_sync *rsp, enum rcu_sync_type type)
        rsp->gp_type = type;
 }
 
+/**
+ * Must be called after rcu_sync_init() and before first use.
+ *
+ * Ensures rcu_sync_is_idle() returns false and rcu_sync_{enter,exit}()
+ * pairs turn into NO-OPs.
+ */
+void rcu_sync_enter_start(struct rcu_sync *rsp)
+{
+       rsp->gp_count++;
+       rsp->gp_state = GP_PASSED;
+}
+
 /**
  * rcu_sync_enter() - Force readers onto slowpath
  * @rsp: Pointer to rcu_sync structure to use for synchronization
index c6a85f813dfda2798a0ceadfd8066b082afae1c9..dc93f1cffc6e0f31b9d97d4076dca53245cf6655 100644 (file)
@@ -14,7 +14,8 @@ endif
 obj-y += core.o loadavg.o clock.o cputime.o
 obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o energy.o
 obj-y += wait.o completion.o idle.o
-obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o
+obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o energy.o
+obj-$(CONFIG_SCHED_WALT) += walt.o
 obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
 obj-$(CONFIG_SCHEDSTATS) += stats.o
 obj-$(CONFIG_SCHED_DEBUG) += debug.o
index a94f6424103cfea44386685b9818df4c6e385420..1df6da0094f01448ff477f6c1b963b2b6c80c8f6 100644 (file)
@@ -89,6 +89,7 @@
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/sched.h>
+#include "walt.h"
 
 DEFINE_MUTEX(sched_domains_mutex);
 DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
@@ -287,6 +288,18 @@ int sysctl_sched_rt_runtime = 950000;
 /* cpus with isolated domains */
 cpumask_var_t cpu_isolated_map;
 
+struct rq *
+lock_rq_of(struct task_struct *p, unsigned long *flags)
+{
+       return task_rq_lock(p, flags);
+}
+
+void
+unlock_rq_of(struct rq *rq, struct task_struct *p, unsigned long *flags)
+{
+       task_rq_unlock(rq, p, flags);
+}
+
 /*
  * this_rq_lock - lock this runqueue and disable interrupts.
  */
@@ -627,7 +640,10 @@ int get_nohz_timer_target(void)
        rcu_read_lock();
        for_each_domain(cpu, sd) {
                for_each_cpu(i, sched_domain_span(sd)) {
-                       if (!idle_cpu(i) && is_housekeeping_cpu(cpu)) {
+                       if (cpu == i)
+                               continue;
+
+                       if (!idle_cpu(i) && is_housekeeping_cpu(i)) {
                                cpu = i;
                                goto unlock;
                        }
@@ -1073,7 +1089,9 @@ static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int new
 
        dequeue_task(rq, p, 0);
        p->on_rq = TASK_ON_RQ_MIGRATING;
+       double_lock_balance(rq, cpu_rq(new_cpu));
        set_task_cpu(p, new_cpu);
+       double_unlock_balance(rq, cpu_rq(new_cpu));
        raw_spin_unlock(&rq->lock);
 
        rq = cpu_rq(new_cpu);
@@ -1297,6 +1315,8 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
                        p->sched_class->migrate_task_rq(p);
                p->se.nr_migrations++;
                perf_event_task_migrate(p);
+
+               walt_fixup_busy_time(p, new_cpu);
        }
 
        __set_task_cpu(p, new_cpu);
@@ -1925,6 +1945,10 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
 {
        unsigned long flags;
        int cpu, success = 0;
+#ifdef CONFIG_SMP
+       struct rq *rq;
+       u64 wallclock;
+#endif
 
        /*
         * If we are going to wake up a thread waiting for CONDITION we
@@ -1942,6 +1966,28 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
        success = 1; /* we're going to change ->state */
        cpu = task_cpu(p);
 
+       /*
+        * Ensure we load p->on_rq _after_ p->state, otherwise it would
+        * be possible to, falsely, observe p->on_rq == 0 and get stuck
+        * in smp_cond_load_acquire() below.
+        *
+        * sched_ttwu_pending()                 try_to_wake_up()
+        *   [S] p->on_rq = 1;                  [L] P->state
+        *       UNLOCK rq->lock  -----.
+        *                              \
+        *                               +---   RMB
+        * schedule()                   /
+        *       LOCK rq->lock    -----'
+        *       UNLOCK rq->lock
+        *
+        * [task p]
+        *   [S] p->state = UNINTERRUPTIBLE     [L] p->on_rq
+        *
+        * Pairs with the UNLOCK+LOCK on rq->lock from the
+        * last wakeup of our task and the schedule that got our task
+        * current.
+        */
+       smp_rmb();
        if (p->on_rq && ttwu_remote(p, wake_flags))
                goto stat;
 
@@ -1982,6 +2028,14 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
         */
        smp_rmb();
 
+       rq = cpu_rq(task_cpu(p));
+
+       raw_spin_lock(&rq->lock);
+       wallclock = walt_ktime_clock();
+       walt_update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
+       walt_update_task_ravg(p, rq, TASK_WAKE, wallclock, 0);
+       raw_spin_unlock(&rq->lock);
+
        p->sched_contributes_to_load = !!task_contributes_to_load(p);
        p->state = TASK_WAKING;
 
@@ -1989,10 +2043,12 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
                p->sched_class->task_waking(p);
 
        cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags);
+
        if (task_cpu(p) != cpu) {
                wake_flags |= WF_MIGRATED;
                set_task_cpu(p, cpu);
        }
+
 #endif /* CONFIG_SMP */
 
        ttwu_queue(p, cpu);
@@ -2041,8 +2097,13 @@ static void try_to_wake_up_local(struct task_struct *p)
 
        trace_sched_waking(p);
 
-       if (!task_on_rq_queued(p))
+       if (!task_on_rq_queued(p)) {
+               u64 wallclock = walt_ktime_clock();
+
+               walt_update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0);
+               walt_update_task_ravg(p, rq, TASK_WAKE, wallclock, 0);
                ttwu_activate(rq, p, ENQUEUE_WAKEUP);
+       }
 
        ttwu_do_wakeup(rq, p, 0);
        ttwu_stat(p, smp_processor_id(), 0);
@@ -2108,6 +2169,7 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
        p->se.nr_migrations             = 0;
        p->se.vruntime                  = 0;
        INIT_LIST_HEAD(&p->se.group_node);
+       walt_init_new_task_load(p);
 
 #ifdef CONFIG_SCHEDSTATS
        memset(&p->se.statistics, 0, sizeof(p->se.statistics));
@@ -2375,6 +2437,9 @@ void wake_up_new_task(struct task_struct *p)
        struct rq *rq;
 
        raw_spin_lock_irqsave(&p->pi_lock, flags);
+
+       walt_init_new_task_load(p);
+
        /* Initialize new task's runnable average */
        init_entity_runnable_average(&p->se);
 #ifdef CONFIG_SMP
@@ -2387,6 +2452,7 @@ void wake_up_new_task(struct task_struct *p)
 #endif
 
        rq = __task_rq_lock(p);
+       walt_mark_task_starting(p);
        activate_task(rq, p, ENQUEUE_WAKEUP_NEW);
        p->on_rq = TASK_ON_RQ_QUEUED;
        trace_sched_wakeup_new(p);
@@ -2768,6 +2834,36 @@ unsigned long nr_iowait_cpu(int cpu)
        return atomic_read(&this->nr_iowait);
 }
 
+#ifdef CONFIG_CPU_QUIET
+u64 nr_running_integral(unsigned int cpu)
+{
+       unsigned int seqcnt;
+       u64 integral;
+       struct rq *q;
+
+       if (cpu >= nr_cpu_ids)
+               return 0;
+
+       q = cpu_rq(cpu);
+
+       /*
+        * Update average to avoid reading stalled value if there were
+        * no run-queue changes for a long time. On the other hand if
+        * the changes are happening right now, just read current value
+        * directly.
+        */
+
+       seqcnt = read_seqcount_begin(&q->ave_seqcnt);
+       integral = do_nr_running_integral(q);
+       if (read_seqcount_retry(&q->ave_seqcnt, seqcnt)) {
+               read_seqcount_begin(&q->ave_seqcnt);
+               integral = q->nr_running_integral;
+       }
+
+       return integral;
+}
+#endif
+
 void get_iowait_load(unsigned long *nr_waiters, unsigned long *load)
 {
        struct rq *rq = this_rq();
@@ -2855,20 +2951,76 @@ unsigned long long task_sched_runtime(struct task_struct *p)
 }
 
 #ifdef CONFIG_CPU_FREQ_GOV_SCHED
-static unsigned long sum_capacity_reqs(unsigned long cfs_cap,
-                                      struct sched_capacity_reqs *scr)
+
+static inline
+unsigned long add_capacity_margin(unsigned long cpu_capacity)
 {
-       unsigned long total = cfs_cap + scr->rt;
+       cpu_capacity  = cpu_capacity * capacity_margin;
+       cpu_capacity /= SCHED_CAPACITY_SCALE;
+       return cpu_capacity;
+}
 
-       total = total * capacity_margin;
-       total /= SCHED_CAPACITY_SCALE;
-       total += scr->dl;
-       return total;
+static inline
+unsigned long sum_capacity_reqs(unsigned long cfs_cap,
+                               struct sched_capacity_reqs *scr)
+{
+       unsigned long total = add_capacity_margin(cfs_cap + scr->rt);
+       return total += scr->dl;
 }
 
-static void sched_freq_tick(int cpu)
+static void sched_freq_tick_pelt(int cpu)
 {
+       unsigned long cpu_utilization = capacity_max;
+       unsigned long capacity_curr = capacity_curr_of(cpu);
        struct sched_capacity_reqs *scr;
+
+       scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
+       if (sum_capacity_reqs(cpu_utilization, scr) < capacity_curr)
+               return;
+
+       /*
+        * To make free room for a task that is building up its "real"
+        * utilization and to harm its performance the least, request
+        * a jump to a higher OPP as soon as the margin of free capacity
+        * is impacted (specified by capacity_margin).
+        */
+       set_cfs_cpu_capacity(cpu, true, cpu_utilization);
+}
+
+#ifdef CONFIG_SCHED_WALT
+static void sched_freq_tick_walt(int cpu)
+{
+       unsigned long cpu_utilization = cpu_util(cpu);
+       unsigned long capacity_curr = capacity_curr_of(cpu);
+
+       if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
+               return sched_freq_tick_pelt(cpu);
+
+       /*
+        * Add a margin to the WALT utilization.
+        * NOTE: WALT tracks a single CPU signal for all the scheduling
+        * classes, thus this margin is going to be added to the DL class as
+        * well, which is something we do not do in sched_freq_tick_pelt case.
+        */
+       cpu_utilization = add_capacity_margin(cpu_utilization);
+       if (cpu_utilization <= capacity_curr)
+               return;
+
+       /*
+        * It is likely that the load is growing so we
+        * keep the added margin in our request as an
+        * extra boost.
+        */
+       set_cfs_cpu_capacity(cpu, true, cpu_utilization);
+
+}
+#define _sched_freq_tick(cpu) sched_freq_tick_walt(cpu)
+#else
+#define _sched_freq_tick(cpu) sched_freq_tick_pelt(cpu)
+#endif /* CONFIG_SCHED_WALT */
+
+static void sched_freq_tick(int cpu)
+{
        unsigned long capacity_orig, capacity_curr;
 
        if (!sched_freq())
@@ -2879,19 +3031,11 @@ static void sched_freq_tick(int cpu)
        if (capacity_curr == capacity_orig)
                return;
 
-       /*
-        * To make free room for a task that is building up its "real"
-        * utilization and to harm its performance the least, request
-        * a jump to max OPP as soon as the margin of free capacity is
-        * impacted (specified by capacity_margin).
-        */
-       scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
-       if (capacity_curr < sum_capacity_reqs(cpu_util(cpu), scr))
-               set_cfs_cpu_capacity(cpu, true, capacity_max);
+       _sched_freq_tick(cpu);
 }
 #else
 static inline void sched_freq_tick(int cpu) { }
-#endif
+#endif /* CONFIG_CPU_FREQ_GOV_SCHED */
 
 /*
  * This function gets called by the timer code, with HZ frequency.
@@ -2906,9 +3050,12 @@ void scheduler_tick(void)
        sched_clock_tick();
 
        raw_spin_lock(&rq->lock);
+       walt_set_window_start(rq);
        update_rq_clock(rq);
        curr->sched_class->task_tick(rq, curr, 0);
        update_cpu_load_active(rq);
+       walt_update_task_ravg(rq->curr, rq, TASK_UPDATE,
+                       walt_ktime_clock(), 0);
        calc_global_load_tick(rq);
        sched_freq_tick(cpu);
        raw_spin_unlock(&rq->lock);
@@ -3147,6 +3294,7 @@ static void __sched notrace __schedule(bool preempt)
        unsigned long *switch_count;
        struct rq *rq;
        int cpu;
+       u64 wallclock;
 
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
@@ -3208,6 +3356,9 @@ static void __sched notrace __schedule(bool preempt)
                update_rq_clock(rq);
 
        next = pick_next_task(rq, prev);
+       wallclock = walt_ktime_clock();
+       walt_update_task_ravg(prev, rq, PUT_PREV_TASK, wallclock, 0);
+       walt_update_task_ravg(next, rq, PICK_NEXT_TASK, wallclock, 0);
        clear_tsk_need_resched(prev);
        clear_preempt_need_resched();
        rq->clock_skip_update = 0;
@@ -4991,14 +5142,16 @@ void show_state_filter(unsigned long state_filter)
                /*
                 * reset the NMI-timeout, listing all files on a slow
                 * console might take a lot of time:
+                * Also, reset softlockup watchdogs on all CPUs, because
+                * another CPU might be blocked waiting for us to process
+                * an IPI.
                 */
                touch_nmi_watchdog();
+               touch_all_softlockup_watchdogs();
                if (!state_filter || (p->state & state_filter))
                        sched_show_task(p);
        }
 
-       touch_all_softlockup_watchdogs();
-
 #ifdef CONFIG_SCHED_DEBUG
        sysrq_sched_debug_show();
 #endif
@@ -5032,6 +5185,7 @@ void init_idle(struct task_struct *idle, int cpu)
        raw_spin_lock(&rq->lock);
 
        __sched_fork(0, idle);
+
        idle->state = TASK_RUNNING;
        idle->se.exec_start = sched_clock();
 
@@ -5628,6 +5782,9 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
        switch (action & ~CPU_TASKS_FROZEN) {
 
        case CPU_UP_PREPARE:
+               raw_spin_lock_irqsave(&rq->lock, flags);
+               walt_set_window_start(rq);
+               raw_spin_unlock_irqrestore(&rq->lock, flags);
                rq->calc_load_update = calc_load_update;
                account_reset_rq(rq);
                break;
@@ -5648,6 +5805,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                sched_ttwu_pending();
                /* Update our root-domain */
                raw_spin_lock_irqsave(&rq->lock, flags);
+               walt_migrate_sync_cpu(cpu);
                if (rq->rd) {
                        BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
                        set_rq_offline(rq);
@@ -7492,6 +7650,7 @@ void __init sched_init_smp(void)
 {
        cpumask_var_t non_isolated_cpus;
 
+       walt_init_cpu_efficiency();
        alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL);
        alloc_cpumask_var(&fallback_doms, GFP_KERNEL);
 
@@ -7669,6 +7828,11 @@ void __init sched_init(void)
                rq->idle_stamp = 0;
                rq->avg_idle = 2*sysctl_sched_migration_cost;
                rq->max_idle_balance_cost = sysctl_sched_migration_cost;
+#ifdef CONFIG_SCHED_WALT
+               rq->cur_irqload = 0;
+               rq->avg_irqload = 0;
+               rq->irqload_ts = 0;
+#endif
 
                INIT_LIST_HEAD(&rq->cfs_tasks);
 
@@ -8792,7 +8956,6 @@ struct cgroup_subsys cpu_cgrp_subsys = {
        .fork           = cpu_cgroup_fork,
        .can_attach     = cpu_cgroup_can_attach,
        .attach         = cpu_cgroup_attach,
-       .allow_attach   = subsys_cgroup_allow_attach,
        .legacy_cftypes = cpu_files,
        .early_init     = 1,
 };
index e1d208e101ed86ab6c835867a7cac9ed97b07d6c..f6f9b9b3a4a8367a2753c82b27a373a73b3f3ddd 100644 (file)
@@ -19,7 +19,8 @@
 
 #include "sched.h"
 
-#define THROTTLE_NSEC          50000000 /* 50ms default */
+#define THROTTLE_DOWN_NSEC     50000000 /* 50ms default */
+#define THROTTLE_UP_NSEC       500000 /* 500us default */
 
 struct static_key __read_mostly __sched_freq = STATIC_KEY_INIT_FALSE;
 static bool __read_mostly cpufreq_driver_slow;
@@ -33,8 +34,10 @@ DEFINE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
 
 /**
  * gov_data - per-policy data internal to the governor
- * @throttle: next throttling period expiry. Derived from throttle_nsec
- * @throttle_nsec: throttle period length in nanoseconds
+ * @up_throttle: next throttling period expiry if increasing OPP
+ * @down_throttle: next throttling period expiry if decreasing OPP
+ * @up_throttle_nsec: throttle period length in nanoseconds if increasing OPP
+ * @down_throttle_nsec: throttle period length in nanoseconds if decreasing OPP
  * @task: worker thread for dvfs transition that may block/sleep
  * @irq_work: callback used to wake up worker thread
  * @requested_freq: last frequency requested by the sched governor
@@ -48,8 +51,10 @@ DEFINE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
  * call down_write(policy->rwsem).
  */
 struct gov_data {
-       ktime_t throttle;
-       unsigned int throttle_nsec;
+       ktime_t up_throttle;
+       ktime_t down_throttle;
+       unsigned int up_throttle_nsec;
+       unsigned int down_throttle_nsec;
        struct task_struct *task;
        struct irq_work irq_work;
        unsigned int requested_freq;
@@ -66,25 +71,29 @@ static void cpufreq_sched_try_driver_target(struct cpufreq_policy *policy,
 
        __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
 
-       gd->throttle = ktime_add_ns(ktime_get(), gd->throttle_nsec);
+       gd->up_throttle = ktime_add_ns(ktime_get(), gd->up_throttle_nsec);
+       gd->down_throttle = ktime_add_ns(ktime_get(), gd->down_throttle_nsec);
        up_write(&policy->rwsem);
 }
 
-static bool finish_last_request(struct gov_data *gd)
+static bool finish_last_request(struct gov_data *gd, unsigned int cur_freq)
 {
        ktime_t now = ktime_get();
 
-       if (ktime_after(now, gd->throttle))
+       ktime_t throttle = gd->requested_freq < cur_freq ?
+               gd->down_throttle : gd->up_throttle;
+
+       if (ktime_after(now, throttle))
                return false;
 
        while (1) {
-               int usec_left = ktime_to_ns(ktime_sub(gd->throttle, now));
+               int usec_left = ktime_to_ns(ktime_sub(throttle, now));
 
                usec_left /= NSEC_PER_USEC;
                trace_cpufreq_sched_throttled(usec_left);
                usleep_range(usec_left, usec_left + 100);
                now = ktime_get();
-               if (ktime_after(now, gd->throttle))
+               if (ktime_after(now, throttle))
                        return true;
        }
 }
@@ -122,13 +131,15 @@ static int cpufreq_sched_thread(void *data)
                new_request = gd->requested_freq;
                if (new_request == last_request) {
                        set_current_state(TASK_INTERRUPTIBLE);
+                       if (kthread_should_stop())
+                               break;
                        schedule();
                } else {
                        /*
                         * if the frequency thread sleeps while waiting to be
                         * unthrottled, start over to check for a newer request
                         */
-                       if (finish_last_request(gd))
+                       if (finish_last_request(gd, policy->cur))
                                continue;
                        last_request = new_request;
                        cpufreq_sched_try_driver_target(policy, new_request);
@@ -190,9 +201,14 @@ static void update_fdomain_capacity_request(int cpu)
                goto out;
        freq_new = policy->freq_table[index_new].frequency;
 
+       if (freq_new > policy->max)
+               freq_new = policy->max;
+
+       if (freq_new < policy->min)
+               freq_new = policy->min;
+
        trace_cpufreq_sched_request_opp(cpu, capacity, freq_new,
                                        gd->requested_freq);
-
        if (freq_new == gd->requested_freq)
                goto out;
 
@@ -246,10 +262,17 @@ static inline void clear_sched_freq(void)
        static_key_slow_dec(&__sched_freq);
 }
 
+static struct attribute_group sched_attr_group_gov_pol;
+static struct attribute_group *get_sysfs_attr(void)
+{
+       return &sched_attr_group_gov_pol;
+}
+
 static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
 {
        struct gov_data *gd;
        int cpu;
+       int rc;
 
        for_each_cpu(cpu, policy->cpus)
                memset(&per_cpu(cpu_sched_capacity_reqs, cpu), 0,
@@ -259,12 +282,20 @@ static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
        if (!gd)
                return -ENOMEM;
 
-       gd->throttle_nsec = policy->cpuinfo.transition_latency ?
+       gd->up_throttle_nsec = policy->cpuinfo.transition_latency ?
                            policy->cpuinfo.transition_latency :
-                           THROTTLE_NSEC;
+                           THROTTLE_UP_NSEC;
+       gd->down_throttle_nsec = THROTTLE_DOWN_NSEC;
        pr_debug("%s: throttle threshold = %u [ns]\n",
-                 __func__, gd->throttle_nsec);
+                 __func__, gd->up_throttle_nsec);
+
+       rc = sysfs_create_group(get_governor_parent_kobj(policy), get_sysfs_attr());
+       if (rc) {
+               pr_err("%s: couldn't create sysfs attributes: %d\n", __func__, rc);
+               goto err;
+       }
 
+       policy->governor_data = gd;
        if (cpufreq_driver_is_slow()) {
                cpufreq_driver_slow = true;
                gd->task = kthread_create(cpufreq_sched_thread, policy,
@@ -281,12 +312,12 @@ static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
                init_irq_work(&gd->irq_work, cpufreq_sched_irq_work);
        }
 
-       policy->governor_data = gd;
        set_sched_freq();
 
        return 0;
 
 err:
+       policy->governor_data = NULL;
        kfree(gd);
        return -ENOMEM;
 }
@@ -301,6 +332,8 @@ static int cpufreq_sched_policy_exit(struct cpufreq_policy *policy)
                put_task_struct(gd->task);
        }
 
+       sysfs_remove_group(get_governor_parent_kobj(policy), get_sysfs_attr());
+
        policy->governor_data = NULL;
 
        kfree(gd);
@@ -317,6 +350,21 @@ static int cpufreq_sched_start(struct cpufreq_policy *policy)
        return 0;
 }
 
+static void cpufreq_sched_limits(struct cpufreq_policy *policy)
+{
+       unsigned int clamp_freq;
+       struct gov_data *gd = policy->governor_data;;
+
+       pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
+               policy->cpu, policy->min, policy->max,
+               policy->cur);
+
+       clamp_freq = clamp(gd->requested_freq, policy->min, policy->max);
+
+       if (policy->cur != clamp_freq)
+               __cpufreq_driver_target(policy, clamp_freq, CPUFREQ_RELATION_L);
+}
+
 static int cpufreq_sched_stop(struct cpufreq_policy *policy)
 {
        int cpu;
@@ -340,11 +388,95 @@ static int cpufreq_sched_setup(struct cpufreq_policy *policy,
        case CPUFREQ_GOV_STOP:
                return cpufreq_sched_stop(policy);
        case CPUFREQ_GOV_LIMITS:
+               cpufreq_sched_limits(policy);
                break;
        }
        return 0;
 }
 
+/* Tunables */
+static ssize_t show_up_throttle_nsec(struct gov_data *gd, char *buf)
+{
+       return sprintf(buf, "%u\n", gd->up_throttle_nsec);
+}
+
+static ssize_t store_up_throttle_nsec(struct gov_data *gd,
+               const char *buf, size_t count)
+{
+       int ret;
+       long unsigned int val;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+       gd->up_throttle_nsec = val;
+       return count;
+}
+
+static ssize_t show_down_throttle_nsec(struct gov_data *gd, char *buf)
+{
+       return sprintf(buf, "%u\n", gd->down_throttle_nsec);
+}
+
+static ssize_t store_down_throttle_nsec(struct gov_data *gd,
+               const char *buf, size_t count)
+{
+       int ret;
+       long unsigned int val;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+       gd->down_throttle_nsec = val;
+       return count;
+}
+
+/*
+ * Create show/store routines
+ * - sys: One governor instance for complete SYSTEM
+ * - pol: One governor instance per struct cpufreq_policy
+ */
+#define show_gov_pol_sys(file_name)                                    \
+static ssize_t show_##file_name##_gov_pol                              \
+(struct cpufreq_policy *policy, char *buf)                             \
+{                                                                      \
+       return show_##file_name(policy->governor_data, buf);            \
+}
+
+#define store_gov_pol_sys(file_name)                                   \
+static ssize_t store_##file_name##_gov_pol                             \
+(struct cpufreq_policy *policy, const char *buf, size_t count)         \
+{                                                                      \
+       return store_##file_name(policy->governor_data, buf, count);    \
+}
+
+#define gov_pol_attr_rw(_name)                                         \
+       static struct freq_attr _name##_gov_pol =                               \
+       __ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
+
+#define show_store_gov_pol_sys(file_name)                              \
+       show_gov_pol_sys(file_name);                                            \
+       store_gov_pol_sys(file_name)
+#define tunable_handlers(file_name) \
+       show_gov_pol_sys(file_name); \
+       store_gov_pol_sys(file_name); \
+       gov_pol_attr_rw(file_name)
+
+tunable_handlers(down_throttle_nsec);
+tunable_handlers(up_throttle_nsec);
+
+/* Per policy governor instance */
+static struct attribute *sched_attributes_gov_pol[] = {
+       &up_throttle_nsec_gov_pol.attr,
+       &down_throttle_nsec_gov_pol.attr,
+       NULL,
+};
+
+static struct attribute_group sched_attr_group_gov_pol = {
+       .attrs = sched_attributes_gov_pol,
+       .name = "sched",
+};
+
 #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
 static
 #endif
index f74ea89e77a8e5aa5faf8abf6c2f1132a92de397..acde1d7c763ceeafdcb6cd0f009c95adccda6332 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/static_key.h>
 #include <linux/context_tracking.h>
 #include "sched.h"
+#include "walt.h"
 
 
 #ifdef CONFIG_IRQ_TIME_ACCOUNTING
@@ -49,6 +50,10 @@ void irqtime_account_irq(struct task_struct *curr)
        unsigned long flags;
        s64 delta;
        int cpu;
+#ifdef CONFIG_SCHED_WALT
+       u64 wallclock;
+       bool account = true;
+#endif
 
        if (!sched_clock_irqtime)
                return;
@@ -56,6 +61,9 @@ void irqtime_account_irq(struct task_struct *curr)
        local_irq_save(flags);
 
        cpu = smp_processor_id();
+#ifdef CONFIG_SCHED_WALT
+       wallclock = sched_clock_cpu(cpu);
+#endif
        delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time);
        __this_cpu_add(irq_start_time, delta);
 
@@ -70,8 +78,16 @@ void irqtime_account_irq(struct task_struct *curr)
                __this_cpu_add(cpu_hardirq_time, delta);
        else if (in_serving_softirq() && curr != this_cpu_ksoftirqd())
                __this_cpu_add(cpu_softirq_time, delta);
+#ifdef CONFIG_SCHED_WALT
+       else
+               account = false;
+#endif
 
        irq_time_write_end();
+#ifdef CONFIG_SCHED_WALT
+       if (account)
+               walt_account_irqtime(cpu, curr, delta, wallclock);
+#endif
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(irqtime_account_irq);
@@ -600,19 +616,25 @@ static void cputime_adjust(struct task_cputime *curr,
        stime = curr->stime;
        utime = curr->utime;
 
-       if (utime == 0) {
-               stime = rtime;
+       /*
+        * If either stime or both stime and utime are 0, assume all runtime is
+        * userspace. Once a task gets some ticks, the monotonicy code at
+        * 'update' will ensure things converge to the observed ratio.
+        */
+       if (stime == 0) {
+               utime = rtime;
                goto update;
        }
 
-       if (stime == 0) {
-               utime = rtime;
+       if (utime == 0) {
+               stime = rtime;
                goto update;
        }
 
        stime = scale_stime((__force u64)stime, (__force u64)rtime,
                            (__force u64)(stime + utime));
 
+update:
        /*
         * Make sure stime doesn't go backwards; this preserves monotonicity
         * for utime because rtime is monotonic.
@@ -635,7 +657,6 @@ static void cputime_adjust(struct task_cputime *curr,
                stime = rtime - utime;
        }
 
-update:
        prev->stime = stime;
        prev->utime = utime;
 out:
index 3217494e326efd6c19305f593bc0606b8a640ae8..d5965cfbd3d729595644ecc84363c7af925f865d 100644 (file)
 #include <linux/mempolicy.h>
 #include <linux/migrate.h>
 #include <linux/task_work.h>
+#include <linux/module.h>
 
 #include <trace/events/sched.h>
 
 #include "sched.h"
 #include "tune.h"
+#include "walt.h"
 
 /*
  * Targeted preemption latency for CPU-bound tasks:
 unsigned int sysctl_sched_latency = 6000000ULL;
 unsigned int normalized_sysctl_sched_latency = 6000000ULL;
 
+unsigned int sysctl_sched_is_big_little = 0;
+unsigned int sysctl_sched_sync_hint_enable = 1;
+unsigned int sysctl_sched_initial_task_util = 0;
+unsigned int sysctl_sched_cstate_aware = 1;
+
+#ifdef CONFIG_SCHED_WALT
+unsigned int sysctl_sched_use_walt_cpu_util = 1;
+unsigned int sysctl_sched_use_walt_task_util = 1;
+__read_mostly unsigned int sysctl_sched_walt_cpu_high_irqload =
+    (10 * NSEC_PER_MSEC);
+#endif
 /*
  * The initial- and re-scaling of tunables is configurable
  * (default SCHED_TUNABLESCALING_LOG = *(1+ilog(ncpus))
@@ -683,13 +696,13 @@ void init_entity_runnable_average(struct sched_entity *se)
        sa->period_contrib = 1023;
        sa->load_avg = scale_load_down(se->load.weight);
        sa->load_sum = sa->load_avg * LOAD_AVG_MAX;
-       sa->util_avg = scale_load_down(SCHED_LOAD_SCALE);
+       sa->util_avg =  sched_freq() ?
+               sysctl_sched_initial_task_util :
+               scale_load_down(SCHED_LOAD_SCALE);
        sa->util_sum = sa->util_avg * LOAD_AVG_MAX;
        /* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
 }
 
-static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq);
-static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq);
 #else
 void init_entity_runnable_average(struct sched_entity *se)
 {
@@ -1194,8 +1207,6 @@ static void task_numa_assign(struct task_numa_env *env,
 {
        if (env->best_task)
                put_task_struct(env->best_task);
-       if (p)
-               get_task_struct(p);
 
        env->best_task = p;
        env->best_imp = imp;
@@ -1263,20 +1274,30 @@ static void task_numa_compare(struct task_numa_env *env,
        long imp = env->p->numa_group ? groupimp : taskimp;
        long moveimp = imp;
        int dist = env->dist;
+       bool assigned = false;
 
        rcu_read_lock();
 
        raw_spin_lock_irq(&dst_rq->lock);
        cur = dst_rq->curr;
        /*
-        * No need to move the exiting task, and this ensures that ->curr
-        * wasn't reaped and thus get_task_struct() in task_numa_assign()
-        * is safe under RCU read lock.
-        * Note that rcu_read_lock() itself can't protect from the final
-        * put_task_struct() after the last schedule().
+        * No need to move the exiting task or idle task.
         */
        if ((cur->flags & PF_EXITING) || is_idle_task(cur))
                cur = NULL;
+       else {
+               /*
+                * The task_struct must be protected here to protect the
+                * p->numa_faults access in the task_weight since the
+                * numa_faults could already be freed in the following path:
+                * finish_task_switch()
+                *     --> put_task_struct()
+                *         --> __put_task_struct()
+                *             --> task_numa_free()
+                */
+               get_task_struct(cur);
+       }
+
        raw_spin_unlock_irq(&dst_rq->lock);
 
        /*
@@ -1360,6 +1381,7 @@ balance:
                 */
                if (!load_too_imbalanced(src_load, dst_load, env)) {
                        imp = moveimp - 1;
+                       put_task_struct(cur);
                        cur = NULL;
                        goto assign;
                }
@@ -1385,9 +1407,16 @@ balance:
                env->dst_cpu = select_idle_sibling(env->p, env->dst_cpu);
 
 assign:
+       assigned = true;
        task_numa_assign(env, cur, imp);
 unlock:
        rcu_read_unlock();
+       /*
+        * The dst_rq->curr isn't assigned. The protection for task_struct is
+        * finished.
+        */
+       if (cur && !assigned)
+               put_task_struct(cur);
 }
 
 static void task_numa_find_cpu(struct task_numa_env *env,
@@ -4168,8 +4197,14 @@ static inline void hrtick_update(struct rq *rq)
 }
 #endif
 
+#ifdef CONFIG_SMP
+static bool cpu_overutilized(int cpu);
 static inline unsigned long boosted_cpu_util(int cpu);
+#else
+#define boosted_cpu_util(cpu) cpu_util(cpu)
+#endif
 
+#ifdef CONFIG_SMP
 static void update_capacity_of(int cpu)
 {
        unsigned long req_cap;
@@ -4182,8 +4217,7 @@ static void update_capacity_of(int cpu)
        req_cap = req_cap * SCHED_CAPACITY_SCALE / capacity_orig_of(cpu);
        set_cfs_cpu_capacity(cpu, true, req_cap);
 }
-
-static bool cpu_overutilized(int cpu);
+#endif
 
 /*
  * The enqueue_task method is called before nr_running is
@@ -4195,8 +4229,10 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
 {
        struct cfs_rq *cfs_rq;
        struct sched_entity *se = &p->se;
+#ifdef CONFIG_SMP
        int task_new = flags & ENQUEUE_WAKEUP_NEW;
        int task_wakeup = flags & ENQUEUE_WAKEUP;
+#endif
 
        for_each_sched_entity(se) {
                if (se->on_rq)
@@ -4213,6 +4249,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                if (cfs_rq_throttled(cfs_rq))
                        break;
                cfs_rq->h_nr_running++;
+               walt_inc_cfs_cumulative_runnable_avg(cfs_rq, p);
 
                flags = ENQUEUE_WAKEUP;
        }
@@ -4220,6 +4257,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
                cfs_rq->h_nr_running++;
+               walt_inc_cfs_cumulative_runnable_avg(cfs_rq, p);
 
                if (cfs_rq_throttled(cfs_rq))
                        break;
@@ -4228,13 +4266,37 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                update_cfs_shares(cfs_rq);
        }
 
-       if (!se) {
+       if (!se)
                add_nr_running(rq, 1);
+
+#ifdef CONFIG_SMP
+
+       /*
+        * Update SchedTune accounting.
+        *
+        * We do it before updating the CPU capacity to ensure the
+        * boost value of the current task is accounted for in the
+        * selection of the OPP.
+        *
+        * We do it also in the case where we enqueue a throttled task;
+        * we could argue that a throttled task should not boost a CPU,
+        * however:
+        * a) properly implementing CPU boosting considering throttled
+        *    tasks will increase a lot the complexity of the solution
+        * b) it's not easy to quantify the benefits introduced by
+        *    such a more complex solution.
+        * Thus, for the time being we go for the simple solution and boost
+        * also for throttled RQs.
+        */
+       schedtune_enqueue_task(p, cpu_of(rq));
+
+       if (!se) {
+               walt_inc_cumulative_runnable_avg(rq, p);
                if (!task_new && !rq->rd->overutilized &&
-                   cpu_overutilized(rq->cpu))
+                   cpu_overutilized(rq->cpu)) {
                        rq->rd->overutilized = true;
-
-               schedtune_enqueue_task(p, cpu_of(rq));
+                       trace_sched_overutilized(true);
+               }
 
                /*
                 * We want to potentially trigger a freq switch
@@ -4246,6 +4308,8 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                if (task_new || task_wakeup)
                        update_capacity_of(cpu_of(rq));
        }
+
+#endif /* CONFIG_SMP */
        hrtick_update(rq);
 }
 
@@ -4275,6 +4339,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                if (cfs_rq_throttled(cfs_rq))
                        break;
                cfs_rq->h_nr_running--;
+               walt_dec_cfs_cumulative_runnable_avg(cfs_rq, p);
 
                /* Don't dequeue parent if it has other entities besides us */
                if (cfs_rq->load.weight) {
@@ -4295,6 +4360,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
                cfs_rq->h_nr_running--;
+               walt_dec_cfs_cumulative_runnable_avg(cfs_rq, p);
 
                if (cfs_rq_throttled(cfs_rq))
                        break;
@@ -4303,9 +4369,22 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                update_cfs_shares(cfs_rq);
        }
 
-       if (!se) {
+       if (!se)
                sub_nr_running(rq, 1);
-               schedtune_dequeue_task(p, cpu_of(rq));
+
+#ifdef CONFIG_SMP
+
+       /*
+        * Update SchedTune accounting
+        *
+        * We do it before updating the CPU capacity to ensure the
+        * boost value of the current task is accounted for in the
+        * selection of the OPP.
+        */
+       schedtune_dequeue_task(p, cpu_of(rq));
+
+       if (!se) {
+               walt_dec_cumulative_runnable_avg(rq, p);
 
                /*
                 * We want to potentially trigger a freq switch
@@ -4322,6 +4401,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                                set_cfs_cpu_capacity(cpu_of(rq), false, 0);
                }
        }
+
+#endif /* CONFIG_SMP */
+
        hrtick_update(rq);
 }
 
@@ -4660,19 +4742,24 @@ static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
                return wl;
 
        for_each_sched_entity(se) {
-               long w, W;
+               struct cfs_rq *cfs_rq = se->my_q;
+               long W, w = cfs_rq_load_avg(cfs_rq);
 
-               tg = se->my_q->tg;
+               tg = cfs_rq->tg;
 
                /*
                 * W = @wg + \Sum rw_j
                 */
-               W = wg + calc_tg_weight(tg, se->my_q);
+               W = wg + atomic_long_read(&tg->load_avg);
+
+               /* Ensure \Sum rw_j >= rw_i */
+               W -= cfs_rq->tg_load_avg_contrib;
+               W += w;
 
                /*
                 * w = rw_i + @wl
                 */
-               w = cfs_rq_load_avg(se->my_q) + wl;
+               w += wl;
 
                /*
                 * wl = S * s'_i; see (2)
@@ -4954,6 +5041,7 @@ static int sched_group_energy(struct energy_env *eenv)
                        } while (sg = sg->next, sg != sd->groups);
                }
 next_cpu:
+               cpumask_clear_cpu(cpu, &visit_cpus);
                continue;
        }
 
@@ -4966,44 +5054,6 @@ static inline bool cpu_in_sg(struct sched_group *sg, int cpu)
        return cpu != -1 && cpumask_test_cpu(cpu, sched_group_cpus(sg));
 }
 
-#ifdef CONFIG_SCHED_TUNE
-static int energy_diff_evaluate(struct energy_env *eenv)
-{
-       unsigned int boost;
-       int nrg_delta;
-
-       /* Return energy diff when boost margin is 0 */
-#ifdef CONFIG_CGROUP_SCHEDTUNE
-       boost = schedtune_task_boost(eenv->task);
-#else
-       boost = get_sysctl_sched_cfs_boost();
-#endif
-       if (boost == 0)
-               return eenv->nrg.diff;
-
-       /* Compute normalized energy diff */
-       nrg_delta = schedtune_normalize_energy(eenv->nrg.diff);
-       eenv->nrg.delta = nrg_delta;
-
-       eenv->payoff = schedtune_accept_deltas(
-                       eenv->nrg.delta,
-                       eenv->cap.delta,
-                       eenv->task);
-
-       /*
-        * When SchedTune is enabled, the energy_diff() function will return
-        * the computed energy payoff value. Since the energy_diff() return
-        * value is expected to be negative by its callers, this evaluation
-        * function return a negative value each time the evaluation return a
-        * positive payoff, which is the condition for the acceptance of
-        * a scheduling decision
-        */
-       return -eenv->payoff;
-}
-#else /* CONFIG_SCHED_TUNE */
-#define energy_diff_evaluate(eenv) eenv->nrg.diff
-#endif
-
 /*
  * energy_diff(): Estimate the energy impact of changing the utilization
  * distribution. eenv specifies the change: utilisation amount, source, and
@@ -5011,7 +5061,7 @@ static int energy_diff_evaluate(struct energy_env *eenv)
  * utilization is removed from or added to the system (e.g. task wake-up). If
  * both are specified, the utilization is migrated.
  */
-static inenergy_diff(struct energy_env *eenv)
+static inline int __energy_diff(struct energy_env *eenv)
 {
        struct sched_domain *sd;
        struct sched_group *sg;
@@ -5059,9 +5109,86 @@ static int energy_diff(struct energy_env *eenv)
        eenv->nrg.diff = eenv->nrg.after - eenv->nrg.before;
        eenv->payoff = 0;
 
-       return energy_diff_evaluate(eenv);
+       trace_sched_energy_diff(eenv->task,
+                       eenv->src_cpu, eenv->dst_cpu, eenv->util_delta,
+                       eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff,
+                       eenv->cap.before, eenv->cap.after, eenv->cap.delta,
+                       eenv->nrg.delta, eenv->payoff);
+
+       return eenv->nrg.diff;
 }
 
+#ifdef CONFIG_SCHED_TUNE
+
+struct target_nrg schedtune_target_nrg;
+
+/*
+ * System energy normalization
+ * Returns the normalized value, in the range [0..SCHED_LOAD_SCALE],
+ * corresponding to the specified energy variation.
+ */
+static inline int
+normalize_energy(int energy_diff)
+{
+       u32 normalized_nrg;
+#ifdef CONFIG_SCHED_DEBUG
+       int max_delta;
+
+       /* Check for boundaries */
+       max_delta  = schedtune_target_nrg.max_power;
+       max_delta -= schedtune_target_nrg.min_power;
+       WARN_ON(abs(energy_diff) >= max_delta);
+#endif
+
+       /* Do scaling using positive numbers to increase the range */
+       normalized_nrg = (energy_diff < 0) ? -energy_diff : energy_diff;
+
+       /* Scale by energy magnitude */
+       normalized_nrg <<= SCHED_LOAD_SHIFT;
+
+       /* Normalize on max energy for target platform */
+       normalized_nrg = reciprocal_divide(
+                       normalized_nrg, schedtune_target_nrg.rdiv);
+
+       return (energy_diff < 0) ? -normalized_nrg : normalized_nrg;
+}
+
+static inline int
+energy_diff(struct energy_env *eenv)
+{
+       int boost = schedtune_task_boost(eenv->task);
+       int nrg_delta;
+
+       /* Conpute "absolute" energy diff */
+       __energy_diff(eenv);
+
+       /* Return energy diff when boost margin is 0 */
+       if (boost == 0)
+               return eenv->nrg.diff;
+
+       /* Compute normalized energy diff */
+       nrg_delta = normalize_energy(eenv->nrg.diff);
+       eenv->nrg.delta = nrg_delta;
+
+       eenv->payoff = schedtune_accept_deltas(
+                       eenv->nrg.delta,
+                       eenv->cap.delta,
+                       eenv->task);
+
+       /*
+        * When SchedTune is enabled, the energy_diff() function will return
+        * the computed energy payoff value. Since the energy_diff() return
+        * value is expected to be negative by its callers, this evaluation
+        * function return a negative value each time the evaluation return a
+        * positive payoff, which is the condition for the acceptance of
+        * a scheduling decision
+        */
+       return -eenv->payoff;
+}
+#else /* CONFIG_SCHED_TUNE */
+#define energy_diff(eenv) __energy_diff(eenv)
+#endif
+
 /*
  * Detect M:N waker/wakee relationships via a switching-frequency heuristic.
  * A waker of many should wake a different task than the one last awakened
@@ -5155,6 +5282,12 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 
 static inline unsigned long task_util(struct task_struct *p)
 {
+#ifdef CONFIG_SCHED_WALT
+       if (!walt_disabled && sysctl_sched_use_walt_task_util) {
+               unsigned long demand = p->ravg.demand;
+               return (demand << 10) / walt_ravg_window;
+       }
+#endif
        return p->se.avg.util_avg;
 }
 
@@ -5197,22 +5330,25 @@ static bool cpu_overutilized(int cpu)
 
 #ifdef CONFIG_SCHED_TUNE
 
-static unsigned long
-schedtune_margin(unsigned long signal, unsigned long boost)
+static long
+schedtune_margin(unsigned long signal, long boost)
 {
-       unsigned long long margin = 0;
+       long long margin = 0;
 
        /*
         * Signal proportional compensation (SPC)
         *
         * The Boost (B) value is used to compute a Margin (M) which is
         * proportional to the complement of the original Signal (S):
-        *   M = B * (SCHED_LOAD_SCALE - S)
+        *   M = B * (SCHED_LOAD_SCALE - S), if B is positive
+        *   M = B * S, if B is negative
         * The obtained M could be used by the caller to "boost" S.
         */
-       margin  = SCHED_LOAD_SCALE - signal;
-       margin *= boost;
-
+       if (boost >= 0) {
+               margin  = SCHED_LOAD_SCALE - signal;
+               margin *= boost;
+       } else
+               margin = -signal * boost;
        /*
         * Fast integer division by constant:
         *  Constant   :                 (C) = 100
@@ -5228,37 +5364,29 @@ schedtune_margin(unsigned long signal, unsigned long boost)
        margin  *= 1311;
        margin >>= 17;
 
+       if (boost < 0)
+               margin *= -1;
        return margin;
 }
 
-static inline unsigned int
+static inline int
 schedtune_cpu_margin(unsigned long util, int cpu)
 {
-       unsigned int boost;
+       int boost = schedtune_cpu_boost(cpu);
 
-#ifdef CONFIG_CGROUP_SCHEDTUNE
-       boost = schedtune_cpu_boost(cpu);
-#else
-       boost = get_sysctl_sched_cfs_boost();
-#endif
        if (boost == 0)
                return 0;
 
        return schedtune_margin(util, boost);
 }
 
-static inline unsigned long
+static inline long
 schedtune_task_margin(struct task_struct *task)
 {
-       unsigned int boost;
+       int boost = schedtune_task_boost(task);
        unsigned long util;
-       unsigned long margin;
+       long margin;
 
-#ifdef CONFIG_CGROUP_SCHEDTUNE
-       boost = schedtune_task_boost(task);
-#else
-       boost = get_sysctl_sched_cfs_boost();
-#endif
        if (boost == 0)
                return 0;
 
@@ -5270,13 +5398,13 @@ schedtune_task_margin(struct task_struct *task)
 
 #else /* CONFIG_SCHED_TUNE */
 
-static inline unsigned int
+static inline int
 schedtune_cpu_margin(unsigned long util, int cpu)
 {
        return 0;
 }
 
-static inline unsigned int
+static inline int
 schedtune_task_margin(struct task_struct *task)
 {
        return 0;
@@ -5288,7 +5416,7 @@ static inline unsigned long
 boosted_cpu_util(int cpu)
 {
        unsigned long util = cpu_util(cpu);
-       unsigned long margin = schedtune_cpu_margin(util, cpu);
+       long margin = schedtune_cpu_margin(util, cpu);
 
        trace_sched_boost_cpu(cpu, util, margin);
 
@@ -5299,7 +5427,9 @@ static inline unsigned long
 boosted_task_util(struct task_struct *task)
 {
        unsigned long util = task_util(task);
-       unsigned long margin = schedtune_task_margin(task);
+       long margin = schedtune_task_margin(task);
+
+       trace_sched_boost_task(task, util, margin);
 
        return util + margin;
 }
@@ -5455,15 +5585,20 @@ static int select_idle_sibling(struct task_struct *p, int target)
        struct sched_domain *sd;
        struct sched_group *sg;
        int i = task_cpu(p);
+       int best_idle = -1;
+       int best_idle_cstate = -1;
+       int best_idle_capacity = INT_MAX;
 
-       if (idle_cpu(target))
-               return target;
+       if (!sysctl_sched_cstate_aware) {
+               if (idle_cpu(target))
+                       return target;
 
-       /*
-        * If the prevous cpu is cache affine and idle, don't be stupid.
-        */
-       if (i != target && cpus_share_cache(i, target) && idle_cpu(i))
-               return i;
+               /*
+                * If the prevous cpu is cache affine and idle, don't be stupid.
+                */
+               if (i != target && cpus_share_cache(i, target) && idle_cpu(i))
+                       return i;
+       }
 
        /*
         * Otherwise, iterate the domains and find an elegible idle cpu.
@@ -5476,30 +5611,165 @@ static int select_idle_sibling(struct task_struct *p, int target)
                                                tsk_cpus_allowed(p)))
                                goto next;
 
-                       for_each_cpu(i, sched_group_cpus(sg)) {
-                               if (i == target || !idle_cpu(i))
-                                       goto next;
-                       }
+                       if (sysctl_sched_cstate_aware) {
+                               for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg)) {
+                                       struct rq *rq = cpu_rq(i);
+                                       int idle_idx = idle_get_state_idx(rq);
+                                       unsigned long new_usage = boosted_task_util(p);
+                                       unsigned long capacity_orig = capacity_orig_of(i);
+                                       if (new_usage > capacity_orig || !idle_cpu(i))
+                                               goto next;
+
+                                       if (i == target && new_usage <= capacity_curr_of(target))
+                                               return target;
+
+                                       if (best_idle < 0 || (idle_idx < best_idle_cstate && capacity_orig <= best_idle_capacity)) {
+                                               best_idle = i;
+                                               best_idle_cstate = idle_idx;
+                                               best_idle_capacity = capacity_orig;
+                                       }
+                               }
+                       } else {
+                               for_each_cpu(i, sched_group_cpus(sg)) {
+                                       if (i == target || !idle_cpu(i))
+                                               goto next;
+                               }
 
-                       target = cpumask_first_and(sched_group_cpus(sg),
+                               target = cpumask_first_and(sched_group_cpus(sg),
                                        tsk_cpus_allowed(p));
-                       goto done;
+                               goto done;
+                       }
 next:
                        sg = sg->next;
                } while (sg != sd->groups);
        }
+       if (best_idle > 0)
+               target = best_idle;
+
 done:
        return target;
 }
 
-static int energy_aware_wake_cpu(struct task_struct *p, int target)
+static inline int find_best_target(struct task_struct *p, bool boosted, bool prefer_idle)
+{
+       int iter_cpu;
+       int target_cpu = -1;
+       int target_util = 0;
+       int backup_capacity = 0;
+       int best_idle_cpu = -1;
+       int best_idle_cstate = INT_MAX;
+       int backup_cpu = -1;
+       unsigned long task_util_boosted, new_util;
+
+       task_util_boosted = boosted_task_util(p);
+       for (iter_cpu = 0; iter_cpu < NR_CPUS; iter_cpu++) {
+               int cur_capacity;
+               struct rq *rq;
+               int idle_idx;
+
+               /*
+                * Iterate from higher cpus for boosted tasks.
+                */
+               int i = boosted ? NR_CPUS-iter_cpu-1 : iter_cpu;
+
+               if (!cpu_online(i) || !cpumask_test_cpu(i, tsk_cpus_allowed(p)))
+                       continue;
+
+               /*
+                * p's blocked utilization is still accounted for on prev_cpu
+                * so prev_cpu will receive a negative bias due to the double
+                * accounting. However, the blocked utilization may be zero.
+                */
+               new_util = cpu_util(i) + task_util_boosted;
+
+               /*
+                * Ensure minimum capacity to grant the required boost.
+                * The target CPU can be already at a capacity level higher
+                * than the one required to boost the task.
+                */
+               if (new_util > capacity_orig_of(i))
+                       continue;
+
+#ifdef CONFIG_SCHED_WALT
+               if (walt_cpu_high_irqload(i))
+                       continue;
+#endif
+               /*
+                * Unconditionally favoring tasks that prefer idle cpus to
+                * improve latency.
+                */
+               if (idle_cpu(i) && prefer_idle) {
+                       if (best_idle_cpu < 0)
+                               best_idle_cpu = i;
+                       continue;
+               }
+
+               cur_capacity = capacity_curr_of(i);
+               rq = cpu_rq(i);
+               idle_idx = idle_get_state_idx(rq);
+
+               if (new_util < cur_capacity) {
+                       if (cpu_rq(i)->nr_running) {
+                               if (prefer_idle) {
+                                       /* Find a target cpu with highest
+                                        * utilization.
+                                        */
+                                       if (target_util == 0 ||
+                                               target_util < new_util) {
+                                               target_cpu = i;
+                                               target_util = new_util;
+                                       }
+                               } else {
+                                       /* Find a target cpu with lowest
+                                        * utilization.
+                                        */
+                                       if (target_util == 0 ||
+                                               target_util > new_util) {
+                                               target_cpu = i;
+                                               target_util = new_util;
+                                       }
+                               }
+                       } else if (!prefer_idle) {
+                               if (best_idle_cpu < 0 ||
+                                       (sysctl_sched_cstate_aware &&
+                                               best_idle_cstate > idle_idx)) {
+                                       best_idle_cstate = idle_idx;
+                                       best_idle_cpu = i;
+                               }
+                       }
+               } else if (backup_capacity == 0 ||
+                               backup_capacity > cur_capacity) {
+                       // Find a backup cpu with least capacity.
+                       backup_capacity = cur_capacity;
+                       backup_cpu = i;
+               }
+       }
+
+       if (prefer_idle && best_idle_cpu >= 0)
+               target_cpu = best_idle_cpu;
+       else if (target_cpu < 0)
+               target_cpu = best_idle_cpu >= 0 ? best_idle_cpu : backup_cpu;
+
+       return target_cpu;
+}
+
+static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync)
 {
        struct sched_domain *sd;
        struct sched_group *sg, *sg_target;
        int target_max_cap = INT_MAX;
        int target_cpu = task_cpu(p);
+       unsigned long task_util_boosted, new_util;
        int i;
 
+       if (sysctl_sched_sync_hint_enable && sync) {
+               int cpu = smp_processor_id();
+               cpumask_t search_cpus;
+               cpumask_and(&search_cpus, tsk_cpus_allowed(p), cpu_online_mask);
+               if (cpumask_test_cpu(cpu, &search_cpus))
+                       return cpu;
+       }
+
        sd = rcu_dereference(per_cpu(sd_ea, task_cpu(p)));
 
        if (!sd)
@@ -5508,50 +5778,76 @@ static int energy_aware_wake_cpu(struct task_struct *p, int target)
        sg = sd->groups;
        sg_target = sg;
 
-       /*
-        * Find group with sufficient capacity. We only get here if no cpu is
-        * overutilized. We may end up overutilizing a cpu by adding the task,
-        * but that should not be any worse than select_idle_sibling().
-        * load_balance() should sort it out later as we get above the tipping
-        * point.
-        */
-       do {
-               /* Assuming all cpus are the same in group */
-               int max_cap_cpu = group_first_cpu(sg);
+       if (sysctl_sched_is_big_little) {
 
                /*
-                * Assume smaller max capacity means more energy-efficient.
-                * Ideally we should query the energy model for the right
-                * answer but it easily ends up in an exhaustive search.
+                * Find group with sufficient capacity. We only get here if no cpu is
+                * overutilized. We may end up overutilizing a cpu by adding the task,
+                * but that should not be any worse than select_idle_sibling().
+                * load_balance() should sort it out later as we get above the tipping
+                * point.
                 */
-               if (capacity_of(max_cap_cpu) < target_max_cap &&
-                   task_fits_max(p, max_cap_cpu)) {
-                       sg_target = sg;
-                       target_max_cap = capacity_of(max_cap_cpu);
-               }
-       } while (sg = sg->next, sg != sd->groups);
+               do {
+                       /* Assuming all cpus are the same in group */
+                       int max_cap_cpu = group_first_cpu(sg);
 
-       /* Find cpu with sufficient capacity */
-       for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg_target)) {
-               /*
-                * p's blocked utilization is still accounted for on prev_cpu
-                * so prev_cpu will receive a negative bias due to the double
-                * accounting. However, the blocked utilization may be zero.
-                */
-               int new_util = cpu_util(i) + boosted_task_util(p);
+                       /*
+                        * Assume smaller max capacity means more energy-efficient.
+                        * Ideally we should query the energy model for the right
+                        * answer but it easily ends up in an exhaustive search.
+                        */
+                       if (capacity_of(max_cap_cpu) < target_max_cap &&
+                           task_fits_max(p, max_cap_cpu)) {
+                               sg_target = sg;
+                               target_max_cap = capacity_of(max_cap_cpu);
+                       }
+               } while (sg = sg->next, sg != sd->groups);
 
-               if (new_util > capacity_orig_of(i))
-                       continue;
+               task_util_boosted = boosted_task_util(p);
+               /* Find cpu with sufficient capacity */
+               for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg_target)) {
+                       /*
+                        * p's blocked utilization is still accounted for on prev_cpu
+                        * so prev_cpu will receive a negative bias due to the double
+                        * accounting. However, the blocked utilization may be zero.
+                        */
+                       new_util = cpu_util(i) + task_util_boosted;
 
-               if (new_util < capacity_curr_of(i)) {
-                       target_cpu = i;
-                       if (cpu_rq(i)->nr_running)
-                               break;
-               }
+                       /*
+                        * Ensure minimum capacity to grant the required boost.
+                        * The target CPU can be already at a capacity level higher
+                        * than the one required to boost the task.
+                        */
+                       if (new_util > capacity_orig_of(i))
+                               continue;
+
+                       if (new_util < capacity_curr_of(i)) {
+                               target_cpu = i;
+                               if (cpu_rq(i)->nr_running)
+                                       break;
+                       }
 
-               /* cpu has capacity at higher OPP, keep it as fallback */
-               if (target_cpu == task_cpu(p))
-                       target_cpu = i;
+                       /* cpu has capacity at higher OPP, keep it as fallback */
+                       if (target_cpu == task_cpu(p))
+                               target_cpu = i;
+               }
+       } else {
+               /*
+                * Find a cpu with sufficient capacity
+                */
+#ifdef CONFIG_CGROUP_SCHEDTUNE
+               bool boosted = schedtune_task_boost(p) > 0;
+               bool prefer_idle = schedtune_prefer_idle(p) > 0;
+#else
+               bool boosted = 0;
+               bool prefer_idle = 0;
+#endif
+               int tmp_target = find_best_target(p, boosted, prefer_idle);
+               if (tmp_target >= 0) {
+                       target_cpu = tmp_target;
+                       if ((boosted || prefer_idle) && idle_cpu(target_cpu))
+                               return target_cpu;
+               }
        }
 
        if (target_cpu != task_cpu(p)) {
@@ -5628,7 +5924,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
 
        if (!sd) {
                if (energy_aware() && !cpu_rq(cpu)->rd->overutilized)
-                       new_cpu = energy_aware_wake_cpu(p, prev_cpu);
+                       new_cpu = energy_aware_wake_cpu(p, prev_cpu, sync);
                else if (sd_flag & SD_BALANCE_WAKE) /* XXX always ? */
                        new_cpu = select_idle_sibling(p, new_cpu);
 
@@ -5699,6 +5995,8 @@ static void task_dead_fair(struct task_struct *p)
 {
        remove_entity_load_avg(&p->se);
 }
+#else
+#define task_fits_max(p, cpu) true
 #endif /* CONFIG_SMP */
 
 static unsigned long
@@ -6404,7 +6702,9 @@ static void detach_task(struct task_struct *p, struct lb_env *env)
 
        deactivate_task(env->src_rq, p, 0);
        p->on_rq = TASK_ON_RQ_MIGRATING;
+       double_lock_balance(env->src_rq, env->dst_rq);
        set_task_cpu(p, env->dst_cpu);
+       double_unlock_balance(env->src_rq, env->dst_rq);
 }
 
 /*
@@ -6825,7 +7125,10 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu)
                mcc->cpu = cpu;
 #ifdef CONFIG_SCHED_DEBUG
                raw_spin_unlock_irqrestore(&mcc->lock, flags);
-               //pr_info("CPU%d: update max cpu_capacity %lu\n", cpu, capacity);
+/*
+               printk_deferred(KERN_INFO "CPU%d: update max cpu_capacity %lu\n",
+                               cpu, capacity);
+*/
                goto skip_unlock;
 #endif
        }
@@ -7048,7 +7351,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                        bool *overload, bool *overutilized)
 {
        unsigned long load;
-       int i;
+       int i, nr_running;
 
        memset(sgs, 0, sizeof(*sgs));
 
@@ -7065,7 +7368,8 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                sgs->group_util += cpu_util(i);
                sgs->sum_nr_running += rq->cfs.h_nr_running;
 
-               if (rq->nr_running > 1)
+               nr_running = rq->nr_running;
+               if (nr_running > 1)
                        *overload = true;
 
 #ifdef CONFIG_NUMA_BALANCING
@@ -7073,7 +7377,10 @@ static inline void update_sg_lb_stats(struct lb_env *env,
                sgs->nr_preferred_running += rq->nr_preferred_running;
 #endif
                sgs->sum_weighted_load += weighted_cpuload(i);
-               if (idle_cpu(i))
+               /*
+                * No need to call idle_cpu() if nr_running is not 0
+                */
+               if (!nr_running && idle_cpu(i))
                        sgs->idle_cpus++;
 
                if (cpu_overutilized(i)) {
@@ -7279,12 +7586,17 @@ next_group:
                        env->dst_rq->rd->overload = overload;
 
                /* Update over-utilization (tipping point, U >= 0) indicator */
-               if (env->dst_rq->rd->overutilized != overutilized)
+               if (env->dst_rq->rd->overutilized != overutilized) {
                        env->dst_rq->rd->overutilized = overutilized;
+                       trace_sched_overutilized(overutilized);
+               }
        } else {
-               if (!env->dst_rq->rd->overutilized && overutilized)
+               if (!env->dst_rq->rd->overutilized && overutilized) {
                        env->dst_rq->rd->overutilized = true;
+                       trace_sched_overutilized(true);
+               }
        }
+
 }
 
 /**
@@ -8078,6 +8390,7 @@ static int idle_balance(struct rq *this_rq)
        struct sched_domain *sd;
        int pulled_task = 0;
        u64 curr_cost = 0;
+       long removed_util=0;
 
        idle_enter_fair(this_rq);
 
@@ -8101,6 +8414,17 @@ static int idle_balance(struct rq *this_rq)
 
        raw_spin_unlock(&this_rq->lock);
 
+       /*
+        * If removed_util_avg is !0 we most probably migrated some task away
+        * from this_cpu. In this case we might be willing to trigger an OPP
+        * update, but we want to do so if we don't find anybody else to pull
+        * here (we will trigger an OPP update with the pulled task's enqueue
+        * anyway).
+        *
+        * Record removed_util before calling update_blocked_averages, and use
+        * it below (before returning) to see if an OPP update is required.
+        */
+       removed_util = atomic_long_read(&(this_rq->cfs).removed_util_avg);
        update_blocked_averages(this_cpu);
        rcu_read_lock();
        for_each_domain(this_cpu, sd) {
@@ -8165,6 +8489,12 @@ out:
        if (pulled_task) {
                idle_exit_fair(this_rq);
                this_rq->idle_stamp = 0;
+       } else if (removed_util) {
+               /*
+                * No task pulled and someone has been migrated away.
+                * Good case to trigger an OPP update.
+                */
+               update_capacity_of(this_cpu);
        }
 
        return pulled_task;
@@ -8723,10 +9053,15 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
        if (static_branch_unlikely(&sched_numa_balancing))
                task_tick_numa(rq, curr);
 
-       if (!rq->rd->overutilized && cpu_overutilized(task_cpu(curr)))
+#ifdef CONFIG_SMP
+       if (!rq->rd->overutilized && cpu_overutilized(task_cpu(curr))) {
                rq->rd->overutilized = true;
+               trace_sched_overutilized(true);
+       }
 
        rq->misfit_task = !task_fits_max(curr, rq->cpu);
+#endif
+
 }
 
 /*
index b634151ce286851a4802a8e3316222f9efa1d62a..55e461055332971c2d5b0e9a036b462050d57144 100644 (file)
@@ -73,4 +73,8 @@ SCHED_FEAT(ATTACH_AGE_LOAD, true)
  * Energy aware scheduling. Use platform energy model to guide scheduling
  * decisions optimizing for energy efficiency.
  */
+#ifdef CONFIG_DEFAULT_USE_ENERGY_AWARE
+SCHED_FEAT(ENERGY_AWARE, true)
+#else
 SCHED_FEAT(ENERGY_AWARE, false)
+#endif
index cbc130efbc5bc6a63ced39f4f1325e7d81c0ec79..917c94abf5bbaebfb332f2df17f85fcf2bfc1cfa 100644 (file)
@@ -220,6 +220,7 @@ static void cpu_idle_loop(void)
                 */
 
                __current_set_polling();
+               quiet_vmstat();
                tick_nohz_idle_enter();
 
                while (!need_resched()) {
index 9694204660b7e7c4a29e070252cda0dd9e6007d6..8a16cba968c43c981b0e2671a5e1e2d6cc8e341a 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/slab.h>
 #include <linux/irq_work.h>
 
+#include "walt.h"
+
 int sched_rr_timeslice = RR_TIMESLICE;
 
 static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun);
@@ -889,6 +891,51 @@ static inline int rt_se_prio(struct sched_rt_entity *rt_se)
        return rt_task_of(rt_se)->prio;
 }
 
+static void dump_throttled_rt_tasks(struct rt_rq *rt_rq)
+{
+       struct rt_prio_array *array = &rt_rq->active;
+       struct sched_rt_entity *rt_se;
+       char buf[500];
+       char *pos = buf;
+       char *end = buf + sizeof(buf);
+       int idx;
+
+       pos += snprintf(pos, sizeof(buf),
+               "sched: RT throttling activated for rt_rq %p (cpu %d)\n",
+               rt_rq, cpu_of(rq_of_rt_rq(rt_rq)));
+
+       if (bitmap_empty(array->bitmap, MAX_RT_PRIO))
+               goto out;
+
+       pos += snprintf(pos, end - pos, "potential CPU hogs:\n");
+       idx = sched_find_first_bit(array->bitmap);
+       while (idx < MAX_RT_PRIO) {
+               list_for_each_entry(rt_se, array->queue + idx, run_list) {
+                       struct task_struct *p;
+
+                       if (!rt_entity_is_task(rt_se))
+                               continue;
+
+                       p = rt_task_of(rt_se);
+                       if (pos < end)
+                               pos += snprintf(pos, end - pos, "\t%s (%d)\n",
+                                       p->comm, p->pid);
+               }
+               idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx + 1);
+       }
+out:
+#ifdef CONFIG_PANIC_ON_RT_THROTTLING
+       /*
+        * Use pr_err() in the BUG() case since printk_sched() will
+        * not get flushed and deadlock is not a concern.
+        */
+       pr_err("%s", buf);
+       BUG();
+#else
+       printk_deferred("%s", buf);
+#endif
+}
+
 static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
 {
        u64 runtime = sched_rt_runtime(rt_rq);
@@ -912,8 +959,14 @@ static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
                 * but accrue some time due to boosting.
                 */
                if (likely(rt_b->rt_runtime)) {
+                       static bool once = false;
+
                        rt_rq->rt_throttled = 1;
-                       printk_deferred_once("sched: RT throttling activated\n");
+
+                       if (!once) {
+                               once = true;
+                               dump_throttled_rt_tasks(rt_rq);
+                       }
                } else {
                        /*
                         * In case we did anyway, make it go away,
@@ -1261,6 +1314,7 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags)
                rt_se->timeout = 0;
 
        enqueue_rt_entity(rt_se, flags & ENQUEUE_HEAD);
+       walt_inc_cumulative_runnable_avg(rq, p);
 
        if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
                enqueue_pushable_task(rq, p);
@@ -1272,6 +1326,7 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
 
        update_curr_rt(rq);
        dequeue_rt_entity(rt_se);
+       walt_dec_cumulative_runnable_avg(rq, p);
 
        dequeue_pushable_task(rq, p);
 }
index a537f1864dd08bad9b94563eeac44912da276f09..2f2b959ad24485ca8eaf2907b2fc66d58e04bc33 100644 (file)
@@ -410,6 +410,10 @@ struct cfs_rq {
        struct list_head leaf_cfs_rq_list;
        struct task_group *tg;  /* group that "owns" this runqueue */
 
+#ifdef CONFIG_SCHED_WALT
+       u64 cumulative_runnable_avg;
+#endif
+
 #ifdef CONFIG_CFS_BANDWIDTH
        int runtime_enabled;
        u64 runtime_expires;
@@ -594,6 +598,14 @@ struct rq {
 #ifdef CONFIG_NO_HZ_FULL
        unsigned long last_sched_tick;
 #endif
+
+#ifdef CONFIG_CPU_QUIET
+       /* time-based average load */
+       u64 nr_last_stamp;
+       u64 nr_running_integral;
+       seqcount_t ave_seqcnt;
+#endif
+
        /* capture load from *all* tasks on this cpu: */
        struct load_weight load;
        unsigned long nr_load_updates;
@@ -655,6 +667,30 @@ struct rq {
        u64 max_idle_balance_cost;
 #endif
 
+#ifdef CONFIG_SCHED_WALT
+       /*
+        * max_freq = user or thermal defined maximum
+        * max_possible_freq = maximum supported by hardware
+        */
+       unsigned int cur_freq, max_freq, min_freq, max_possible_freq;
+       struct cpumask freq_domain_cpumask;
+
+       u64 cumulative_runnable_avg;
+       int efficiency; /* Differentiate cpus with different IPC capability */
+       int load_scale_factor;
+       int capacity;
+       int max_possible_capacity;
+       u64 window_start;
+       u64 curr_runnable_sum;
+       u64 prev_runnable_sum;
+       u64 nt_curr_runnable_sum;
+       u64 nt_prev_runnable_sum;
+       u64 cur_irqload;
+       u64 avg_irqload;
+       u64 irqload_ts;
+#endif /* CONFIG_SCHED_WALT */
+
+
 #ifdef CONFIG_IRQ_TIME_ACCOUNTING
        u64 prev_irq_time;
 #endif
@@ -1269,6 +1305,7 @@ extern const struct sched_class idle_sched_class;
 
 #ifdef CONFIG_SMP
 
+extern void init_max_cpu_capacity(struct max_cpu_capacity *mcc);
 extern void update_group_capacity(struct sched_domain *sd, int cpu);
 
 extern void trigger_load_balance(struct rq *rq);
@@ -1351,9 +1388,7 @@ unsigned long to_ratio(u64 period, u64 runtime);
 
 extern void init_entity_runnable_average(struct sched_entity *se);
 
-extern void init_max_cpu_capacity(struct max_cpu_capacity *mcc);
-
-static inline void add_nr_running(struct rq *rq, unsigned count)
+static inline void __add_nr_running(struct rq *rq, unsigned count)
 {
        unsigned prev_nr = rq->nr_running;
 
@@ -1381,11 +1416,48 @@ static inline void add_nr_running(struct rq *rq, unsigned count)
        }
 }
 
-static inline void sub_nr_running(struct rq *rq, unsigned count)
+static inline void __sub_nr_running(struct rq *rq, unsigned count)
 {
        rq->nr_running -= count;
 }
 
+#ifdef CONFIG_CPU_QUIET
+#define NR_AVE_SCALE(x)                ((x) << FSHIFT)
+static inline u64 do_nr_running_integral(struct rq *rq)
+{
+       s64 nr, deltax;
+       u64 nr_running_integral = rq->nr_running_integral;
+
+       deltax = rq->clock_task - rq->nr_last_stamp;
+       nr = NR_AVE_SCALE(rq->nr_running);
+
+       nr_running_integral += nr * deltax;
+
+       return nr_running_integral;
+}
+
+static inline void add_nr_running(struct rq *rq, unsigned count)
+{
+       write_seqcount_begin(&rq->ave_seqcnt);
+       rq->nr_running_integral = do_nr_running_integral(rq);
+       rq->nr_last_stamp = rq->clock_task;
+       __add_nr_running(rq, count);
+       write_seqcount_end(&rq->ave_seqcnt);
+}
+
+static inline void sub_nr_running(struct rq *rq, unsigned count)
+{
+       write_seqcount_begin(&rq->ave_seqcnt);
+       rq->nr_running_integral = do_nr_running_integral(rq);
+       rq->nr_last_stamp = rq->clock_task;
+       __sub_nr_running(rq, count);
+       write_seqcount_end(&rq->ave_seqcnt);
+}
+#else
+#define add_nr_running __add_nr_running
+#define sub_nr_running __sub_nr_running
+#endif
+
 static inline void rq_last_tick_reset(struct rq *rq)
 {
 #ifdef CONFIG_NO_HZ_FULL
@@ -1469,6 +1541,10 @@ static inline unsigned long capacity_orig_of(int cpu)
        return cpu_rq(cpu)->cpu_capacity_orig;
 }
 
+extern unsigned int sysctl_sched_use_walt_cpu_util;
+extern unsigned int walt_ravg_window;
+extern unsigned int walt_disabled;
+
 /*
  * cpu_util returns the amount of capacity of a CPU that is used by CFS
  * tasks. The unit of the return value must be the one of capacity so we can
@@ -1500,6 +1576,12 @@ static inline unsigned long __cpu_util(int cpu, int delta)
        unsigned long util = cpu_rq(cpu)->cfs.avg.util_avg;
        unsigned long capacity = capacity_orig_of(cpu);
 
+#ifdef CONFIG_SCHED_WALT
+       if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
+               util = cpu_rq(cpu)->prev_runnable_sum << SCHED_LOAD_SHIFT;
+               do_div(util, walt_ravg_window);
+       }
+#endif
        delta += util;
        if (delta < 0)
                return 0;
@@ -1530,8 +1612,27 @@ void update_cpu_capacity_request(int cpu, bool request);
 static inline void set_cfs_cpu_capacity(int cpu, bool request,
                                        unsigned long capacity)
 {
-       if (per_cpu(cpu_sched_capacity_reqs, cpu).cfs != capacity) {
-               per_cpu(cpu_sched_capacity_reqs, cpu).cfs = capacity;
+       struct sched_capacity_reqs *scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
+
+#ifdef CONFIG_SCHED_WALT
+       if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
+               int rtdl = scr->rt + scr->dl;
+               /*
+                * WALT tracks the utilization of a CPU considering the load
+                * generated by all the scheduling classes.
+                * Since the following call to:
+                *    update_cpu_capacity
+                * is already adding the RT and DL utilizations let's remove
+                * these contributions from the WALT signal.
+                */
+               if (capacity > rtdl)
+                       capacity -= rtdl;
+               else
+                       capacity = 0;
+       }
+#endif
+       if (scr->cfs != capacity) {
+               scr->cfs = capacity;
                update_cpu_capacity_request(cpu, request);
        }
 }
@@ -1657,6 +1758,9 @@ task_rq_unlock(struct rq *rq, struct task_struct *p, unsigned long *flags)
        raw_spin_unlock_irqrestore(&p->pi_lock, *flags);
 }
 
+extern struct rq *lock_rq_of(struct task_struct *p, unsigned long *flags);
+extern void unlock_rq_of(struct rq *rq, struct task_struct *p, unsigned long *flags);
+
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PREEMPT
 
@@ -1729,7 +1833,8 @@ static inline int double_lock_balance(struct rq *this_rq, struct rq *busiest)
 static inline void double_unlock_balance(struct rq *this_rq, struct rq *busiest)
        __releases(busiest->lock)
 {
-       raw_spin_unlock(&busiest->lock);
+       if (this_rq != busiest)
+               raw_spin_unlock(&busiest->lock);
        lock_set_subclass(&this_rq->lock.dep_map, 0, _RET_IP_);
 }
 
index cbc67da109544c4f0841b609e44d7337650aa81c..61f852d46858c868fda8b00601311b7837f66552 100644 (file)
@@ -1,4 +1,5 @@
 #include "sched.h"
+#include "walt.h"
 
 /*
  * stop-task scheduling class.
@@ -42,12 +43,14 @@ static void
 enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 {
        add_nr_running(rq, 1);
+       walt_inc_cumulative_runnable_avg(rq, p);
 }
 
 static void
 dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 {
        sub_nr_running(rq, 1);
+       walt_dec_cumulative_runnable_avg(rq, p);
 }
 
 static void yield_task_stop(struct rq *rq)
index 9d8eeb4381409fd1f16572fdc61172214efc3234..68a24a044b0a4f66cf91ee446608934e17cd3f41 100644 (file)
@@ -3,24 +3,21 @@
 #include <linux/kernel.h>
 #include <linux/percpu.h>
 #include <linux/printk.h>
-#include <linux/reciprocal_div.h>
 #include <linux/rcupdate.h>
 #include <linux/slab.h>
 
 #include <trace/events/sched.h>
 
 #include "sched.h"
+#include "tune.h"
+
+#ifdef CONFIG_CGROUP_SCHEDTUNE
+static bool schedtune_initialized = false;
+#endif
 
 unsigned int sysctl_sched_cfs_boost __read_mostly;
 
-/*
- * System energy normalization constants
- */
-static struct target_nrg {
-       unsigned long min_power;
-       unsigned long max_power;
-       struct reciprocal_value rdiv;
-} schedtune_target_nrg;
+extern struct target_nrg schedtune_target_nrg;
 
 /* Performance Boost region (B) threshold params */
 static int perf_boost_idx;
@@ -41,16 +38,16 @@ struct threshold_params {
  */
 static struct threshold_params
 threshold_gains[] = {
-       { 0, 4 }, /* >=  0% */
-       { 0, 4 }, /* >= 10% */
-       { 1, 4 }, /* >= 20% */
-       { 2, 4 }, /* >= 30% */
-       { 3, 4 }, /* >= 40% */
-       { 4, 3 }, /* >= 50% */
-       { 4, 2 }, /* >= 60% */
-       { 4, 1 }, /* >= 70% */
-       { 4, 0 }, /* >= 80% */
-       { 4, 0 }  /* >= 90% */
+       { 0, 5 }, /*   < 10% */
+       { 1, 5 }, /*   < 20% */
+       { 2, 5 }, /*   < 30% */
+       { 3, 5 }, /*   < 40% */
+       { 4, 5 }, /*   < 50% */
+       { 5, 4 }, /*   < 60% */
+       { 5, 3 }, /*   < 70% */
+       { 5, 2 }, /*   < 80% */
+       { 5, 1 }, /*   < 90% */
+       { 5, 0 }  /* <= 100% */
 };
 
 static int
@@ -58,36 +55,51 @@ __schedtune_accept_deltas(int nrg_delta, int cap_delta,
                          int perf_boost_idx, int perf_constrain_idx)
 {
        int payoff = -INT_MAX;
+       int gain_idx = -1;
 
        /* Performance Boost (B) region */
-       if (nrg_delta > 0 && cap_delta > 0) {
-               /*
-                * Evaluate "Performance Boost" vs "Energy Increase"
-                * payoff criteria:
-                *    cap_delta / nrg_delta < cap_gain / nrg_gain
-                * which is:
-                *    nrg_delta * cap_gain > cap_delta * nrg_gain
-                */
-               payoff  = nrg_delta * threshold_gains[perf_boost_idx].cap_gain;
-               payoff -= cap_delta * threshold_gains[perf_boost_idx].nrg_gain;
-               return payoff;
-       }
-
+       if (nrg_delta >= 0 && cap_delta > 0)
+               gain_idx = perf_boost_idx;
        /* Performance Constraint (C) region */
-       if (nrg_delta < 0 && cap_delta < 0) {
-               /*
-                * Evaluate "Performance Boost" vs "Energy Increase"
-                * payoff criteria:
-                *    cap_delta / nrg_delta > cap_gain / nrg_gain
-                * which is:
-                *    cap_delta * nrg_gain > nrg_delta * cap_gain
-                */
-               payoff  = cap_delta * threshold_gains[perf_constrain_idx].nrg_gain;
-               payoff -= nrg_delta * threshold_gains[perf_constrain_idx].cap_gain;
-               return payoff;
-       }
+       else if (nrg_delta < 0 && cap_delta <= 0)
+               gain_idx = perf_constrain_idx;
 
        /* Default: reject schedule candidate */
+       if (gain_idx == -1)
+               return payoff;
+
+       /*
+        * Evaluate "Performance Boost" vs "Energy Increase"
+        *
+        * - Performance Boost (B) region
+        *
+        *   Condition: nrg_delta > 0 && cap_delta > 0
+        *   Payoff criteria:
+        *     cap_gain / nrg_gain  < cap_delta / nrg_delta =
+        *     cap_gain * nrg_delta < cap_delta * nrg_gain
+        *   Note that since both nrg_gain and nrg_delta are positive, the
+        *   inequality does not change. Thus:
+        *
+        *     payoff = (cap_delta * nrg_gain) - (cap_gain * nrg_delta)
+        *
+        * - Performance Constraint (C) region
+        *
+        *   Condition: nrg_delta < 0 && cap_delta < 0
+        *   payoff criteria:
+        *     cap_gain / nrg_gain  > cap_delta / nrg_delta =
+        *     cap_gain * nrg_delta < cap_delta * nrg_gain
+        *   Note that since nrg_gain > 0 while nrg_delta < 0, the
+        *   inequality change. Thus:
+        *
+        *     payoff = (cap_delta * nrg_gain) - (cap_gain * nrg_delta)
+        *
+        * This means that, in case of same positive defined {cap,nrg}_gain
+        * for both the B and C regions, we can use the same payoff formula
+        * where a positive value represents the accept condition.
+        */
+       payoff  = cap_delta * threshold_gains[gain_idx].nrg_gain;
+       payoff -= nrg_delta * threshold_gains[gain_idx].cap_gain;
+
        return payoff;
 }
 
@@ -113,6 +125,10 @@ struct schedtune {
 
        /* Performance Constraint (C) region threshold params */
        int perf_constrain_idx;
+
+       /* Hint to bias scheduling of tasks on that SchedTune CGroup
+        * towards idle CPUs */
+       int prefer_idle;
 };
 
 static inline struct schedtune *css_st(struct cgroup_subsys_state *css)
@@ -144,6 +160,7 @@ root_schedtune = {
        .boost  = 0,
        .perf_boost_idx = 0,
        .perf_constrain_idx = 0,
+       .prefer_idle = 0,
 };
 
 int
@@ -155,12 +172,16 @@ schedtune_accept_deltas(int nrg_delta, int cap_delta,
        int perf_constrain_idx;
 
        /* Optimal (O) region */
-       if (nrg_delta < 0 && cap_delta > 0)
+       if (nrg_delta < 0 && cap_delta > 0) {
+               trace_sched_tune_filter(nrg_delta, cap_delta, 0, 0, 1, 0);
                return INT_MAX;
+       }
 
        /* Suboptimal (S) region */
-       if (nrg_delta > 0 && cap_delta < 0)
+       if (nrg_delta > 0 && cap_delta < 0) {
+               trace_sched_tune_filter(nrg_delta, cap_delta, 0, 0, -1, 5);
                return -INT_MAX;
+       }
 
        /* Get task specific perf Boost/Constraints indexes */
        rcu_read_lock();
@@ -202,13 +223,16 @@ static struct schedtune *allocated_group[BOOSTGROUPS_COUNT] = {
  */
 struct boost_groups {
        /* Maximum boost value for all RUNNABLE tasks on a CPU */
-       unsigned boost_max;
+       bool idle;
+       int boost_max;
        struct {
                /* The boost for tasks on that boost group */
-               unsigned boost;
+               int boost;
                /* Count of RUNNABLE tasks on that boost group */
                unsigned tasks;
        } group[BOOSTGROUPS_COUNT];
+       /* CPU's boost group locking */
+       raw_spinlock_t lock;
 };
 
 /* Boost groups affecting each CPU in the system */
@@ -218,7 +242,7 @@ static void
 schedtune_cpu_update(int cpu)
 {
        struct boost_groups *bg;
-       unsigned boost_max;
+       int boost_max;
        int idx;
 
        bg = &per_cpu(cpu_boost_groups, cpu);
@@ -232,9 +256,13 @@ schedtune_cpu_update(int cpu)
                 */
                if (bg->group[idx].tasks == 0)
                        continue;
+
                boost_max = max(boost_max, bg->group[idx].boost);
        }
-
+       /* Ensures boost_max is non-negative when all cgroup boost values
+        * are neagtive. Avoids under-accounting of cpu capacity which may cause
+        * task stacking and frequency spikes.*/
+       boost_max = max(boost_max, 0);
        bg->boost_max = boost_max;
 }
 
@@ -281,28 +309,24 @@ schedtune_boostgroup_update(int idx, int boost)
        return 0;
 }
 
+#define ENQUEUE_TASK  1
+#define DEQUEUE_TASK -1
+
 static inline void
 schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count)
 {
-       struct boost_groups *bg;
-       int tasks;
-
-       bg = &per_cpu(cpu_boost_groups, cpu);
+       struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu);
+       int tasks = bg->group[idx].tasks + task_count;
 
        /* Update boosted tasks count while avoiding to make it negative */
-       if (task_count < 0 && bg->group[idx].tasks <= -task_count)
-               bg->group[idx].tasks = 0;
-       else
-               bg->group[idx].tasks += task_count;
-
-       /* Boost group activation or deactivation on that RQ */
-       tasks = bg->group[idx].tasks;
-       if (tasks == 1 || tasks == 0)
-               schedtune_cpu_update(cpu);
+       bg->group[idx].tasks = max(0, tasks);
 
        trace_sched_tune_tasks_update(p, cpu, tasks, idx,
                        bg->group[idx].boost, bg->boost_max);
 
+       /* Boost group activation or deactivation on that RQ */
+       if (tasks == 1 || tasks == 0)
+               schedtune_cpu_update(cpu);
 }
 
 /*
@@ -310,9 +334,14 @@ schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count)
  */
 void schedtune_enqueue_task(struct task_struct *p, int cpu)
 {
+       struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu);
+       unsigned long irq_flags;
        struct schedtune *st;
        int idx;
 
+       if (!unlikely(schedtune_initialized))
+               return;
+
        /*
         * When a task is marked PF_EXITING by do_exit() it's going to be
         * dequeued and enqueued multiple times in the exit path.
@@ -322,13 +351,103 @@ void schedtune_enqueue_task(struct task_struct *p, int cpu)
        if (p->flags & PF_EXITING)
                return;
 
-       /* Get task boost group */
+       /*
+        * Boost group accouting is protected by a per-cpu lock and requires
+        * interrupt to be disabled to avoid race conditions for example on
+        * do_exit()::cgroup_exit() and task migration.
+        */
+       raw_spin_lock_irqsave(&bg->lock, irq_flags);
        rcu_read_lock();
+
        st = task_schedtune(p);
        idx = st->idx;
+
+       schedtune_tasks_update(p, cpu, idx, ENQUEUE_TASK);
+
        rcu_read_unlock();
+       raw_spin_unlock_irqrestore(&bg->lock, irq_flags);
+}
+
+int schedtune_can_attach(struct cgroup_taskset *tset)
+{
+       struct task_struct *task;
+       struct cgroup_subsys_state *css;
+       struct boost_groups *bg;
+       unsigned long irq_flags;
+       unsigned int cpu;
+       struct rq *rq;
+       int src_bg; /* Source boost group index */
+       int dst_bg; /* Destination boost group index */
+       int tasks;
+
+       if (!unlikely(schedtune_initialized))
+               return 0;
+
+
+       cgroup_taskset_for_each(task, css, tset) {
+
+               /*
+                * Lock the CPU's RQ the task is enqueued to avoid race
+                * conditions with migration code while the task is being
+                * accounted
+                */
+               rq = lock_rq_of(task, &irq_flags);
+
+               if (!task->on_rq) {
+                       unlock_rq_of(rq, task, &irq_flags);
+                       continue;
+               }
+
+               /*
+                * Boost group accouting is protected by a per-cpu lock and requires
+                * interrupt to be disabled to avoid race conditions on...
+                */
+               cpu = cpu_of(rq);
+               bg = &per_cpu(cpu_boost_groups, cpu);
+               raw_spin_lock(&bg->lock);
+
+               dst_bg = css_st(css)->idx;
+               src_bg = task_schedtune(task)->idx;
+
+               /*
+                * Current task is not changing boostgroup, which can
+                * happen when the new hierarchy is in use.
+                */
+               if (unlikely(dst_bg == src_bg)) {
+                       raw_spin_unlock(&bg->lock);
+                       unlock_rq_of(rq, task, &irq_flags);
+                       continue;
+               }
+
+               /*
+                * This is the case of a RUNNABLE task which is switching its
+                * current boost group.
+                */
+
+               /* Move task from src to dst boost group */
+               tasks = bg->group[src_bg].tasks - 1;
+               bg->group[src_bg].tasks = max(0, tasks);
+               bg->group[dst_bg].tasks += 1;
+
+               raw_spin_unlock(&bg->lock);
+               unlock_rq_of(rq, task, &irq_flags);
+
+               /* Update CPU boost group */
+               if (bg->group[src_bg].tasks == 0 || bg->group[dst_bg].tasks == 1)
+                       schedtune_cpu_update(task_cpu(task));
+
+       }
 
-       schedtune_tasks_update(p, cpu, idx, 1);
+       return 0;
+}
+
+void schedtune_cancel_attach(struct cgroup_taskset *tset)
+{
+       /* This can happen only if SchedTune controller is mounted with
+        * other hierarchies ane one of them fails. Since usually SchedTune is
+        * mouted on its own hierarcy, for the time being we do not implement
+        * a proper rollback mechanism */
+       WARN(1, "SchedTune cancel attach not implemented");
 }
 
 /*
@@ -336,26 +455,62 @@ void schedtune_enqueue_task(struct task_struct *p, int cpu)
  */
 void schedtune_dequeue_task(struct task_struct *p, int cpu)
 {
+       struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu);
+       unsigned long irq_flags;
        struct schedtune *st;
        int idx;
 
+       if (!unlikely(schedtune_initialized))
+               return;
+
        /*
         * When a task is marked PF_EXITING by do_exit() it's going to be
         * dequeued and enqueued multiple times in the exit path.
         * Thus we avoid any further update, since we do not want to change
         * CPU boosting while the task is exiting.
-        * The last dequeue will be done by cgroup exit() callback.
+        * The last dequeue is already enforce by the do_exit() code path
+        * via schedtune_exit_task().
         */
        if (p->flags & PF_EXITING)
                return;
 
-       /* Get task boost group */
+       /*
+        * Boost group accouting is protected by a per-cpu lock and requires
+        * interrupt to be disabled to avoid race conditions on...
+        */
+       raw_spin_lock_irqsave(&bg->lock, irq_flags);
        rcu_read_lock();
+
        st = task_schedtune(p);
        idx = st->idx;
+
+       schedtune_tasks_update(p, cpu, idx, DEQUEUE_TASK);
+
        rcu_read_unlock();
+       raw_spin_unlock_irqrestore(&bg->lock, irq_flags);
+}
+
+void schedtune_exit_task(struct task_struct *tsk)
+{
+       struct schedtune *st;
+       unsigned long irq_flags;
+       unsigned int cpu;
+       struct rq *rq;
+       int idx;
+
+       if (!unlikely(schedtune_initialized))
+               return;
+
+       rq = lock_rq_of(tsk, &irq_flags);
+       rcu_read_lock();
 
-       schedtune_tasks_update(p, cpu, idx, -1);
+       cpu = cpu_of(rq);
+       st = task_schedtune(tsk);
+       idx = st->idx;
+       schedtune_tasks_update(tsk, cpu, idx, DEQUEUE_TASK);
+
+       rcu_read_unlock();
+       unlock_rq_of(rq, tsk, &irq_flags);
 }
 
 int schedtune_cpu_boost(int cpu)
@@ -380,7 +535,39 @@ int schedtune_task_boost(struct task_struct *p)
        return task_boost;
 }
 
+int schedtune_prefer_idle(struct task_struct *p)
+{
+       struct schedtune *st;
+       int prefer_idle;
+
+       /* Get prefer_idle value */
+       rcu_read_lock();
+       st = task_schedtune(p);
+       prefer_idle = st->prefer_idle;
+       rcu_read_unlock();
+
+       return prefer_idle;
+}
+
 static u64
+prefer_idle_read(struct cgroup_subsys_state *css, struct cftype *cft)
+{
+       struct schedtune *st = css_st(css);
+
+       return st->prefer_idle;
+}
+
+static int
+prefer_idle_write(struct cgroup_subsys_state *css, struct cftype *cft,
+           u64 prefer_idle)
+{
+       struct schedtune *st = css_st(css);
+       st->prefer_idle = prefer_idle;
+
+       return 0;
+}
+
+static s64
 boost_read(struct cgroup_subsys_state *css, struct cftype *cft)
 {
        struct schedtune *st = css_st(css);
@@ -390,16 +577,32 @@ boost_read(struct cgroup_subsys_state *css, struct cftype *cft)
 
 static int
 boost_write(struct cgroup_subsys_state *css, struct cftype *cft,
-           u64 boost)
+           s64 boost)
 {
        struct schedtune *st = css_st(css);
+       unsigned threshold_idx;
+       int boost_pct;
 
-       if (boost < 0 || boost > 100)
+       if (boost < -100 || boost > 100)
                return -EINVAL;
+       boost_pct = boost;
+
+       /*
+        * Update threshold params for Performance Boost (B)
+        * and Performance Constraint (C) regions.
+        * The current implementatio uses the same cuts for both
+        * B and C regions.
+        */
+       threshold_idx = clamp(boost_pct, 0, 99) / 10;
+       st->perf_boost_idx = threshold_idx;
+       st->perf_constrain_idx = threshold_idx;
 
        st->boost = boost;
-       if (css == &root_schedtune.css)
+       if (css == &root_schedtune.css) {
                sysctl_sched_cfs_boost = boost;
+               perf_boost_idx  = threshold_idx;
+               perf_constrain_idx  = threshold_idx;
+       }
 
        /* Update CPU boost */
        schedtune_boostgroup_update(st->idx, st->boost);
@@ -412,8 +615,13 @@ boost_write(struct cgroup_subsys_state *css, struct cftype *cft,
 static struct cftype files[] = {
        {
                .name = "boost",
-               .read_u64 = boost_read,
-               .write_u64 = boost_write,
+               .read_s64 = boost_read,
+               .write_s64 = boost_write,
+       },
+       {
+               .name = "prefer_idle",
+               .read_u64 = prefer_idle_read,
+               .write_u64 = prefer_idle_write,
        },
        { }     /* terminate */
 };
@@ -437,33 +645,14 @@ schedtune_boostgroup_init(struct schedtune *st)
        return 0;
 }
 
-static int
-schedtune_init(void)
-{
-       struct boost_groups *bg;
-       int cpu;
-
-       /* Initialize the per CPU boost groups */
-       for_each_possible_cpu(cpu) {
-               bg = &per_cpu(cpu_boost_groups, cpu);
-               memset(bg, 0, sizeof(struct boost_groups));
-       }
-
-       pr_info("  schedtune configured to support %d boost groups\n",
-               BOOSTGROUPS_COUNT);
-       return 0;
-}
-
 static struct cgroup_subsys_state *
 schedtune_css_alloc(struct cgroup_subsys_state *parent_css)
 {
        struct schedtune *st;
        int idx;
 
-       if (!parent_css) {
-               schedtune_init();
+       if (!parent_css)
                return &root_schedtune.css;
-       }
 
        /* Allow only single level hierachies */
        if (parent_css != &root_schedtune.css) {
@@ -520,10 +709,30 @@ schedtune_css_free(struct cgroup_subsys_state *css)
 struct cgroup_subsys schedtune_cgrp_subsys = {
        .css_alloc      = schedtune_css_alloc,
        .css_free       = schedtune_css_free,
+       .can_attach     = schedtune_can_attach,
+       .cancel_attach  = schedtune_cancel_attach,
        .legacy_cftypes = files,
        .early_init     = 1,
 };
 
+static inline void
+schedtune_init_cgroups(void)
+{
+       struct boost_groups *bg;
+       int cpu;
+
+       /* Initialize the per CPU boost groups */
+       for_each_possible_cpu(cpu) {
+               bg = &per_cpu(cpu_boost_groups, cpu);
+               memset(bg, 0, sizeof(struct boost_groups));
+       }
+
+       pr_info("schedtune: configured to support %d boost groups\n",
+               BOOSTGROUPS_COUNT);
+
+       schedtune_initialized = true;
+}
+
 #else /* CONFIG_CGROUP_SCHEDTUNE */
 
 int
@@ -531,12 +740,16 @@ schedtune_accept_deltas(int nrg_delta, int cap_delta,
                        struct task_struct *task)
 {
        /* Optimal (O) region */
-       if (nrg_delta < 0 && cap_delta > 0)
+       if (nrg_delta < 0 && cap_delta > 0) {
+               trace_sched_tune_filter(nrg_delta, cap_delta, 0, 0, 1, 0);
                return INT_MAX;
+       }
 
        /* Suboptimal (S) region */
-       if (nrg_delta > 0 && cap_delta < 0)
+       if (nrg_delta > 0 && cap_delta < 0) {
+               trace_sched_tune_filter(nrg_delta, cap_delta, 0, 0, -1, 5);
                return -INT_MAX;
+       }
 
        return __schedtune_accept_deltas(nrg_delta, cap_delta,
                        perf_boost_idx, perf_constrain_idx);
@@ -550,52 +763,29 @@ sysctl_sched_cfs_boost_handler(struct ctl_table *table, int write,
                               loff_t *ppos)
 {
        int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       unsigned threshold_idx;
+       int boost_pct;
 
        if (ret || !write)
                return ret;
 
-       /* Performance Boost (B) region threshold params */
-       perf_boost_idx  = sysctl_sched_cfs_boost;
-       perf_boost_idx /= 10;
+       if (sysctl_sched_cfs_boost < -100 || sysctl_sched_cfs_boost > 100)
+               return -EINVAL;
+       boost_pct = sysctl_sched_cfs_boost;
 
-       /* Performance Constraint (C) region threshold params */
-       perf_constrain_idx  = 100 - sysctl_sched_cfs_boost;
-       perf_constrain_idx /= 10;
+       /*
+        * Update threshold params for Performance Boost (B)
+        * and Performance Constraint (C) regions.
+        * The current implementatio uses the same cuts for both
+        * B and C regions.
+        */
+       threshold_idx = clamp(boost_pct, 0, 99) / 10;
+       perf_boost_idx = threshold_idx;
+       perf_constrain_idx = threshold_idx;
 
        return 0;
 }
 
-/*
- * System energy normalization
- * Returns the normalized value, in the range [0..SCHED_LOAD_SCALE],
- * corresponding to the specified energy variation.
- */
-int
-schedtune_normalize_energy(int energy_diff)
-{
-       u32 normalized_nrg;
-       int max_delta;
-
-#ifdef CONFIG_SCHED_DEBUG
-       /* Check for boundaries */
-       max_delta  = schedtune_target_nrg.max_power;
-       max_delta -= schedtune_target_nrg.min_power;
-       WARN_ON(abs(energy_diff) >= max_delta);
-#endif
-
-       /* Do scaling using positive numbers to increase the range */
-       normalized_nrg = (energy_diff < 0) ? -energy_diff : energy_diff;
-
-       /* Scale by energy magnitude */
-       normalized_nrg <<= SCHED_LOAD_SHIFT;
-
-       /* Normalize on max energy for target platform */
-       normalized_nrg = reciprocal_divide(
-                       normalized_nrg, schedtune_target_nrg.rdiv);
-
-       return (energy_diff < 0) ? -normalized_nrg : normalized_nrg;
-}
-
 #ifdef CONFIG_SCHED_DEBUG
 static void
 schedtune_test_nrg(unsigned long delta_pwr)
@@ -698,7 +888,7 @@ schedtune_add_cluster_nrg(
  * that bind the EM to the topology information.
  */
 static int
-schedtune_init_late(void)
+schedtune_init(void)
 {
        struct target_nrg *ste = &schedtune_target_nrg;
        unsigned long delta_pwr = 0;
@@ -738,11 +928,17 @@ schedtune_init_late(void)
                ste->rdiv.m, ste->rdiv.sh1, ste->rdiv.sh2);
 
        schedtune_test_nrg(delta_pwr);
+
+#ifdef CONFIG_CGROUP_SCHEDTUNE
+       schedtune_init_cgroups();
+#else
+       pr_info("schedtune: configured to support global boosting only\n");
+#endif
+
        return 0;
 
 nodata:
        rcu_read_unlock();
        return -EINVAL;
 }
-late_initcall(schedtune_init_late);
-
+postcore_initcall(schedtune_init);
index f7273a5d994aa4708c74ad5d815fe984a2ef1a20..4f6441771e4c9e169380deb8c3b4c53ae0014c47 100644 (file)
@@ -1,16 +1,36 @@
 
 #ifdef CONFIG_SCHED_TUNE
 
+#include <linux/reciprocal_div.h>
+
+/*
+ * System energy normalization constants
+ */
+struct target_nrg {
+       unsigned long min_power;
+       unsigned long max_power;
+       struct reciprocal_value rdiv;
+};
+
 #ifdef CONFIG_CGROUP_SCHEDTUNE
 
 int schedtune_cpu_boost(int cpu);
 int schedtune_task_boost(struct task_struct *tsk);
 
+int schedtune_prefer_idle(struct task_struct *tsk);
+
+void schedtune_exit_task(struct task_struct *tsk);
+
 void schedtune_enqueue_task(struct task_struct *p, int cpu);
 void schedtune_dequeue_task(struct task_struct *p, int cpu);
 
 #else /* CONFIG_CGROUP_SCHEDTUNE */
 
+#define schedtune_cpu_boost(cpu)  get_sysctl_sched_cfs_boost()
+#define schedtune_task_boost(tsk) get_sysctl_sched_cfs_boost()
+
+#define schedtune_exit_task(task) do { } while (0)
+
 #define schedtune_enqueue_task(task, cpu) do { } while (0)
 #define schedtune_dequeue_task(task, cpu) do { } while (0)
 
@@ -22,10 +42,14 @@ int schedtune_accept_deltas(int nrg_delta, int cap_delta,
 
 #else /* CONFIG_SCHED_TUNE */
 
+#define schedtune_cpu_boost(cpu)  0
+#define schedtune_task_boost(tsk) 0
+
+#define schedtune_exit_task(task) do { } while (0)
+
 #define schedtune_enqueue_task(task, cpu) do { } while (0)
 #define schedtune_dequeue_task(task, cpu) do { } while (0)
 
-#define schedtune_normalize_energy(energy) energy
 #define schedtune_accept_deltas(nrg_delta, cap_delta, task) nrg_delta
 
 #endif /* CONFIG_SCHED_TUNE */
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
new file mode 100644 (file)
index 0000000..2ffb168
--- /dev/null
@@ -0,0 +1,1168 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Window Assisted Load Tracking (WALT) implementation credits:
+ * Srivatsa Vaddagiri, Steve Muckle, Syed Rameez Mustafa, Joonwoo Park,
+ * Pavan Kumar Kondeti, Olav Haugan
+ *
+ * 2016-03-06: Integration with EAS/refactoring by Vikram Mulukutla
+ *             and Todd Kjos
+ */
+
+#include <linux/syscore_ops.h>
+#include <linux/cpufreq.h>
+#include <trace/events/sched.h>
+#include "sched.h"
+#include "walt.h"
+
+#define WINDOW_STATS_RECENT            0
+#define WINDOW_STATS_MAX               1
+#define WINDOW_STATS_MAX_RECENT_AVG    2
+#define WINDOW_STATS_AVG               3
+#define WINDOW_STATS_INVALID_POLICY    4
+
+#define EXITING_TASK_MARKER    0xdeaddead
+
+static __read_mostly unsigned int walt_ravg_hist_size = 5;
+static __read_mostly unsigned int walt_window_stats_policy =
+       WINDOW_STATS_MAX_RECENT_AVG;
+static __read_mostly unsigned int walt_account_wait_time = 1;
+static __read_mostly unsigned int walt_freq_account_wait_time = 0;
+static __read_mostly unsigned int walt_io_is_busy = 0;
+
+unsigned int sysctl_sched_walt_init_task_load_pct = 15;
+
+/* 1 -> use PELT based load stats, 0 -> use window-based load stats */
+unsigned int __read_mostly walt_disabled = 0;
+
+static unsigned int max_possible_efficiency = 1024;
+static unsigned int min_possible_efficiency = 1024;
+
+/*
+ * Maximum possible frequency across all cpus. Task demand and cpu
+ * capacity (cpu_power) metrics are scaled in reference to it.
+ */
+static unsigned int max_possible_freq = 1;
+
+/*
+ * Minimum possible max_freq across all cpus. This will be same as
+ * max_possible_freq on homogeneous systems and could be different from
+ * max_possible_freq on heterogenous systems. min_max_freq is used to derive
+ * capacity (cpu_power) of cpus.
+ */
+static unsigned int min_max_freq = 1;
+
+static unsigned int max_capacity = 1024;
+static unsigned int min_capacity = 1024;
+static unsigned int max_load_scale_factor = 1024;
+static unsigned int max_possible_capacity = 1024;
+
+/* Mask of all CPUs that have  max_possible_capacity */
+static cpumask_t mpc_mask = CPU_MASK_ALL;
+
+/* Window size (in ns) */
+__read_mostly unsigned int walt_ravg_window = 20000000;
+
+/* Min window size (in ns) = 10ms */
+#define MIN_SCHED_RAVG_WINDOW 10000000
+
+/* Max window size (in ns) = 1s */
+#define MAX_SCHED_RAVG_WINDOW 1000000000
+
+static unsigned int sync_cpu;
+static ktime_t ktime_last;
+static bool walt_ktime_suspended;
+
+static unsigned int task_load(struct task_struct *p)
+{
+       return p->ravg.demand;
+}
+
+void
+walt_inc_cumulative_runnable_avg(struct rq *rq,
+                                struct task_struct *p)
+{
+       rq->cumulative_runnable_avg += p->ravg.demand;
+}
+
+void
+walt_dec_cumulative_runnable_avg(struct rq *rq,
+                                struct task_struct *p)
+{
+       rq->cumulative_runnable_avg -= p->ravg.demand;
+       BUG_ON((s64)rq->cumulative_runnable_avg < 0);
+}
+
+static void
+fixup_cumulative_runnable_avg(struct rq *rq,
+                             struct task_struct *p, s64 task_load_delta)
+{
+       rq->cumulative_runnable_avg += task_load_delta;
+       if ((s64)rq->cumulative_runnable_avg < 0)
+               panic("cra less than zero: tld: %lld, task_load(p) = %u\n",
+                       task_load_delta, task_load(p));
+}
+
+u64 walt_ktime_clock(void)
+{
+       if (unlikely(walt_ktime_suspended))
+               return ktime_to_ns(ktime_last);
+       return ktime_get_ns();
+}
+
+static void walt_resume(void)
+{
+       walt_ktime_suspended = false;
+}
+
+static int walt_suspend(void)
+{
+       ktime_last = ktime_get();
+       walt_ktime_suspended = true;
+       return 0;
+}
+
+static struct syscore_ops walt_syscore_ops = {
+       .resume = walt_resume,
+       .suspend = walt_suspend
+};
+
+static int __init walt_init_ops(void)
+{
+       register_syscore_ops(&walt_syscore_ops);
+       return 0;
+}
+late_initcall(walt_init_ops);
+
+void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *cfs_rq,
+               struct task_struct *p)
+{
+       cfs_rq->cumulative_runnable_avg += p->ravg.demand;
+}
+
+void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *cfs_rq,
+               struct task_struct *p)
+{
+       cfs_rq->cumulative_runnable_avg -= p->ravg.demand;
+}
+
+static int exiting_task(struct task_struct *p)
+{
+       if (p->flags & PF_EXITING) {
+               if (p->ravg.sum_history[0] != EXITING_TASK_MARKER) {
+                       p->ravg.sum_history[0] = EXITING_TASK_MARKER;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+static int __init set_walt_ravg_window(char *str)
+{
+       get_option(&str, &walt_ravg_window);
+
+       walt_disabled = (walt_ravg_window < MIN_SCHED_RAVG_WINDOW ||
+                               walt_ravg_window > MAX_SCHED_RAVG_WINDOW);
+       return 0;
+}
+
+early_param("walt_ravg_window", set_walt_ravg_window);
+
+static void
+update_window_start(struct rq *rq, u64 wallclock)
+{
+       s64 delta;
+       int nr_windows;
+
+       delta = wallclock - rq->window_start;
+       /* If the MPM global timer is cleared, set delta as 0 to avoid kernel BUG happening */
+       if (delta < 0) {
+               delta = 0;
+               WARN_ONCE(1, "WALT wallclock appears to have gone backwards or reset\n");
+       }
+
+       if (delta < walt_ravg_window)
+               return;
+
+       nr_windows = div64_u64(delta, walt_ravg_window);
+       rq->window_start += (u64)nr_windows * (u64)walt_ravg_window;
+}
+
+static u64 scale_exec_time(u64 delta, struct rq *rq)
+{
+       unsigned int cur_freq = rq->cur_freq;
+       int sf;
+
+       if (unlikely(cur_freq > max_possible_freq))
+               cur_freq = rq->max_possible_freq;
+
+       /* round up div64 */
+       delta = div64_u64(delta * cur_freq + max_possible_freq - 1,
+                         max_possible_freq);
+
+       sf = DIV_ROUND_UP(rq->efficiency * 1024, max_possible_efficiency);
+
+       delta *= sf;
+       delta >>= 10;
+
+       return delta;
+}
+
+static int cpu_is_waiting_on_io(struct rq *rq)
+{
+       if (!walt_io_is_busy)
+               return 0;
+
+       return atomic_read(&rq->nr_iowait);
+}
+
+void walt_account_irqtime(int cpu, struct task_struct *curr,
+                                u64 delta, u64 wallclock)
+{
+       struct rq *rq = cpu_rq(cpu);
+       unsigned long flags, nr_windows;
+       u64 cur_jiffies_ts;
+
+       raw_spin_lock_irqsave(&rq->lock, flags);
+
+       /*
+        * cputime (wallclock) uses sched_clock so use the same here for
+        * consistency.
+        */
+       delta += sched_clock() - wallclock;
+       cur_jiffies_ts = get_jiffies_64();
+
+       if (is_idle_task(curr))
+               walt_update_task_ravg(curr, rq, IRQ_UPDATE, walt_ktime_clock(),
+                                delta);
+
+       nr_windows = cur_jiffies_ts - rq->irqload_ts;
+
+       if (nr_windows) {
+               if (nr_windows < 10) {
+                       /* Decay CPU's irqload by 3/4 for each window. */
+                       rq->avg_irqload *= (3 * nr_windows);
+                       rq->avg_irqload = div64_u64(rq->avg_irqload,
+                                                   4 * nr_windows);
+               } else {
+                       rq->avg_irqload = 0;
+               }
+               rq->avg_irqload += rq->cur_irqload;
+               rq->cur_irqload = 0;
+       }
+
+       rq->cur_irqload += delta;
+       rq->irqload_ts = cur_jiffies_ts;
+       raw_spin_unlock_irqrestore(&rq->lock, flags);
+}
+
+
+#define WALT_HIGH_IRQ_TIMEOUT 3
+
+u64 walt_irqload(int cpu) {
+       struct rq *rq = cpu_rq(cpu);
+       s64 delta;
+       delta = get_jiffies_64() - rq->irqload_ts;
+
+        /*
+        * Current context can be preempted by irq and rq->irqload_ts can be
+        * updated by irq context so that delta can be negative.
+        * But this is okay and we can safely return as this means there
+        * was recent irq occurrence.
+        */
+
+        if (delta < WALT_HIGH_IRQ_TIMEOUT)
+               return rq->avg_irqload;
+        else
+               return 0;
+}
+
+int walt_cpu_high_irqload(int cpu) {
+       return walt_irqload(cpu) >= sysctl_sched_walt_cpu_high_irqload;
+}
+
+static int account_busy_for_cpu_time(struct rq *rq, struct task_struct *p,
+                                    u64 irqtime, int event)
+{
+       if (is_idle_task(p)) {
+               /* TASK_WAKE && TASK_MIGRATE is not possible on idle task! */
+               if (event == PICK_NEXT_TASK)
+                       return 0;
+
+               /* PUT_PREV_TASK, TASK_UPDATE && IRQ_UPDATE are left */
+               return irqtime || cpu_is_waiting_on_io(rq);
+       }
+
+       if (event == TASK_WAKE)
+               return 0;
+
+       if (event == PUT_PREV_TASK || event == IRQ_UPDATE ||
+                                        event == TASK_UPDATE)
+               return 1;
+
+       /* Only TASK_MIGRATE && PICK_NEXT_TASK left */
+       return walt_freq_account_wait_time;
+}
+
+/*
+ * Account cpu activity in its busy time counters (rq->curr/prev_runnable_sum)
+ */
+static void update_cpu_busy_time(struct task_struct *p, struct rq *rq,
+            int event, u64 wallclock, u64 irqtime)
+{
+       int new_window, nr_full_windows = 0;
+       int p_is_curr_task = (p == rq->curr);
+       u64 mark_start = p->ravg.mark_start;
+       u64 window_start = rq->window_start;
+       u32 window_size = walt_ravg_window;
+       u64 delta;
+
+       new_window = mark_start < window_start;
+       if (new_window) {
+               nr_full_windows = div64_u64((window_start - mark_start),
+                                               window_size);
+               if (p->ravg.active_windows < USHRT_MAX)
+                       p->ravg.active_windows++;
+       }
+
+       /* Handle per-task window rollover. We don't care about the idle
+        * task or exiting tasks. */
+       if (new_window && !is_idle_task(p) && !exiting_task(p)) {
+               u32 curr_window = 0;
+
+               if (!nr_full_windows)
+                       curr_window = p->ravg.curr_window;
+
+               p->ravg.prev_window = curr_window;
+               p->ravg.curr_window = 0;
+       }
+
+       if (!account_busy_for_cpu_time(rq, p, irqtime, event)) {
+               /* account_busy_for_cpu_time() = 0, so no update to the
+                * task's current window needs to be made. This could be
+                * for example
+                *
+                *   - a wakeup event on a task within the current
+                *     window (!new_window below, no action required),
+                *   - switching to a new task from idle (PICK_NEXT_TASK)
+                *     in a new window where irqtime is 0 and we aren't
+                *     waiting on IO */
+
+               if (!new_window)
+                       return;
+
+               /* A new window has started. The RQ demand must be rolled
+                * over if p is the current task. */
+               if (p_is_curr_task) {
+                       u64 prev_sum = 0;
+
+                       /* p is either idle task or an exiting task */
+                       if (!nr_full_windows) {
+                               prev_sum = rq->curr_runnable_sum;
+                       }
+
+                       rq->prev_runnable_sum = prev_sum;
+                       rq->curr_runnable_sum = 0;
+               }
+
+               return;
+       }
+
+       if (!new_window) {
+               /* account_busy_for_cpu_time() = 1 so busy time needs
+                * to be accounted to the current window. No rollover
+                * since we didn't start a new window. An example of this is
+                * when a task starts execution and then sleeps within the
+                * same window. */
+
+               if (!irqtime || !is_idle_task(p) || cpu_is_waiting_on_io(rq))
+                       delta = wallclock - mark_start;
+               else
+                       delta = irqtime;
+               delta = scale_exec_time(delta, rq);
+               rq->curr_runnable_sum += delta;
+               if (!is_idle_task(p) && !exiting_task(p))
+                       p->ravg.curr_window += delta;
+
+               return;
+       }
+
+       if (!p_is_curr_task) {
+               /* account_busy_for_cpu_time() = 1 so busy time needs
+                * to be accounted to the current window. A new window
+                * has also started, but p is not the current task, so the
+                * window is not rolled over - just split up and account
+                * as necessary into curr and prev. The window is only
+                * rolled over when a new window is processed for the current
+                * task.
+                *
+                * Irqtime can't be accounted by a task that isn't the
+                * currently running task. */
+
+               if (!nr_full_windows) {
+                       /* A full window hasn't elapsed, account partial
+                        * contribution to previous completed window. */
+                       delta = scale_exec_time(window_start - mark_start, rq);
+                       if (!exiting_task(p))
+                               p->ravg.prev_window += delta;
+               } else {
+                       /* Since at least one full window has elapsed,
+                        * the contribution to the previous window is the
+                        * full window (window_size). */
+                       delta = scale_exec_time(window_size, rq);
+                       if (!exiting_task(p))
+                               p->ravg.prev_window = delta;
+               }
+               rq->prev_runnable_sum += delta;
+
+               /* Account piece of busy time in the current window. */
+               delta = scale_exec_time(wallclock - window_start, rq);
+               rq->curr_runnable_sum += delta;
+               if (!exiting_task(p))
+                       p->ravg.curr_window = delta;
+
+               return;
+       }
+
+       if (!irqtime || !is_idle_task(p) || cpu_is_waiting_on_io(rq)) {
+               /* account_busy_for_cpu_time() = 1 so busy time needs
+                * to be accounted to the current window. A new window
+                * has started and p is the current task so rollover is
+                * needed. If any of these three above conditions are true
+                * then this busy time can't be accounted as irqtime.
+                *
+                * Busy time for the idle task or exiting tasks need not
+                * be accounted.
+                *
+                * An example of this would be a task that starts execution
+                * and then sleeps once a new window has begun. */
+
+               if (!nr_full_windows) {
+                       /* A full window hasn't elapsed, account partial
+                        * contribution to previous completed window. */
+                       delta = scale_exec_time(window_start - mark_start, rq);
+                       if (!is_idle_task(p) && !exiting_task(p))
+                               p->ravg.prev_window += delta;
+
+                       delta += rq->curr_runnable_sum;
+               } else {
+                       /* Since at least one full window has elapsed,
+                        * the contribution to the previous window is the
+                        * full window (window_size). */
+                       delta = scale_exec_time(window_size, rq);
+                       if (!is_idle_task(p) && !exiting_task(p))
+                               p->ravg.prev_window = delta;
+
+               }
+               /*
+                * Rollover for normal runnable sum is done here by overwriting
+                * the values in prev_runnable_sum and curr_runnable_sum.
+                * Rollover for new task runnable sum has completed by previous
+                * if-else statement.
+                */
+               rq->prev_runnable_sum = delta;
+
+               /* Account piece of busy time in the current window. */
+               delta = scale_exec_time(wallclock - window_start, rq);
+               rq->curr_runnable_sum = delta;
+               if (!is_idle_task(p) && !exiting_task(p))
+                       p->ravg.curr_window = delta;
+
+               return;
+       }
+
+       if (irqtime) {
+               /* account_busy_for_cpu_time() = 1 so busy time needs
+                * to be accounted to the current window. A new window
+                * has started and p is the current task so rollover is
+                * needed. The current task must be the idle task because
+                * irqtime is not accounted for any other task.
+                *
+                * Irqtime will be accounted each time we process IRQ activity
+                * after a period of idleness, so we know the IRQ busy time
+                * started at wallclock - irqtime. */
+
+               BUG_ON(!is_idle_task(p));
+               mark_start = wallclock - irqtime;
+
+               /* Roll window over. If IRQ busy time was just in the current
+                * window then that is all that need be accounted. */
+               rq->prev_runnable_sum = rq->curr_runnable_sum;
+               if (mark_start > window_start) {
+                       rq->curr_runnable_sum = scale_exec_time(irqtime, rq);
+                       return;
+               }
+
+               /* The IRQ busy time spanned multiple windows. Process the
+                * busy time preceding the current window start first. */
+               delta = window_start - mark_start;
+               if (delta > window_size)
+                       delta = window_size;
+               delta = scale_exec_time(delta, rq);
+               rq->prev_runnable_sum += delta;
+
+               /* Process the remaining IRQ busy time in the current window. */
+               delta = wallclock - window_start;
+               rq->curr_runnable_sum = scale_exec_time(delta, rq);
+
+               return;
+       }
+
+       BUG();
+}
+
+static int account_busy_for_task_demand(struct task_struct *p, int event)
+{
+       /* No need to bother updating task demand for exiting tasks
+        * or the idle task. */
+       if (exiting_task(p) || is_idle_task(p))
+               return 0;
+
+       /* When a task is waking up it is completing a segment of non-busy
+        * time. Likewise, if wait time is not treated as busy time, then
+        * when a task begins to run or is migrated, it is not running and
+        * is completing a segment of non-busy time. */
+       if (event == TASK_WAKE || (!walt_account_wait_time &&
+                        (event == PICK_NEXT_TASK || event == TASK_MIGRATE)))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * Called when new window is starting for a task, to record cpu usage over
+ * recently concluded window(s). Normally 'samples' should be 1. It can be > 1
+ * when, say, a real-time task runs without preemption for several windows at a
+ * stretch.
+ */
+static void update_history(struct rq *rq, struct task_struct *p,
+                        u32 runtime, int samples, int event)
+{
+       u32 *hist = &p->ravg.sum_history[0];
+       int ridx, widx;
+       u32 max = 0, avg, demand;
+       u64 sum = 0;
+
+       /* Ignore windows where task had no activity */
+       if (!runtime || is_idle_task(p) || exiting_task(p) || !samples)
+                       goto done;
+
+       /* Push new 'runtime' value onto stack */
+       widx = walt_ravg_hist_size - 1;
+       ridx = widx - samples;
+       for (; ridx >= 0; --widx, --ridx) {
+               hist[widx] = hist[ridx];
+               sum += hist[widx];
+               if (hist[widx] > max)
+                       max = hist[widx];
+       }
+
+       for (widx = 0; widx < samples && widx < walt_ravg_hist_size; widx++) {
+               hist[widx] = runtime;
+               sum += hist[widx];
+               if (hist[widx] > max)
+                       max = hist[widx];
+       }
+
+       p->ravg.sum = 0;
+
+       if (walt_window_stats_policy == WINDOW_STATS_RECENT) {
+               demand = runtime;
+       } else if (walt_window_stats_policy == WINDOW_STATS_MAX) {
+               demand = max;
+       } else {
+               avg = div64_u64(sum, walt_ravg_hist_size);
+               if (walt_window_stats_policy == WINDOW_STATS_AVG)
+                       demand = avg;
+               else
+                       demand = max(avg, runtime);
+       }
+
+       /*
+        * A throttled deadline sched class task gets dequeued without
+        * changing p->on_rq. Since the dequeue decrements hmp stats
+        * avoid decrementing it here again.
+        */
+       if (task_on_rq_queued(p) && (!task_has_dl_policy(p) ||
+                                               !p->dl.dl_throttled))
+               fixup_cumulative_runnable_avg(rq, p, demand);
+
+       p->ravg.demand = demand;
+
+done:
+       trace_walt_update_history(rq, p, runtime, samples, event);
+       return;
+}
+
+static void add_to_task_demand(struct rq *rq, struct task_struct *p,
+                               u64 delta)
+{
+       delta = scale_exec_time(delta, rq);
+       p->ravg.sum += delta;
+       if (unlikely(p->ravg.sum > walt_ravg_window))
+               p->ravg.sum = walt_ravg_window;
+}
+
+/*
+ * Account cpu demand of task and/or update task's cpu demand history
+ *
+ * ms = p->ravg.mark_start;
+ * wc = wallclock
+ * ws = rq->window_start
+ *
+ * Three possibilities:
+ *
+ *     a) Task event is contained within one window.
+ *             window_start < mark_start < wallclock
+ *
+ *             ws   ms  wc
+ *             |    |   |
+ *             V    V   V
+ *             |---------------|
+ *
+ *     In this case, p->ravg.sum is updated *iff* event is appropriate
+ *     (ex: event == PUT_PREV_TASK)
+ *
+ *     b) Task event spans two windows.
+ *             mark_start < window_start < wallclock
+ *
+ *             ms   ws   wc
+ *             |    |    |
+ *             V    V    V
+ *             -----|-------------------
+ *
+ *     In this case, p->ravg.sum is updated with (ws - ms) *iff* event
+ *     is appropriate, then a new window sample is recorded followed
+ *     by p->ravg.sum being set to (wc - ws) *iff* event is appropriate.
+ *
+ *     c) Task event spans more than two windows.
+ *
+ *             ms ws_tmp                          ws  wc
+ *             |  |                               |   |
+ *             V  V                               V   V
+ *             ---|-------|-------|-------|-------|------
+ *                |                               |
+ *                |<------ nr_full_windows ------>|
+ *
+ *     In this case, p->ravg.sum is updated with (ws_tmp - ms) first *iff*
+ *     event is appropriate, window sample of p->ravg.sum is recorded,
+ *     'nr_full_window' samples of window_size is also recorded *iff*
+ *     event is appropriate and finally p->ravg.sum is set to (wc - ws)
+ *     *iff* event is appropriate.
+ *
+ * IMPORTANT : Leave p->ravg.mark_start unchanged, as update_cpu_busy_time()
+ * depends on it!
+ */
+static void update_task_demand(struct task_struct *p, struct rq *rq,
+            int event, u64 wallclock)
+{
+       u64 mark_start = p->ravg.mark_start;
+       u64 delta, window_start = rq->window_start;
+       int new_window, nr_full_windows;
+       u32 window_size = walt_ravg_window;
+
+       new_window = mark_start < window_start;
+       if (!account_busy_for_task_demand(p, event)) {
+               if (new_window)
+                       /* If the time accounted isn't being accounted as
+                        * busy time, and a new window started, only the
+                        * previous window need be closed out with the
+                        * pre-existing demand. Multiple windows may have
+                        * elapsed, but since empty windows are dropped,
+                        * it is not necessary to account those. */
+                       update_history(rq, p, p->ravg.sum, 1, event);
+               return;
+       }
+
+       if (!new_window) {
+               /* The simple case - busy time contained within the existing
+                * window. */
+               add_to_task_demand(rq, p, wallclock - mark_start);
+               return;
+       }
+
+       /* Busy time spans at least two windows. Temporarily rewind
+        * window_start to first window boundary after mark_start. */
+       delta = window_start - mark_start;
+       nr_full_windows = div64_u64(delta, window_size);
+       window_start -= (u64)nr_full_windows * (u64)window_size;
+
+       /* Process (window_start - mark_start) first */
+       add_to_task_demand(rq, p, window_start - mark_start);
+
+       /* Push new sample(s) into task's demand history */
+       update_history(rq, p, p->ravg.sum, 1, event);
+       if (nr_full_windows)
+               update_history(rq, p, scale_exec_time(window_size, rq),
+                              nr_full_windows, event);
+
+       /* Roll window_start back to current to process any remainder
+        * in current window. */
+       window_start += (u64)nr_full_windows * (u64)window_size;
+
+       /* Process (wallclock - window_start) next */
+       mark_start = window_start;
+       add_to_task_demand(rq, p, wallclock - mark_start);
+}
+
+/* Reflect task activity on its demand and cpu's busy time statistics */
+void walt_update_task_ravg(struct task_struct *p, struct rq *rq,
+            int event, u64 wallclock, u64 irqtime)
+{
+       if (walt_disabled || !rq->window_start)
+               return;
+
+       lockdep_assert_held(&rq->lock);
+
+       update_window_start(rq, wallclock);
+
+       if (!p->ravg.mark_start)
+               goto done;
+
+       update_task_demand(p, rq, event, wallclock);
+       update_cpu_busy_time(p, rq, event, wallclock, irqtime);
+
+done:
+       trace_walt_update_task_ravg(p, rq, event, wallclock, irqtime);
+
+       p->ravg.mark_start = wallclock;
+}
+
+unsigned long __weak arch_get_cpu_efficiency(int cpu)
+{
+       return SCHED_LOAD_SCALE;
+}
+
+void walt_init_cpu_efficiency(void)
+{
+       int i, efficiency;
+       unsigned int max = 0, min = UINT_MAX;
+
+       for_each_possible_cpu(i) {
+               efficiency = arch_get_cpu_efficiency(i);
+               cpu_rq(i)->efficiency = efficiency;
+
+               if (efficiency > max)
+                       max = efficiency;
+               if (efficiency < min)
+                       min = efficiency;
+       }
+
+       if (max)
+               max_possible_efficiency = max;
+
+       if (min)
+               min_possible_efficiency = min;
+}
+
+static void reset_task_stats(struct task_struct *p)
+{
+       u32 sum = 0;
+
+       if (exiting_task(p))
+               sum = EXITING_TASK_MARKER;
+
+       memset(&p->ravg, 0, sizeof(struct ravg));
+       /* Retain EXITING_TASK marker */
+       p->ravg.sum_history[0] = sum;
+}
+
+void walt_mark_task_starting(struct task_struct *p)
+{
+       u64 wallclock;
+       struct rq *rq = task_rq(p);
+
+       if (!rq->window_start) {
+               reset_task_stats(p);
+               return;
+       }
+
+       wallclock = walt_ktime_clock();
+       p->ravg.mark_start = wallclock;
+}
+
+void walt_set_window_start(struct rq *rq)
+{
+       int cpu = cpu_of(rq);
+       struct rq *sync_rq = cpu_rq(sync_cpu);
+
+       if (rq->window_start)
+               return;
+
+       if (cpu == sync_cpu) {
+               rq->window_start = walt_ktime_clock();
+       } else {
+               raw_spin_unlock(&rq->lock);
+               double_rq_lock(rq, sync_rq);
+               rq->window_start = cpu_rq(sync_cpu)->window_start;
+               rq->curr_runnable_sum = rq->prev_runnable_sum = 0;
+               raw_spin_unlock(&sync_rq->lock);
+       }
+
+       rq->curr->ravg.mark_start = rq->window_start;
+}
+
+void walt_migrate_sync_cpu(int cpu)
+{
+       if (cpu == sync_cpu)
+               sync_cpu = smp_processor_id();
+}
+
+void walt_fixup_busy_time(struct task_struct *p, int new_cpu)
+{
+       struct rq *src_rq = task_rq(p);
+       struct rq *dest_rq = cpu_rq(new_cpu);
+       u64 wallclock;
+
+       if (!p->on_rq && p->state != TASK_WAKING)
+               return;
+
+       if (exiting_task(p)) {
+               return;
+       }
+
+       if (p->state == TASK_WAKING)
+               double_rq_lock(src_rq, dest_rq);
+
+       wallclock = walt_ktime_clock();
+
+       walt_update_task_ravg(task_rq(p)->curr, task_rq(p),
+                       TASK_UPDATE, wallclock, 0);
+       walt_update_task_ravg(dest_rq->curr, dest_rq,
+                       TASK_UPDATE, wallclock, 0);
+
+       walt_update_task_ravg(p, task_rq(p), TASK_MIGRATE, wallclock, 0);
+
+       if (p->ravg.curr_window) {
+               src_rq->curr_runnable_sum -= p->ravg.curr_window;
+               dest_rq->curr_runnable_sum += p->ravg.curr_window;
+       }
+
+       if (p->ravg.prev_window) {
+               src_rq->prev_runnable_sum -= p->ravg.prev_window;
+               dest_rq->prev_runnable_sum += p->ravg.prev_window;
+       }
+
+       if ((s64)src_rq->prev_runnable_sum < 0) {
+               src_rq->prev_runnable_sum = 0;
+               WARN_ON(1);
+       }
+       if ((s64)src_rq->curr_runnable_sum < 0) {
+               src_rq->curr_runnable_sum = 0;
+               WARN_ON(1);
+       }
+
+       trace_walt_migration_update_sum(src_rq, p);
+       trace_walt_migration_update_sum(dest_rq, p);
+
+       if (p->state == TASK_WAKING)
+               double_rq_unlock(src_rq, dest_rq);
+}
+
+/* Keep track of max/min capacity possible across CPUs "currently" */
+static void __update_min_max_capacity(void)
+{
+       int i;
+       int max = 0, min = INT_MAX;
+
+       for_each_online_cpu(i) {
+               if (cpu_rq(i)->capacity > max)
+                       max = cpu_rq(i)->capacity;
+               if (cpu_rq(i)->capacity < min)
+                       min = cpu_rq(i)->capacity;
+       }
+
+       max_capacity = max;
+       min_capacity = min;
+}
+
+static void update_min_max_capacity(void)
+{
+       unsigned long flags;
+       int i;
+
+       local_irq_save(flags);
+       for_each_possible_cpu(i)
+               raw_spin_lock(&cpu_rq(i)->lock);
+
+       __update_min_max_capacity();
+
+       for_each_possible_cpu(i)
+               raw_spin_unlock(&cpu_rq(i)->lock);
+       local_irq_restore(flags);
+}
+
+/*
+ * Return 'capacity' of a cpu in reference to "least" efficient cpu, such that
+ * least efficient cpu gets capacity of 1024
+ */
+static unsigned long capacity_scale_cpu_efficiency(int cpu)
+{
+       return (1024 * cpu_rq(cpu)->efficiency) / min_possible_efficiency;
+}
+
+/*
+ * Return 'capacity' of a cpu in reference to cpu with lowest max_freq
+ * (min_max_freq), such that one with lowest max_freq gets capacity of 1024.
+ */
+static unsigned long capacity_scale_cpu_freq(int cpu)
+{
+       return (1024 * cpu_rq(cpu)->max_freq) / min_max_freq;
+}
+
+/*
+ * Return load_scale_factor of a cpu in reference to "most" efficient cpu, so
+ * that "most" efficient cpu gets a load_scale_factor of 1
+ */
+static unsigned long load_scale_cpu_efficiency(int cpu)
+{
+       return DIV_ROUND_UP(1024 * max_possible_efficiency,
+                           cpu_rq(cpu)->efficiency);
+}
+
+/*
+ * Return load_scale_factor of a cpu in reference to cpu with best max_freq
+ * (max_possible_freq), so that one with best max_freq gets a load_scale_factor
+ * of 1.
+ */
+static unsigned long load_scale_cpu_freq(int cpu)
+{
+       return DIV_ROUND_UP(1024 * max_possible_freq, cpu_rq(cpu)->max_freq);
+}
+
+static int compute_capacity(int cpu)
+{
+       int capacity = 1024;
+
+       capacity *= capacity_scale_cpu_efficiency(cpu);
+       capacity >>= 10;
+
+       capacity *= capacity_scale_cpu_freq(cpu);
+       capacity >>= 10;
+
+       return capacity;
+}
+
+static int compute_load_scale_factor(int cpu)
+{
+       int load_scale = 1024;
+
+       /*
+        * load_scale_factor accounts for the fact that task load
+        * is in reference to "best" performing cpu. Task's load will need to be
+        * scaled (up) by a factor to determine suitability to be placed on a
+        * (little) cpu.
+        */
+       load_scale *= load_scale_cpu_efficiency(cpu);
+       load_scale >>= 10;
+
+       load_scale *= load_scale_cpu_freq(cpu);
+       load_scale >>= 10;
+
+       return load_scale;
+}
+
+static int cpufreq_notifier_policy(struct notifier_block *nb,
+               unsigned long val, void *data)
+{
+       struct cpufreq_policy *policy = (struct cpufreq_policy *)data;
+       int i, update_max = 0;
+       u64 highest_mpc = 0, highest_mplsf = 0;
+       const struct cpumask *cpus = policy->related_cpus;
+       unsigned int orig_min_max_freq = min_max_freq;
+       unsigned int orig_max_possible_freq = max_possible_freq;
+       /* Initialized to policy->max in case policy->related_cpus is empty! */
+       unsigned int orig_max_freq = policy->max;
+
+       if (val != CPUFREQ_NOTIFY && val != CPUFREQ_REMOVE_POLICY &&
+                                               val != CPUFREQ_CREATE_POLICY)
+               return 0;
+
+       if (val == CPUFREQ_REMOVE_POLICY || val == CPUFREQ_CREATE_POLICY) {
+               update_min_max_capacity();
+               return 0;
+       }
+
+       for_each_cpu(i, policy->related_cpus) {
+               cpumask_copy(&cpu_rq(i)->freq_domain_cpumask,
+                            policy->related_cpus);
+               orig_max_freq = cpu_rq(i)->max_freq;
+               cpu_rq(i)->min_freq = policy->min;
+               cpu_rq(i)->max_freq = policy->max;
+               cpu_rq(i)->cur_freq = policy->cur;
+               cpu_rq(i)->max_possible_freq = policy->cpuinfo.max_freq;
+       }
+
+       max_possible_freq = max(max_possible_freq, policy->cpuinfo.max_freq);
+       if (min_max_freq == 1)
+               min_max_freq = UINT_MAX;
+       min_max_freq = min(min_max_freq, policy->cpuinfo.max_freq);
+       BUG_ON(!min_max_freq);
+       BUG_ON(!policy->max);
+
+       /* Changes to policy other than max_freq don't require any updates */
+       if (orig_max_freq == policy->max)
+               return 0;
+
+       /*
+        * A changed min_max_freq or max_possible_freq (possible during bootup)
+        * needs to trigger re-computation of load_scale_factor and capacity for
+        * all possible cpus (even those offline). It also needs to trigger
+        * re-computation of nr_big_task count on all online cpus.
+        *
+        * A changed rq->max_freq otoh needs to trigger re-computation of
+        * load_scale_factor and capacity for just the cluster of cpus involved.
+        * Since small task definition depends on max_load_scale_factor, a
+        * changed load_scale_factor of one cluster could influence
+        * classification of tasks in another cluster. Hence a changed
+        * rq->max_freq will need to trigger re-computation of nr_big_task
+        * count on all online cpus.
+        *
+        * While it should be sufficient for nr_big_tasks to be
+        * re-computed for only online cpus, we have inadequate context
+        * information here (in policy notifier) with regard to hotplug-safety
+        * context in which notification is issued. As a result, we can't use
+        * get_online_cpus() here, as it can lead to deadlock. Until cpufreq is
+        * fixed up to issue notification always in hotplug-safe context,
+        * re-compute nr_big_task for all possible cpus.
+        */
+
+       if (orig_min_max_freq != min_max_freq ||
+               orig_max_possible_freq != max_possible_freq) {
+                       cpus = cpu_possible_mask;
+                       update_max = 1;
+       }
+
+       /*
+        * Changed load_scale_factor can trigger reclassification of tasks as
+        * big or small. Make this change "atomic" so that tasks are accounted
+        * properly due to changed load_scale_factor
+        */
+       for_each_cpu(i, cpus) {
+               struct rq *rq = cpu_rq(i);
+
+               rq->capacity = compute_capacity(i);
+               rq->load_scale_factor = compute_load_scale_factor(i);
+
+               if (update_max) {
+                       u64 mpc, mplsf;
+
+                       mpc = div_u64(((u64) rq->capacity) *
+                               rq->max_possible_freq, rq->max_freq);
+                       rq->max_possible_capacity = (int) mpc;
+
+                       mplsf = div_u64(((u64) rq->load_scale_factor) *
+                               rq->max_possible_freq, rq->max_freq);
+
+                       if (mpc > highest_mpc) {
+                               highest_mpc = mpc;
+                               cpumask_clear(&mpc_mask);
+                               cpumask_set_cpu(i, &mpc_mask);
+                       } else if (mpc == highest_mpc) {
+                               cpumask_set_cpu(i, &mpc_mask);
+                       }
+
+                       if (mplsf > highest_mplsf)
+                               highest_mplsf = mplsf;
+               }
+       }
+
+       if (update_max) {
+               max_possible_capacity = highest_mpc;
+               max_load_scale_factor = highest_mplsf;
+       }
+
+       __update_min_max_capacity();
+
+       return 0;
+}
+
+static int cpufreq_notifier_trans(struct notifier_block *nb,
+               unsigned long val, void *data)
+{
+       struct cpufreq_freqs *freq = (struct cpufreq_freqs *)data;
+       unsigned int cpu = freq->cpu, new_freq = freq->new;
+       unsigned long flags;
+       int i;
+
+       if (val != CPUFREQ_POSTCHANGE)
+               return 0;
+
+       BUG_ON(!new_freq);
+
+       if (cpu_rq(cpu)->cur_freq == new_freq)
+               return 0;
+
+       for_each_cpu(i, &cpu_rq(cpu)->freq_domain_cpumask) {
+               struct rq *rq = cpu_rq(i);
+
+               raw_spin_lock_irqsave(&rq->lock, flags);
+               walt_update_task_ravg(rq->curr, rq, TASK_UPDATE,
+                                     walt_ktime_clock(), 0);
+               rq->cur_freq = new_freq;
+               raw_spin_unlock_irqrestore(&rq->lock, flags);
+       }
+
+       return 0;
+}
+
+static struct notifier_block notifier_policy_block = {
+       .notifier_call = cpufreq_notifier_policy
+};
+
+static struct notifier_block notifier_trans_block = {
+       .notifier_call = cpufreq_notifier_trans
+};
+
+static int register_sched_callback(void)
+{
+       int ret;
+
+       ret = cpufreq_register_notifier(&notifier_policy_block,
+                                               CPUFREQ_POLICY_NOTIFIER);
+
+       if (!ret)
+               ret = cpufreq_register_notifier(&notifier_trans_block,
+                                               CPUFREQ_TRANSITION_NOTIFIER);
+
+       return 0;
+}
+
+/*
+ * cpufreq callbacks can be registered at core_initcall or later time.
+ * Any registration done prior to that is "forgotten" by cpufreq. See
+ * initialization of variable init_cpufreq_transition_notifier_list_called
+ * for further information.
+ */
+core_initcall(register_sched_callback);
+
+void walt_init_new_task_load(struct task_struct *p)
+{
+       int i;
+       u32 init_load_windows =
+                       div64_u64((u64)sysctl_sched_walt_init_task_load_pct *
+                          (u64)walt_ravg_window, 100);
+       u32 init_load_pct = current->init_load_pct;
+
+       p->init_load_pct = 0;
+       memset(&p->ravg, 0, sizeof(struct ravg));
+
+       if (init_load_pct) {
+               init_load_windows = div64_u64((u64)init_load_pct *
+                         (u64)walt_ravg_window, 100);
+       }
+
+       p->ravg.demand = init_load_windows;
+       for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i)
+               p->ravg.sum_history[i] = init_load_windows;
+}
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
new file mode 100644 (file)
index 0000000..e181c87
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WALT_H
+#define __WALT_H
+
+#ifdef CONFIG_SCHED_WALT
+
+void walt_update_task_ravg(struct task_struct *p, struct rq *rq, int event,
+               u64 wallclock, u64 irqtime);
+void walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p);
+void walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p);
+void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *rq,
+               struct task_struct *p);
+void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *rq,
+               struct task_struct *p);
+void walt_fixup_busy_time(struct task_struct *p, int new_cpu);
+void walt_init_new_task_load(struct task_struct *p);
+void walt_mark_task_starting(struct task_struct *p);
+void walt_set_window_start(struct rq *rq);
+void walt_migrate_sync_cpu(int cpu);
+void walt_init_cpu_efficiency(void);
+u64 walt_ktime_clock(void);
+void walt_account_irqtime(int cpu, struct task_struct *curr, u64 delta,
+                                  u64 wallclock);
+
+u64 walt_irqload(int cpu);
+int walt_cpu_high_irqload(int cpu);
+
+#else /* CONFIG_SCHED_WALT */
+
+static inline void walt_update_task_ravg(struct task_struct *p, struct rq *rq,
+               int event, u64 wallclock, u64 irqtime) { }
+static inline void walt_inc_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) { }
+static inline void walt_dec_cumulative_runnable_avg(struct rq *rq, struct task_struct *p) { }
+static inline void walt_inc_cfs_cumulative_runnable_avg(struct cfs_rq *rq,
+               struct task_struct *p) { }
+static inline void walt_dec_cfs_cumulative_runnable_avg(struct cfs_rq *rq,
+               struct task_struct *p) { }
+static inline void walt_fixup_busy_time(struct task_struct *p, int new_cpu) { }
+static inline void walt_init_new_task_load(struct task_struct *p) { }
+static inline void walt_mark_task_starting(struct task_struct *p) { }
+static inline void walt_set_window_start(struct rq *rq) { }
+static inline void walt_migrate_sync_cpu(int cpu) { }
+static inline void walt_init_cpu_efficiency(void) { }
+static inline u64 walt_ktime_clock(void) { return 0; }
+
+#endif /* CONFIG_SCHED_WALT */
+
+extern unsigned int walt_disabled;
+
+#endif
index 46822df92c50e78b721f5aa64bf5c5d9637ad35e..abb795e8a6f1f1e4f9c472577a3b41bdea37b6b1 100644 (file)
@@ -304,6 +304,64 @@ static struct ctl_table kern_table[] = {
                .extra1         = &min_sched_granularity_ns,
                .extra2         = &max_sched_granularity_ns,
        },
+       {
+               .procname       = "sched_is_big_little",
+               .data           = &sysctl_sched_is_big_little,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+#ifdef CONFIG_SCHED_WALT
+       {
+               .procname       = "sched_use_walt_cpu_util",
+               .data           = &sysctl_sched_use_walt_cpu_util,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "sched_use_walt_task_util",
+               .data           = &sysctl_sched_use_walt_task_util,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "sched_walt_init_task_load_pct",
+               .data           = &sysctl_sched_walt_init_task_load_pct,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "sched_walt_cpu_high_irqload",
+               .data           = &sysctl_sched_walt_cpu_high_irqload,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+#endif
+       {
+               .procname       = "sched_sync_hint_enable",
+               .data           = &sysctl_sched_sync_hint_enable,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "sched_initial_task_util",
+               .data           = &sysctl_sched_initial_task_util,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "sched_cstate_aware",
+               .data           = &sysctl_sched_cstate_aware,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {
                .procname       = "sched_wakeup_granularity_ns",
                .data           = &sysctl_sched_wakeup_granularity,
@@ -2097,6 +2155,21 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
        return 0;
 }
 
+static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp,
+                                int *valp,
+                                int write, void *data)
+{
+       if (write) {
+               if (*negp)
+                       return -EINVAL;
+               *valp = *lvalp;
+       } else {
+               unsigned int val = *valp;
+               *lvalp = (unsigned long)val;
+       }
+       return 0;
+}
+
 static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
 
 static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
@@ -2224,8 +2297,27 @@ static int do_proc_dointvec(struct ctl_table *table, int write,
 int proc_dointvec(struct ctl_table *table, int write,
                     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-    return do_proc_dointvec(table,write,buffer,lenp,ppos,
-                           NULL,NULL);
+       return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL);
+}
+
+/**
+ * proc_douintvec - read a vector of unsigned integers
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
+ * values from/to the user buffer, treated as an ASCII string.
+ *
+ * Returns 0 on success.
+ */
+int proc_douintvec(struct ctl_table *table, int write,
+                    void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       return do_proc_dointvec(table, write, buffer, lenp, ppos,
+                               do_proc_douintvec_conv, NULL);
 }
 
 /*
@@ -2838,6 +2930,12 @@ int proc_dointvec(struct ctl_table *table, int write,
        return -ENOSYS;
 }
 
+int proc_douintvec(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       return -ENOSYS;
+}
+
 int proc_dointvec_minmax(struct ctl_table *table, int write,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -2883,6 +2981,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
  * exception granted :-)
  */
 EXPORT_SYMBOL(proc_dointvec);
+EXPORT_SYMBOL(proc_douintvec);
 EXPORT_SYMBOL(proc_dointvec_jiffies);
 EXPORT_SYMBOL(proc_dointvec_minmax);
 EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);
index 1347882d131e11a404b029d83edfb281483b9c9c..b98810d2f3b4e76ae980233c66ca120acb3d2adc 100644 (file)
@@ -323,13 +323,42 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
                /* cs is a watchdog. */
                if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
                        cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
+       }
+       spin_unlock_irqrestore(&watchdog_lock, flags);
+}
+
+static void clocksource_select_watchdog(bool fallback)
+{
+       struct clocksource *cs, *old_wd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&watchdog_lock, flags);
+       /* save current watchdog */
+       old_wd = watchdog;
+       if (fallback)
+               watchdog = NULL;
+
+       list_for_each_entry(cs, &clocksource_list, list) {
+               /* cs is a clocksource to be watched. */
+               if (cs->flags & CLOCK_SOURCE_MUST_VERIFY)
+                       continue;
+
+               /* Skip current if we were requested for a fallback. */
+               if (fallback && cs == old_wd)
+                       continue;
+
                /* Pick the best watchdog. */
-               if (!watchdog || cs->rating > watchdog->rating) {
+               if (!watchdog || cs->rating > watchdog->rating)
                        watchdog = cs;
-                       /* Reset watchdog cycles */
-                       clocksource_reset_watchdog();
-               }
        }
+       /* If we failed to find a fallback restore the old one. */
+       if (!watchdog)
+               watchdog = old_wd;
+
+       /* If we changed the watchdog we need to reset cycles. */
+       if (watchdog != old_wd)
+               clocksource_reset_watchdog();
+
        /* Check if the watchdog timer needs to be started. */
        clocksource_start_watchdog();
        spin_unlock_irqrestore(&watchdog_lock, flags);
@@ -404,6 +433,7 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
                cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
 }
 
+static void clocksource_select_watchdog(bool fallback) { }
 static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { }
 static inline void clocksource_resume_watchdog(void) { }
 static inline int __clocksource_watchdog_kthread(void) { return 0; }
@@ -736,6 +766,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
        clocksource_enqueue(cs);
        clocksource_enqueue_watchdog(cs);
        clocksource_select();
+       clocksource_select_watchdog(false);
        mutex_unlock(&clocksource_mutex);
        return 0;
 }
@@ -758,6 +789,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating)
        mutex_lock(&clocksource_mutex);
        __clocksource_change_rating(cs, rating);
        clocksource_select();
+       clocksource_select_watchdog(false);
        mutex_unlock(&clocksource_mutex);
 }
 EXPORT_SYMBOL(clocksource_change_rating);
@@ -767,12 +799,12 @@ EXPORT_SYMBOL(clocksource_change_rating);
  */
 static int clocksource_unbind(struct clocksource *cs)
 {
-       /*
-        * I really can't convince myself to support this on hardware
-        * designed by lobotomized monkeys.
-        */
-       if (clocksource_is_watchdog(cs))
-               return -EBUSY;
+       if (clocksource_is_watchdog(cs)) {
+               /* Select and try to install a replacement watchdog. */
+               clocksource_select_watchdog(true);
+               if (clocksource_is_watchdog(cs))
+                       return -EBUSY;
+       }
 
        if (cs == curr_clocksource) {
                /* Select and try to install a replacement clock source */
index 58a321c34cfbf7733cbcfe1bf841581f6402f987..405536b22c0ccbdda2de491f57689c4af8d467f3 100644 (file)
@@ -94,6 +94,9 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
 };
 
 static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
+       /* Make sure we catch unsupported clockids */
+       [0 ... MAX_CLOCKS - 1]  = HRTIMER_MAX_CLOCK_BASES,
+
        [CLOCK_REALTIME]        = HRTIMER_BASE_REALTIME,
        [CLOCK_MONOTONIC]       = HRTIMER_BASE_MONOTONIC,
        [CLOCK_BOOTTIME]        = HRTIMER_BASE_BOOTTIME,
@@ -102,7 +105,9 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
 
 static inline int hrtimer_clockid_to_base(clockid_t clock_id)
 {
-       return hrtimer_clock_to_base_table[clock_id];
+       int base = hrtimer_clock_to_base_table[clock_id];
+       BUG_ON(base == HRTIMER_MAX_CLOCK_BASES);
+       return base;
 }
 
 /*
index 149cc8086aea16bbd811d3af37e187fd08bb366f..ab861771e37f8aded12c98c137a7b8b3820ece69 100644 (file)
@@ -674,8 +674,24 @@ int ntp_validate_timex(struct timex *txc)
                        return -EINVAL;
        }
 
-       if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
-               return -EPERM;
+       if (txc->modes & ADJ_SETOFFSET) {
+               /* In order to inject time, you gotta be super-user! */
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+
+               if (txc->modes & ADJ_NANO) {
+                       struct timespec ts;
+
+                       ts.tv_sec = txc->time.tv_sec;
+                       ts.tv_nsec = txc->time.tv_usec;
+                       if (!timespec_inject_offset_valid(&ts))
+                               return -EINVAL;
+
+               } else {
+                       if (!timeval_inject_offset_valid(&txc->time))
+                               return -EINVAL;
+               }
+       }
 
        /*
         * Check for potential multiplication overflows that can
index f5e86d282d520a7881557de76096c1cf46f58fa7..80016b329d94427d83abfb28988b2d268846a0e4 100644 (file)
@@ -808,6 +808,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
                        timer->it.cpu.expires = 0;
                        sample_to_timespec(timer->it_clock, timer->it.cpu.expires,
                                           &itp->it_value);
+                       return;
                } else {
                        cpu_timer_sample_group(timer->it_clock, p, &now);
                        unlock_task_sighand(p, &flags);
index 99188ee5d9d0908df81d3acbadbc6bd1af44ef0f..445601c580d69be7970314238e1c0af5680b9eda 100644 (file)
@@ -298,17 +298,34 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;
 static inline u32 arch_gettimeoffset(void) { return 0; }
 #endif
 
+static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr,
+                                         cycle_t delta)
+{
+       s64 nsec;
+
+       nsec = delta * tkr->mult + tkr->xtime_nsec;
+       nsec >>= tkr->shift;
+
+       /* If arch requires, add in get_arch_timeoffset() */
+       return nsec + arch_gettimeoffset();
+}
+
 static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
 {
        cycle_t delta;
-       s64 nsec;
 
        delta = timekeeping_get_delta(tkr);
+       return timekeeping_delta_to_ns(tkr, delta);
+}
 
-       nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift;
+static inline s64 timekeeping_cycles_to_ns(struct tk_read_base *tkr,
+                                           cycle_t cycles)
+{
+       cycle_t delta;
 
-       /* If arch requires, add in get_arch_timeoffset() */
-       return nsec + arch_gettimeoffset();
+       /* calculate the delta since the last update_wall_time */
+       delta = clocksource_delta(cycles, tkr->cycle_last, tkr->mask);
+       return timekeeping_delta_to_ns(tkr, delta);
 }
 
 /**
@@ -383,7 +400,13 @@ static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
        do {
                seq = raw_read_seqcount_latch(&tkf->seq);
                tkr = tkf->base + (seq & 0x01);
-               now = ktime_to_ns(tkr->base) + timekeeping_get_ns(tkr);
+               now = ktime_to_ns(tkr->base);
+
+               now += timekeeping_delta_to_ns(tkr,
+                               clocksource_delta(
+                                       tkr->read(tkr->clock),
+                                       tkr->cycle_last,
+                                       tkr->mask));
        } while (read_seqcount_retry(&tkf->seq, seq));
 
        return now;
@@ -958,7 +981,7 @@ int timekeeping_inject_offset(struct timespec *ts)
        struct timespec64 ts64, tmp;
        int ret = 0;
 
-       if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+       if (!timespec_inject_offset_valid(ts))
                return -EINVAL;
 
        ts64 = timespec_to_timespec64(*ts);
index f6bd65236712b218fe89c2bee83b8e56ca1bf89e..107310a6f36f43a47300c46a4bd3b51a6b5b70fa 100644 (file)
@@ -23,7 +23,9 @@
 
 #include "timekeeping_internal.h"
 
-static unsigned int sleep_time_bin[32] = {0};
+#define NUM_BINS 32
+
+static unsigned int sleep_time_bin[NUM_BINS] = {0};
 
 static int tk_debug_show_sleep_time(struct seq_file *s, void *data)
 {
@@ -69,6 +71,9 @@ late_initcall(tk_debug_sleep_time_init);
 
 void tk_debug_account_sleep_time(struct timespec64 *t)
 {
-       sleep_time_bin[fls(t->tv_sec)]++;
+       /* Cap bin index so we don't overflow the array */
+       int bin = min(fls(t->tv_sec), NUM_BINS-1);
+
+       sleep_time_bin[bin]++;
 }
 
index ba04bf0c2653bc342a8d791d5fe67a8cafb45c1f..a9bba37fab5aec746885b403e7452fb39110b861 100644 (file)
@@ -1,4 +1,8 @@
 
+# We are fully aware of the dangers of __builtin_return_address()
+FRAME_CFLAGS := $(call cc-disable-warning,frame-address)
+KBUILD_CFLAGS += $(FRAME_CFLAGS)
+
 # Do not instrument the tracer itself:
 
 ifdef CONFIG_FUNCTION_TRACER
index dd4d86ae8e213aafe5814aa00ffbab01c3cdd1c8..bff7d4c69274b3e6755b26bc39d6717dca02517e 100644 (file)
@@ -4816,19 +4816,20 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
        struct trace_iterator *iter = filp->private_data;
        ssize_t sret;
 
-       /* return any leftover data */
-       sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
-       if (sret != -EBUSY)
-               return sret;
-
-       trace_seq_init(&iter->seq);
-
        /*
         * Avoid more than one consumer on a single file descriptor
         * This is just a matter of traces coherency, the ring buffer itself
         * is protected.
         */
        mutex_lock(&iter->mutex);
+
+       /* return any leftover data */
+       sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
+       if (sret != -EBUSY)
+               goto out;
+
+       trace_seq_init(&iter->seq);
+
        if (iter->trace->read) {
                sret = iter->trace->read(iter, filp, ubuf, cnt, ppos);
                if (sret)
@@ -5855,9 +5856,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                return -EBUSY;
 #endif
 
-       if (splice_grow_spd(pipe, &spd))
-               return -ENOMEM;
-
        if (*ppos & (PAGE_SIZE - 1))
                return -EINVAL;
 
@@ -5867,6 +5865,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                len &= PAGE_MASK;
        }
 
+       if (splice_grow_spd(pipe, &spd))
+               return -ENOMEM;
+
  again:
        trace_access_lock(iter->cpu_file);
        entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
@@ -5924,19 +5925,21 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
        /* did we read anything? */
        if (!spd.nr_pages) {
                if (ret)
-                       return ret;
+                       goto out;
 
+               ret = -EAGAIN;
                if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK))
-                       return -EAGAIN;
+                       goto out;
 
                ret = wait_on_pipe(iter, true);
                if (ret)
-                       return ret;
+                       goto out;
 
                goto again;
        }
 
        ret = splice_to_pipe(pipe, &spd);
+out:
        splice_shrink_spd(&spd);
 
        return ret;
index fc9f2adc0c9b26b830e0e572c01602c70d871724..63d14d9b51d889dceffc1492d4e72b220fae47cc 100644 (file)
@@ -867,6 +867,15 @@ config SCHED_INFO
        bool
        default n
 
+config PANIC_ON_RT_THROTTLING
+       bool "Panic on RT throttling"
+       help
+         Say Y here to enable the kernel to panic when a realtime
+         runqueue is throttled. This may be useful for detecting
+         and debugging RT throttling issues.
+
+         Say N if unsure.
+
 config SCHEDSTATS
        bool "Collect scheduler statistics"
        depends on DEBUG_KERNEL && PROC_FS
index 2b3f46c049d458a590d080823b344da3b3229f7c..554522934c442ae15c01b1b1266e8e3e9515bfbd 100644 (file)
@@ -74,7 +74,7 @@ next_tag:
 
        /* Extract a tag from the data */
        tag = data[dp++];
-       if (tag == 0) {
+       if (tag == ASN1_EOC) {
                /* It appears to be an EOC. */
                if (data[dp++] != 0)
                        goto invalid_eoc;
@@ -96,10 +96,8 @@ next_tag:
 
        /* Extract the length */
        len = data[dp++];
-       if (len <= 0x7f) {
-               dp += len;
-               goto next_tag;
-       }
+       if (len <= 0x7f)
+               goto check_length;
 
        if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
                /* Indefinite length */
@@ -110,14 +108,18 @@ next_tag:
        }
 
        n = len - 0x80;
-       if (unlikely(n > sizeof(size_t) - 1))
+       if (unlikely(n > sizeof(len) - 1))
                goto length_too_long;
        if (unlikely(n > datalen - dp))
                goto data_overrun_error;
-       for (len = 0; n > 0; n--) {
+       len = 0;
+       for (; n > 0; n--) {
                len <<= 8;
                len |= data[dp++];
        }
+check_length:
+       if (len > datalen - dp)
+               goto data_overrun_error;
        dp += len;
        goto next_tag;
 
index 75232ad0a5e7ead00e5d8396ed34763d84a0685c..daca582a8ed072f0b4eb8b6871134a608e3192b1 100644 (file)
@@ -297,26 +297,6 @@ done:
        return wanted - bytes;
 }
 
-/*
- * Fault in the first iovec of the given iov_iter, to a maximum length
- * of bytes. Returns 0 on success, or non-zero if the memory could not be
- * accessed (ie. because it is an invalid address).
- *
- * writev-intensive code may want this to prefault several iovecs -- that
- * would be possible (callers must not rely on the fact that _only_ the
- * first iovec will be faulted with the current implementation).
- */
-int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
-{
-       if (!(i->type & (ITER_BVEC|ITER_KVEC))) {
-               char __user *buf = i->iov->iov_base + i->iov_offset;
-               bytes = min(bytes, i->iov->iov_len - i->iov_offset);
-               return fault_in_pages_readable(buf, bytes);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(iov_iter_fault_in_readable);
-
 /*
  * Fault in one or more iovecs of the given iov_iter, to a maximum length of
  * bytes.  For each iovec, fault in each page that constitutes the iovec.
@@ -324,7 +304,7 @@ EXPORT_SYMBOL(iov_iter_fault_in_readable);
  * Return 0 on success, or non-zero if the memory could not be accessed (i.e.
  * because it is an invalid address).
  */
-int iov_iter_fault_in_multipages_readable(struct iov_iter *i, size_t bytes)
+int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes)
 {
        size_t skip = i->iov_offset;
        const struct iovec *iov;
@@ -341,7 +321,7 @@ int iov_iter_fault_in_multipages_readable(struct iov_iter *i, size_t bytes)
        }
        return 0;
 }
-EXPORT_SYMBOL(iov_iter_fault_in_multipages_readable);
+EXPORT_SYMBOL(iov_iter_fault_in_readable);
 
 void iov_iter_init(struct iov_iter *i, int direction,
                        const struct iovec *iov, unsigned long nr_segs,
index 94be244e844103d0fb6ed20c7bee905ca908fa12..d8a5cf66c316fe21eaecee8d973deac1eb3bd5d7 100644 (file)
@@ -321,6 +321,70 @@ int kstrtos8(const char *s, unsigned int base, s8 *res)
 }
 EXPORT_SYMBOL(kstrtos8);
 
+/**
+ * kstrtobool - convert common user inputs into boolean values
+ * @s: input string
+ * @res: result
+ *
+ * This routine returns 0 iff the first character is one of 'Yy1Nn0', or
+ * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL.  Value
+ * pointed to by res is updated upon finding a match.
+ */
+int kstrtobool(const char *s, bool *res)
+{
+       if (!s)
+               return -EINVAL;
+
+       switch (s[0]) {
+       case 'y':
+       case 'Y':
+       case '1':
+               *res = true;
+               return 0;
+       case 'n':
+       case 'N':
+       case '0':
+               *res = false;
+               return 0;
+       case 'o':
+       case 'O':
+               switch (s[1]) {
+               case 'n':
+               case 'N':
+                       *res = true;
+                       return 0;
+               case 'f':
+               case 'F':
+                       *res = false;
+                       return 0;
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(kstrtobool);
+
+/*
+ * Since "base" would be a nonsense argument, this open-codes the
+ * _from_user helper instead of using the helper macro below.
+ */
+int kstrtobool_from_user(const char __user *s, size_t count, bool *res)
+{
+       /* Longest string needed to differentiate, newline, terminator */
+       char buf[4];
+
+       count = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, s, count))
+               return -EFAULT;
+       buf[count] = '\0';
+       return kstrtobool(buf, res);
+}
+EXPORT_SYMBOL(kstrtobool_from_user);
+
 #define kstrto_from_user(f, g, type)                                   \
 int f(const char __user *s, size_t count, unsigned int base, type *res)        \
 {                                                                      \
index e00ff00e861cea3654dc6483e03a7bf21485b88e..e37dbf53e2263c4ff1f2882d681486516073049e 100644 (file)
@@ -367,7 +367,9 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
        buf_len = sgl->length;
        p2 = sg_virt(sgl);
 
-       for (i = a->nlimbs - 1; i >= 0; i--) {
+       for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB,
+                       lzeros %= BYTES_PER_MPI_LIMB;
+               i >= 0; i--) {
                alimb = a->d[i];
                p = (u8 *)&alimb2;
 #if BYTES_PER_MPI_LIMB == 4
@@ -388,17 +390,12 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
 #error please implement for this limb size.
 #endif
                if (lzeros > 0) {
-                       if (lzeros >= sizeof(alimb)) {
-                               p -= sizeof(alimb);
-                               continue;
-                       } else {
-                               mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
-                               mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
-                                                       + lzeros;
-                               *limb1 = *limb2;
-                               p -= lzeros;
-                               y = lzeros;
-                       }
+                       mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
+                       mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
+                               + lzeros;
+                       *limb1 = *limb2;
+                       p -= lzeros;
+                       y = lzeros;
                        lzeros -= sizeof(alimb);
                }
 
index 0323c0d5629af31e674bcfa24624e0917e2bb80d..1a90db9bc6e1b474099ff9f967efd74101451596 100644 (file)
@@ -630,35 +630,6 @@ bool sysfs_streq(const char *s1, const char *s2)
 }
 EXPORT_SYMBOL(sysfs_streq);
 
-/**
- * strtobool - convert common user inputs into boolean values
- * @s: input string
- * @res: result
- *
- * This routine returns 0 iff the first character is one of 'Yy1Nn0'.
- * Otherwise it will return -EINVAL.  Value pointed to by res is
- * updated upon finding a match.
- */
-int strtobool(const char *s, bool *res)
-{
-       switch (s[0]) {
-       case 'y':
-       case 'Y':
-       case '1':
-               *res = true;
-               break;
-       case 'n':
-       case 'N':
-       case '0':
-               *res = false;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(strtobool);
-
 #ifndef __HAVE_ARCH_MEMSET
 /**
  * memset - Fill a region of memory with the given value
index e0af6ff73d146cfa3356080ebcb1bbea36cd1f96..05efc1fa97f08941d763996d38ce08afbbaba459 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/compiler.h>
 #include <linux/export.h>
+#include <linux/thread_info.h>
 #include <linux/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -39,8 +40,8 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
                unsigned long c, data;
 
                /* Fall back to byte-at-a-time if we get a page fault */
-               if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
-                       break;
+               unsafe_get_user(c, (unsigned long __user *)(src+res), byte_at_a_time);
+
                *(unsigned long *)(dst+res) = c;
                if (has_zero(c, &data, &constants)) {
                        data = prep_zero_mask(c, data, &constants);
@@ -55,8 +56,7 @@ byte_at_a_time:
        while (max) {
                char c;
 
-               if (unlikely(__get_user(c,src+res)))
-                       return -EFAULT;
+               unsafe_get_user(c,src+res, efault);
                dst[res] = c;
                if (!c)
                        return res;
@@ -75,6 +75,7 @@ byte_at_a_time:
         * Nope: we hit the address space limit, and we still had more
         * characters the caller would have wanted. That's an EFAULT.
         */
+efault:
        return -EFAULT;
 }
 
@@ -107,7 +108,13 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
        src_addr = (unsigned long)src;
        if (likely(src_addr < max_addr)) {
                unsigned long max = max_addr - src_addr;
-               return do_strncpy_from_user(dst, src, count, max);
+               long retval;
+
+               check_object_size(dst, count, false);
+               user_access_begin();
+               retval = do_strncpy_from_user(dst, src, count, max);
+               user_access_end();
+               return retval;
        }
        return -EFAULT;
 }
index 3a5f2b366d84ed209a012cf62491ca30f6a8bca8..8e105ed4df12bb6bb0a170afff54d979c15d73c0 100644 (file)
@@ -45,8 +45,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
        src -= align;
        max += align;
 
-       if (unlikely(__get_user(c,(unsigned long __user *)src)))
-               return 0;
+       unsafe_get_user(c, (unsigned long __user *)src, efault);
        c |= aligned_byte_mask(align);
 
        for (;;) {
@@ -61,8 +60,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
                if (unlikely(max <= sizeof(unsigned long)))
                        break;
                max -= sizeof(unsigned long);
-               if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
-                       return 0;
+               unsafe_get_user(c, (unsigned long __user *)(src+res), efault);
        }
        res -= align;
 
@@ -77,6 +75,7 @@ static inline long do_strnlen_user(const char __user *src, unsigned long count,
         * Nope: we hit the address space limit, and we still had more
         * characters the caller would have wanted. That's 0.
         */
+efault:
        return 0;
 }
 
@@ -112,7 +111,12 @@ long strnlen_user(const char __user *str, long count)
        src_addr = (unsigned long)str;
        if (likely(src_addr < max_addr)) {
                unsigned long max = max_addr - src_addr;
-               return do_strnlen_user(str, count, max);
+               long retval;
+
+               user_access_begin();
+               retval = do_strnlen_user(str, count, max);
+               user_access_end();
+               return retval;
        }
        return 0;
 }
@@ -141,7 +145,12 @@ long strlen_user(const char __user *str)
        src_addr = (unsigned long)str;
        if (likely(src_addr < max_addr)) {
                unsigned long max = max_addr - src_addr;
-               return do_strnlen_user(str, ~0ul, max);
+               long retval;
+
+               user_access_begin();
+               retval = do_strnlen_user(str, ~0ul, max);
+               user_access_end();
+               return retval;
        }
        return 0;
 }
index 2ed43191fc3bf78f46f111e88fa9d5a01b8c661a..8b532c94008f2231b2d3d01fc583ff88bb3822ca 100644 (file)
@@ -5,6 +5,9 @@
 KASAN_SANITIZE_slab_common.o := n
 KASAN_SANITIZE_slub.o := n
 
+# Since __builtin_frame_address does work as used, disable the warning.
+CFLAGS_usercopy.o += $(call cc-disable-warning, frame-address)
+
 mmu-y                  := nommu.o
 mmu-$(CONFIG_MMU)      := gup.o highmem.o memory.o mincore.o \
                           mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
@@ -81,3 +84,4 @@ obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
 obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
 obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
 obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
+obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o
index cbe6f0b96f29dd910640452fbc6be35ec709fa9b..9ef80bf441b37ffed8eaed66383261859ebd3623 100644 (file)
@@ -825,6 +825,20 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
 }
 EXPORT_SYMBOL(bdi_register_dev);
 
+int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner)
+{
+       int rc;
+
+       rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt),
+                       MINOR(owner->devt));
+       if (rc)
+               return rc;
+       bdi->owner = owner;
+       get_device(owner);
+       return 0;
+}
+EXPORT_SYMBOL(bdi_register_owner);
+
 /*
  * Remove bdi from bdi_list, and ensure that it is no longer visible
  */
@@ -849,6 +863,11 @@ void bdi_unregister(struct backing_dev_info *bdi)
                device_unregister(bdi->dev);
                bdi->dev = NULL;
        }
+
+       if (bdi->owner) {
+               put_device(bdi->owner);
+               bdi->owner = NULL;
+       }
 }
 
 void bdi_exit(struct backing_dev_info *bdi)
index 7881e072dc33b0b36e5b46dc5d2a9206a2573c7f..dba02dec71952f5c414db14f28c8abc574624b83 100644 (file)
@@ -475,25 +475,23 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                /* Found a free page, break it into order-0 pages */
                isolated = split_free_page(page);
+               if (!isolated)
+                       break;
+
                total_isolated += isolated;
+               cc->nr_freepages += isolated;
                for (i = 0; i < isolated; i++) {
                        list_add(&page->lru, freelist);
                        page++;
                }
-
-               /* If a page was split, advance to the end of it */
-               if (isolated) {
-                       cc->nr_freepages += isolated;
-                       if (!strict &&
-                               cc->nr_migratepages <= cc->nr_freepages) {
-                               blockpfn += isolated;
-                               break;
-                       }
-
-                       blockpfn += isolated - 1;
-                       cursor += isolated - 1;
-                       continue;
+               if (!strict && cc->nr_migratepages <= cc->nr_freepages) {
+                       blockpfn += isolated;
+                       break;
                }
+               /* Advance to the end of split page */
+               blockpfn += isolated - 1;
+               cursor += isolated - 1;
+               continue;
 
 isolate_fail:
                if (strict)
@@ -503,6 +501,9 @@ isolate_fail:
 
        }
 
+       if (locked)
+               spin_unlock_irqrestore(&cc->zone->lock, flags);
+
        /*
         * There is a tiny chance that we have read bogus compound_order(),
         * so be careful to not go outside of the pageblock.
@@ -524,9 +525,6 @@ isolate_fail:
        if (strict && blockpfn < end_pfn)
                total_isolated = 0;
 
-       if (locked)
-               spin_unlock_irqrestore(&cc->zone->lock, flags);
-
        /* Update the pageblock-skip if the whole pageblock was scanned */
        if (blockpfn == end_pfn)
                update_pageblock_skip(cc, valid_page, total_isolated, false);
@@ -966,7 +964,6 @@ static void isolate_freepages(struct compact_control *cc)
                                block_end_pfn = block_start_pfn,
                                block_start_pfn -= pageblock_nr_pages,
                                isolate_start_pfn = block_start_pfn) {
-
                /*
                 * This can iterate a massively long zone without finding any
                 * suitable migration targets, so periodically check if we need
@@ -990,32 +987,30 @@ static void isolate_freepages(struct compact_control *cc)
                        continue;
 
                /* Found a block suitable for isolating free pages from. */
-               isolate_freepages_block(cc, &isolate_start_pfn,
-                                       block_end_pfn, freelist, false);
+               isolate_freepages_block(cc, &isolate_start_pfn, block_end_pfn,
+                                       freelist, false);
 
                /*
-                * If we isolated enough freepages, or aborted due to async
-                * compaction being contended, terminate the loop.
-                * Remember where the free scanner should restart next time,
-                * which is where isolate_freepages_block() left off.
-                * But if it scanned the whole pageblock, isolate_start_pfn
-                * now points at block_end_pfn, which is the start of the next
-                * pageblock.
-                * In that case we will however want to restart at the start
-                * of the previous pageblock.
+                * If we isolated enough freepages, or aborted due to lock
+                * contention, terminate.
                 */
                if ((cc->nr_freepages >= cc->nr_migratepages)
                                                        || cc->contended) {
-                       if (isolate_start_pfn >= block_end_pfn)
+                       if (isolate_start_pfn >= block_end_pfn) {
+                               /*
+                                * Restart at previous pageblock if more
+                                * freepages can be isolated next time.
+                                */
                                isolate_start_pfn =
                                        block_start_pfn - pageblock_nr_pages;
+                       }
                        break;
-               } else {
+               } else if (isolate_start_pfn < block_end_pfn) {
                        /*
-                        * isolate_freepages_block() should not terminate
-                        * prematurely unless contended, or isolated enough
+                        * If isolation failed early, do not continue
+                        * needlessly.
                         */
-                       VM_BUG_ON(isolate_start_pfn < block_end_pfn);
+                       break;
                }
        }
 
index 1bb007624b53e1cc086ae26d91238d6c3683d6b2..c588d1222b2afb2402bd0cf5bbaf4dca027ddc51 100644 (file)
  *   ->tasklist_lock            (memory_failure, collect_procs_ao)
  */
 
+static int page_cache_tree_insert(struct address_space *mapping,
+                                 struct page *page, void **shadowp)
+{
+       struct radix_tree_node *node;
+       void **slot;
+       int error;
+
+       error = __radix_tree_create(&mapping->page_tree, page->index,
+                                   &node, &slot);
+       if (error)
+               return error;
+       if (*slot) {
+               void *p;
+
+               p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
+               if (!radix_tree_exceptional_entry(p))
+                       return -EEXIST;
+               if (shadowp)
+                       *shadowp = p;
+               mapping->nrshadows--;
+               if (node)
+                       workingset_node_shadows_dec(node);
+       }
+       radix_tree_replace_slot(slot, page);
+       mapping->nrpages++;
+       if (node) {
+               workingset_node_pages_inc(node);
+               /*
+                * Don't track node that contains actual pages.
+                *
+                * Avoid acquiring the list_lru lock if already
+                * untracked.  The list_empty() test is safe as
+                * node->private_list is protected by
+                * mapping->tree_lock.
+                */
+               if (!list_empty(&node->private_list))
+                       list_lru_del(&workingset_shadow_nodes,
+                                    &node->private_list);
+       }
+       return 0;
+}
+
 static void page_cache_tree_delete(struct address_space *mapping,
                                   struct page *page, void *shadow)
 {
@@ -122,6 +164,14 @@ static void page_cache_tree_delete(struct address_space *mapping,
 
        __radix_tree_lookup(&mapping->page_tree, page->index, &node, &slot);
 
+       if (!node) {
+               /*
+                * We need a node to properly account shadow
+                * entries. Don't plant any without. XXX
+                */
+               shadow = NULL;
+       }
+
        if (shadow) {
                mapping->nrshadows++;
                /*
@@ -538,9 +588,8 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
                memcg = mem_cgroup_begin_page_stat(old);
                spin_lock_irqsave(&mapping->tree_lock, flags);
                __delete_from_page_cache(old, NULL, memcg);
-               error = radix_tree_insert(&mapping->page_tree, offset, new);
+               error = page_cache_tree_insert(mapping, new, NULL);
                BUG_ON(error);
-               mapping->nrpages++;
 
                /*
                 * hugetlb pages do not participate in page cache accounting.
@@ -562,48 +611,6 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL_GPL(replace_page_cache_page);
 
-static int page_cache_tree_insert(struct address_space *mapping,
-                                 struct page *page, void **shadowp)
-{
-       struct radix_tree_node *node;
-       void **slot;
-       int error;
-
-       error = __radix_tree_create(&mapping->page_tree, page->index,
-                                   &node, &slot);
-       if (error)
-               return error;
-       if (*slot) {
-               void *p;
-
-               p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
-               if (!radix_tree_exceptional_entry(p))
-                       return -EEXIST;
-               if (shadowp)
-                       *shadowp = p;
-               mapping->nrshadows--;
-               if (node)
-                       workingset_node_shadows_dec(node);
-       }
-       radix_tree_replace_slot(slot, page);
-       mapping->nrpages++;
-       if (node) {
-               workingset_node_pages_inc(node);
-               /*
-                * Don't track node that contains actual pages.
-                *
-                * Avoid acquiring the list_lru lock if already
-                * untracked.  The list_empty() test is safe as
-                * node->private_list is protected by
-                * mapping->tree_lock.
-                */
-               if (!list_empty(&node->private_list))
-                       list_lru_del(&workingset_shadow_nodes,
-                                    &node->private_list);
-       }
-       return 0;
-}
-
 static int __add_to_page_cache_locked(struct page *page,
                                      struct address_space *mapping,
                                      pgoff_t offset, gfp_t gfp_mask,
index deafa2c91b362206b7ef56aec918509a9cc24dd2..4b0b7e7d1136820790098312d148d663dd170441 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -58,6 +58,16 @@ static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address,
        return -EEXIST;
 }
 
+/*
+ * FOLL_FORCE can write to even unwritable pte's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+{
+       return pte_write(pte) ||
+               ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
+}
+
 static struct page *follow_page_pte(struct vm_area_struct *vma,
                unsigned long address, pmd_t *pmd, unsigned int flags)
 {
@@ -92,7 +102,7 @@ retry:
        }
        if ((flags & FOLL_NUMA) && pte_protnone(pte))
                goto no_page;
-       if ((flags & FOLL_WRITE) && !pte_write(pte)) {
+       if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
                pte_unmap_unlock(ptep, ptl);
                return NULL;
        }
@@ -352,7 +362,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
         * reCOWed by userspace write).
         */
        if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
-               *flags &= ~FOLL_WRITE;
+               *flags |= FOLL_COW;
        return 0;
 }
 
index ef6963b577fd2920c1a4857f7b74b50e91c98b7a..4434cdd4cd9a6af734a32ff3cae884e9146cd90e 100644 (file)
@@ -1416,12 +1416,13 @@ static void dissolve_free_huge_page(struct page *page)
 {
        spin_lock(&hugetlb_lock);
        if (PageHuge(page) && !page_count(page)) {
-               struct hstate *h = page_hstate(page);
-               int nid = page_to_nid(page);
-               list_del(&page->lru);
+               struct page *head = compound_head(page);
+               struct hstate *h = page_hstate(head);
+               int nid = page_to_nid(head);
+               list_del(&head->lru);
                h->free_huge_pages--;
                h->free_huge_pages_node[nid]--;
-               update_and_free_page(h, page);
+               update_and_free_page(h, head);
        }
        spin_unlock(&hugetlb_lock);
 }
@@ -1429,7 +1430,8 @@ static void dissolve_free_huge_page(struct page *page)
 /*
  * Dissolve free hugepages in a given pfn range. Used by memory hotplug to
  * make specified memory blocks removable from the system.
- * Note that start_pfn should aligned with (minimum) hugepage size.
+ * Note that this will dissolve a free gigantic hugepage completely, if any
+ * part of it lies within the given range.
  */
 void dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
 {
@@ -1438,7 +1440,6 @@ void dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
        if (!hugepages_supported())
                return;
 
-       VM_BUG_ON(!IS_ALIGNED(start_pfn, 1 << minimum_order));
        for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order)
                dissolve_free_huge_page(pfn_to_page(pfn));
 }
@@ -2170,6 +2171,10 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
                 * and reducing the surplus.
                 */
                spin_unlock(&hugetlb_lock);
+
+               /* yield cpu to avoid soft lockup */
+               cond_resched();
+
                if (hstate_is_gigantic(h))
                        ret = alloc_fresh_gigantic_page(h, nodes_allowed);
                else
@@ -4209,7 +4214,6 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
                if (saddr) {
                        spte = huge_pte_offset(svma->vm_mm, saddr);
                        if (spte) {
-                               mm_inc_nr_pmds(mm);
                                get_page(virt_to_page(spte));
                                break;
                        }
@@ -4224,9 +4228,9 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        if (pud_none(*pud)) {
                pud_populate(mm, pud,
                                (pmd_t *)((unsigned long)spte & PAGE_MASK));
+               mm_inc_nr_pmds(mm);
        } else {
                put_page(virt_to_page(spte));
-               mm_inc_nr_pmds(mm);
        }
        spin_unlock(ptl);
 out:
index 38e24b89e4c400394212941a1789dd75bb902198..6979b2bd3227a69eb9ef3386dfcd580af4a2b3e0 100644 (file)
@@ -22,7 +22,8 @@
  */
 #define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\
                        __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\
-                       __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC)
+                       __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\
+                       __GFP_ATOMIC)
 
 /* The GFP flags allowed during early boot */
 #define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))
index b5cd647daa524935f73ae99f6e42743771768eaa..2f028e6d083158910b22238301fb40477a4ce831 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -283,7 +283,8 @@ static inline struct rmap_item *alloc_rmap_item(void)
 {
        struct rmap_item *rmap_item;
 
-       rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL);
+       rmap_item = kmem_cache_zalloc(rmap_item_cache, GFP_KERNEL |
+                                               __GFP_NORETRY | __GFP_NOWARN);
        if (rmap_item)
                ksm_rmap_items++;
        return rmap_item;
index d159b1c96e484d902f6edb34ebb5a83a3977bd57..78f9274dd49d06f11f87beae9520a0e1267dc3ff 100644 (file)
@@ -96,8 +96,7 @@ long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
        pagefault_disable();
 
        do {
-               ret = __copy_from_user_inatomic(dst++,
-                                               (const void __user __force *)src++, 1);
+               ret = __get_user(*dst++, (const char __user __force *)src++);
        } while (dst[-1] && ret == 0 && src - unsafe_addr < count);
 
        dst[-1] = '\0';
index d300f1329814ba538b271fafabb0351d3182d639..07ff069fef256055f776803c708754db310d74f2 100644 (file)
@@ -822,6 +822,17 @@ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
        return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR);
 }
 
+/**
+ * memblock_mark_nomap - Mark a memory region with flag MEMBLOCK_NOMAP.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Return 0 on success, -errno on failure.
+ */
+int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
+{
+       return memblock_setclr_flag(base, size, 1, MEMBLOCK_NOMAP);
+}
 
 /**
  * __next_reserved_mem_region - next function for for_each_reserved_region()
@@ -913,6 +924,10 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
                if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
                        continue;
 
+               /* skip nomap memory unless we were asked for it explicitly */
+               if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+                       continue;
+
                if (!type_b) {
                        if (out_start)
                                *out_start = m_start;
@@ -1022,6 +1037,10 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
                if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
                        continue;
 
+               /* skip nomap memory unless we were asked for it explicitly */
+               if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+                       continue;
+
                if (!type_b) {
                        if (out_start)
                                *out_start = m_start;
@@ -1519,6 +1538,15 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)
        return memblock_search(&memblock.memory, addr) != -1;
 }
 
+int __init_memblock memblock_is_map_memory(phys_addr_t addr)
+{
+       int i = memblock_search(&memblock.memory, addr);
+
+       if (i == -1)
+               return false;
+       return !memblock_is_nomap(&memblock.memory.regions[i]);
+}
+
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
                         unsigned long *start_pfn, unsigned long *end_pfn)
index 08806bb1f070c57ee30f1ec752f3e7d3034f87ce..1e50d37ee132b3768ecb052486e0dd62f2a0d066 100644 (file)
@@ -272,21 +272,7 @@ static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
 
 static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
 {
-       return memcg->css.id;
-}
-
-/*
- * A helper function to get mem_cgroup from ID. must be called under
- * rcu_read_lock().  The caller is responsible for calling
- * css_tryget_online() if the mem_cgroup is used for charging. (dropping
- * refcnt from swap can be called against removed memcg.)
- */
-static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
-{
-       struct cgroup_subsys_state *css;
-
-       css = css_from_id(id, &memory_cgrp_subsys);
-       return mem_cgroup_from_css(css);
+       return memcg->id.id;
 }
 
 /* Writing them here to avoid exposing memcg's inner layout */
@@ -4124,6 +4110,88 @@ static struct cftype mem_cgroup_legacy_files[] = {
        { },    /* terminate */
 };
 
+/*
+ * Private memory cgroup IDR
+ *
+ * Swap-out records and page cache shadow entries need to store memcg
+ * references in constrained space, so we maintain an ID space that is
+ * limited to 16 bit (MEM_CGROUP_ID_MAX), limiting the total number of
+ * memory-controlled cgroups to 64k.
+ *
+ * However, there usually are many references to the oflline CSS after
+ * the cgroup has been destroyed, such as page cache or reclaimable
+ * slab objects, that don't need to hang on to the ID. We want to keep
+ * those dead CSS from occupying IDs, or we might quickly exhaust the
+ * relatively small ID space and prevent the creation of new cgroups
+ * even when there are much fewer than 64k cgroups - possibly none.
+ *
+ * Maintain a private 16-bit ID space for memcg, and allow the ID to
+ * be freed and recycled when it's no longer needed, which is usually
+ * when the CSS is offlined.
+ *
+ * The only exception to that are records of swapped out tmpfs/shmem
+ * pages that need to be attributed to live ancestors on swapin. But
+ * those references are manageable from userspace.
+ */
+
+static DEFINE_IDR(mem_cgroup_idr);
+
+static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
+{
+       atomic_add(n, &memcg->id.ref);
+}
+
+static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
+{
+       while (!atomic_inc_not_zero(&memcg->id.ref)) {
+               /*
+                * The root cgroup cannot be destroyed, so it's refcount must
+                * always be >= 1.
+                */
+               if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
+                       VM_BUG_ON(1);
+                       break;
+               }
+               memcg = parent_mem_cgroup(memcg);
+               if (!memcg)
+                       memcg = root_mem_cgroup;
+       }
+       return memcg;
+}
+
+static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
+{
+       if (atomic_sub_and_test(n, &memcg->id.ref)) {
+               idr_remove(&mem_cgroup_idr, memcg->id.id);
+               memcg->id.id = 0;
+
+               /* Memcg ID pins CSS */
+               css_put(&memcg->css);
+       }
+}
+
+static inline void mem_cgroup_id_get(struct mem_cgroup *memcg)
+{
+       mem_cgroup_id_get_many(memcg, 1);
+}
+
+static inline void mem_cgroup_id_put(struct mem_cgroup *memcg)
+{
+       mem_cgroup_id_put_many(memcg, 1);
+}
+
+/**
+ * mem_cgroup_from_id - look up a memcg from a memcg id
+ * @id: the memcg id to look up
+ *
+ * Caller must hold rcu_read_lock().
+ */
+struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
+{
+       WARN_ON_ONCE(!rcu_read_lock_held());
+       return idr_find(&mem_cgroup_idr, id);
+}
+
 static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
 {
        struct mem_cgroup_per_node *pn;
@@ -4178,6 +4246,12 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
        if (memcg_wb_domain_init(memcg, GFP_KERNEL))
                goto out_free_stat;
 
+       memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL,
+                                1, MEM_CGROUP_ID_MAX,
+                                GFP_KERNEL);
+       if (memcg->id.id < 0)
+               goto out_free_stat;
+
        return memcg;
 
 out_free_stat:
@@ -4263,9 +4337,11 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 #ifdef CONFIG_CGROUP_WRITEBACK
        INIT_LIST_HEAD(&memcg->cgwb_list);
 #endif
+       idr_replace(&mem_cgroup_idr, memcg, memcg->id.id);
        return &memcg->css;
 
 free_out:
+       idr_remove(&mem_cgroup_idr, memcg->id.id);
        __mem_cgroup_free(memcg);
        return ERR_PTR(error);
 }
@@ -4277,8 +4353,9 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
        struct mem_cgroup *parent = mem_cgroup_from_css(css->parent);
        int ret;
 
-       if (css->id > MEM_CGROUP_ID_MAX)
-               return -ENOSPC;
+       /* Online state pins memcg ID, memcg ID pins CSS */
+       mem_cgroup_id_get(mem_cgroup_from_css(css));
+       css_get(css);
 
        if (!parent)
                return 0;
@@ -4352,6 +4429,8 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        memcg_deactivate_kmem(memcg);
 
        wb_memcg_offline(memcg);
+
+       mem_cgroup_id_put(memcg);
 }
 
 static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
@@ -4785,6 +4864,8 @@ static void __mem_cgroup_clear_mc(void)
                if (!mem_cgroup_is_root(mc.from))
                        page_counter_uncharge(&mc.from->memsw, mc.moved_swap);
 
+               mem_cgroup_id_put_many(mc.from, mc.moved_swap);
+
                /*
                 * we charged both to->memory and to->memsw, so we
                 * should uncharge to->memory.
@@ -4792,9 +4873,9 @@ static void __mem_cgroup_clear_mc(void)
                if (!mem_cgroup_is_root(mc.to))
                        page_counter_uncharge(&mc.to->memory, mc.moved_swap);
 
-               css_put_many(&mc.from->css, mc.moved_swap);
+               mem_cgroup_id_get_many(mc.to, mc.moved_swap);
+               css_put_many(&mc.to->css, mc.moved_swap);
 
-               /* we've already done css_get(mc.to) */
                mc.moved_swap = 0;
        }
        memcg_oom_recover(from);
@@ -4891,11 +4972,6 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
        return ret;
 }
 
-static int mem_cgroup_allow_attach(struct cgroup_taskset *tset)
-{
-       return subsys_cgroup_allow_attach(tset);
-}
-
 static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
 {
        if (mc.to)
@@ -5050,10 +5126,6 @@ static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
 {
        return 0;
 }
-static int mem_cgroup_allow_attach(struct cgroup_taskset *tset)
-{
-       return 0;
-}
 static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
 {
 }
@@ -5272,7 +5344,6 @@ struct cgroup_subsys memory_cgrp_subsys = {
        .can_attach = mem_cgroup_can_attach,
        .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,
@@ -5681,7 +5752,7 @@ subsys_initcall(mem_cgroup_init);
  */
 void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
 {
-       struct mem_cgroup *memcg;
+       struct mem_cgroup *memcg, *swap_memcg;
        unsigned short oldid;
 
        VM_BUG_ON_PAGE(PageLRU(page), page);
@@ -5696,15 +5767,27 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
        if (!memcg)
                return;
 
-       oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
+       /*
+        * In case the memcg owning these pages has been offlined and doesn't
+        * have an ID allocated to it anymore, charge the closest online
+        * ancestor for the swap instead and transfer the memory+swap charge.
+        */
+       swap_memcg = mem_cgroup_id_get_online(memcg);
+       oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
        VM_BUG_ON_PAGE(oldid, page);
-       mem_cgroup_swap_statistics(memcg, true);
+       mem_cgroup_swap_statistics(swap_memcg, true);
 
        page->mem_cgroup = NULL;
 
        if (!mem_cgroup_is_root(memcg))
                page_counter_uncharge(&memcg->memory, 1);
 
+       if (memcg != swap_memcg) {
+               if (!mem_cgroup_is_root(swap_memcg))
+                       page_counter_charge(&swap_memcg->memsw, 1);
+               page_counter_uncharge(&memcg->memsw, 1);
+       }
+
        /*
         * Interrupts should be disabled here because the caller holds the
         * mapping->tree_lock lock which is taken with interrupts-off. It is
@@ -5714,6 +5797,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
        VM_BUG_ON(!irqs_disabled());
        mem_cgroup_charge_statistics(memcg, page, -1);
        memcg_check_events(memcg, page);
+
+       if (!mem_cgroup_is_root(memcg))
+               css_put(&memcg->css);
 }
 
 /**
@@ -5737,7 +5823,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
                if (!mem_cgroup_is_root(memcg))
                        page_counter_uncharge(&memcg->memsw, 1);
                mem_cgroup_swap_statistics(memcg, false);
-               css_put(&memcg->css);
+               mem_cgroup_id_put(memcg);
        }
        rcu_read_unlock();
 }
index 8bbefa93eb773b8f552396d5052640a0b43561c7..1874f29022379511123f0a22adbf5b06209b8fea 100644 (file)
@@ -287,7 +287,9 @@ static inline void reset_deferred_meminit(pg_data_t *pgdat)
 /* Returns true if the struct page for the pfn is uninitialised */
 static inline bool __meminit early_page_uninitialised(unsigned long pfn)
 {
-       if (pfn >= NODE_DATA(early_pfn_to_nid(pfn))->first_deferred_pfn)
+       int nid = early_pfn_to_nid(pfn);
+
+       if (node_online(nid) && pfn >= NODE_DATA(nid)->first_deferred_pfn)
                return true;
 
        return false;
@@ -1069,7 +1071,7 @@ int __meminit early_pfn_to_nid(unsigned long pfn)
        spin_lock(&early_pfn_lock);
        nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
        if (nid < 0)
-               nid = 0;
+               nid = first_online_node;
        spin_unlock(&early_pfn_lock);
 
        return nid;
index 4765c97ce6900d98b8ce2968cf9ff62a176f6e42..24a615d42d74f9bacd69e45372b871eeba89dbd1 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -4228,6 +4228,36 @@ static int __init slab_proc_init(void)
 module_init(slab_proc_init);
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
+/*
+ * Rejects objects that are incorrectly sized.
+ *
+ * Returns NULL if check passes, otherwise const char * to name of cache
+ * to indicate an error.
+ */
+const char *__check_heap_object(const void *ptr, unsigned long n,
+                               struct page *page)
+{
+       struct kmem_cache *cachep;
+       unsigned int objnr;
+       unsigned long offset;
+
+       /* Find and validate object. */
+       cachep = page->slab_cache;
+       objnr = obj_to_index(cachep, page, (void *)ptr);
+       BUG_ON(objnr >= cachep->num);
+
+       /* Find offset within object. */
+       offset = ptr - index_to_obj(cachep, page, objnr) - obj_offset(cachep);
+
+       /* Allow address range falling entirely within object size. */
+       if (offset <= cachep->object_size && n <= cachep->object_size - offset)
+               return NULL;
+
+       return cachep->name;
+}
+#endif /* CONFIG_HARDENED_USERCOPY */
+
 /**
  * ksize - get the actual amount of memory allocated for a given object
  * @objp: Pointer to the object
index 3c6a86b4ec25f8462c1584dcb5bcf01e4edbd4ff..bec2fce9fafc33b81ff10d6fcd939b01712af770 100644 (file)
@@ -521,8 +521,8 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
                goto out_unlock;
 
        cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf));
-       cache_name = kasprintf(GFP_KERNEL, "%s(%d:%s)", root_cache->name,
-                              css->id, memcg_name_buf);
+       cache_name = kasprintf(GFP_KERNEL, "%s(%llu:%s)", root_cache->name,
+                              css->serial_nr, memcg_name_buf);
        if (!cache_name)
                goto out_unlock;
 
index 65d5f92d51d27ec1e0993cbe194eaaaae9bcd503..41f7cae64a49bfef91d0f992df18fa4aae0cefb7 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -124,6 +124,14 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 #endif
 }
 
+static inline void *fixup_red_left(struct kmem_cache *s, void *p)
+{
+       if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE)
+               p += s->red_left_pad;
+
+       return p;
+}
+
 static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
 {
 #ifdef CONFIG_SLUB_CPU_PARTIAL
@@ -224,24 +232,6 @@ static inline void stat(const struct kmem_cache *s, enum stat_item si)
  *                     Core slab cache functions
  *******************************************************************/
 
-/* Verify that a pointer has an address that is valid within a slab page */
-static inline int check_valid_pointer(struct kmem_cache *s,
-                               struct page *page, const void *object)
-{
-       void *base;
-
-       if (!object)
-               return 1;
-
-       base = page_address(page);
-       if (object < base || object >= base + page->objects * s->size ||
-               (object - base) % s->size) {
-               return 0;
-       }
-
-       return 1;
-}
-
 static inline void *get_freepointer(struct kmem_cache *s, void *object)
 {
        return *(void **)(object + s->offset);
@@ -271,12 +261,14 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
 
 /* Loop over all objects in a slab */
 #define for_each_object(__p, __s, __addr, __objects) \
-       for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\
-                       __p += (__s)->size)
+       for (__p = fixup_red_left(__s, __addr); \
+               __p < (__addr) + (__objects) * (__s)->size; \
+               __p += (__s)->size)
 
 #define for_each_object_idx(__p, __idx, __s, __addr, __objects) \
-       for (__p = (__addr), __idx = 1; __idx <= __objects;\
-                       __p += (__s)->size, __idx++)
+       for (__p = fixup_red_left(__s, __addr), __idx = 1; \
+               __idx <= __objects; \
+               __p += (__s)->size, __idx++)
 
 /* Determine object index from a given position */
 static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
@@ -456,6 +448,22 @@ static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map)
                set_bit(slab_index(p, s, addr), map);
 }
 
+static inline int size_from_object(struct kmem_cache *s)
+{
+       if (s->flags & SLAB_RED_ZONE)
+               return s->size - s->red_left_pad;
+
+       return s->size;
+}
+
+static inline void *restore_red_left(struct kmem_cache *s, void *p)
+{
+       if (s->flags & SLAB_RED_ZONE)
+               p -= s->red_left_pad;
+
+       return p;
+}
+
 /*
  * Debug settings:
  */
@@ -489,6 +497,26 @@ static inline void metadata_access_disable(void)
 /*
  * Object debugging
  */
+
+/* Verify that a pointer has an address that is valid within a slab page */
+static inline int check_valid_pointer(struct kmem_cache *s,
+                               struct page *page, void *object)
+{
+       void *base;
+
+       if (!object)
+               return 1;
+
+       base = page_address(page);
+       object = restore_red_left(s, object);
+       if (object < base || object >= base + page->objects * s->size ||
+               (object - base) % s->size) {
+               return 0;
+       }
+
+       return 1;
+}
+
 static void print_section(char *text, u8 *addr, unsigned int length)
 {
        metadata_access_enable();
@@ -628,7 +656,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
        pr_err("INFO: Object 0x%p @offset=%tu fp=0x%p\n\n",
               p, p - addr, get_freepointer(s, p));
 
-       if (p > addr + 16)
+       if (s->flags & SLAB_RED_ZONE)
+               print_section("Redzone ", p - s->red_left_pad, s->red_left_pad);
+       else if (p > addr + 16)
                print_section("Bytes b4 ", p - 16, 16);
 
        print_section("Object ", p, min_t(unsigned long, s->object_size,
@@ -645,9 +675,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
        if (s->flags & SLAB_STORE_USER)
                off += 2 * sizeof(struct track);
 
-       if (off != s->size)
+       if (off != size_from_object(s))
                /* Beginning of the filler is the free pointer */
-               print_section("Padding ", p + off, s->size - off);
+               print_section("Padding ", p + off, size_from_object(s) - off);
 
        dump_stack();
 }
@@ -677,6 +707,9 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
 {
        u8 *p = object;
 
+       if (s->flags & SLAB_RED_ZONE)
+               memset(p - s->red_left_pad, val, s->red_left_pad);
+
        if (s->flags & __OBJECT_POISON) {
                memset(p, POISON_FREE, s->object_size - 1);
                p[s->object_size - 1] = POISON_END;
@@ -769,11 +802,11 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
                /* We also have user information there */
                off += 2 * sizeof(struct track);
 
-       if (s->size == off)
+       if (size_from_object(s) == off)
                return 1;
 
        return check_bytes_and_report(s, page, p, "Object padding",
-                               p + off, POISON_INUSE, s->size - off);
+                       p + off, POISON_INUSE, size_from_object(s) - off);
 }
 
 /* Check the pad bytes at the end of a slab page */
@@ -817,6 +850,10 @@ static int check_object(struct kmem_cache *s, struct page *page,
        u8 *endobject = object + s->object_size;
 
        if (s->flags & SLAB_RED_ZONE) {
+               if (!check_bytes_and_report(s, page, object, "Redzone",
+                       object - s->red_left_pad, val, s->red_left_pad))
+                       return 0;
+
                if (!check_bytes_and_report(s, page, object, "Redzone",
                        endobject, val, s->inuse - s->object_size))
                        return 0;
@@ -1468,7 +1505,7 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                        set_freepointer(s, p, NULL);
        }
 
-       page->freelist = start;
+       page->freelist = fixup_red_left(s, start);
        page->inuse = page->objects;
        page->frozen = 1;
 
@@ -3283,7 +3320,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                 */
                size += 2 * sizeof(struct track);
 
-       if (flags & SLAB_RED_ZONE)
+       if (flags & SLAB_RED_ZONE) {
                /*
                 * Add some empty padding so that we can catch
                 * overwrites from earlier objects rather than let
@@ -3292,6 +3329,11 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                 * of the object.
                 */
                size += sizeof(void *);
+
+               s->red_left_pad = sizeof(void *);
+               s->red_left_pad = ALIGN(s->red_left_pad, s->align);
+               size += s->red_left_pad;
+       }
 #endif
 
        /*
@@ -3585,6 +3627,46 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
 EXPORT_SYMBOL(__kmalloc_node);
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
+/*
+ * Rejects objects that are incorrectly sized.
+ *
+ * Returns NULL if check passes, otherwise const char * to name of cache
+ * to indicate an error.
+ */
+const char *__check_heap_object(const void *ptr, unsigned long n,
+                               struct page *page)
+{
+       struct kmem_cache *s;
+       unsigned long offset;
+       size_t object_size;
+
+       /* Find object and usable object size. */
+       s = page->slab_cache;
+       object_size = slab_ksize(s);
+
+       /* Reject impossible pointers. */
+       if (ptr < page_address(page))
+               return s->name;
+
+       /* Find offset within object. */
+       offset = (ptr - page_address(page)) % s->size;
+
+       /* Adjust for redzone and reject if within the redzone. */
+       if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) {
+               if (offset < s->red_left_pad)
+                       return s->name;
+               offset -= s->red_left_pad;
+       }
+
+       /* Allow address range falling entirely within object size. */
+       if (offset <= object_size && n <= object_size - offset)
+               return NULL;
+
+       return s->name;
+}
+#endif /* CONFIG_HARDENED_USERCOPY */
+
 static size_t __ksize(const void *object)
 {
        struct page *page;
diff --git a/mm/usercopy.c b/mm/usercopy.c
new file mode 100644 (file)
index 0000000..b34996a
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * This implements the various checks for CONFIG_HARDENED_USERCOPY*,
+ * which are designed to protect kernel memory from needless exposure
+ * and overwrite under many unintended conditions. This code is based
+ * on PAX_USERCOPY, which is:
+ *
+ * Copyright (C) 2001-2016 PaX Team, Bradley Spengler, Open Source
+ * Security Inc.
+ *
+ * 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/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <asm/sections.h>
+
+enum {
+       BAD_STACK = -1,
+       NOT_STACK = 0,
+       GOOD_FRAME,
+       GOOD_STACK,
+};
+
+/*
+ * Checks if a given pointer and length is contained by the current
+ * stack frame (if possible).
+ *
+ * Returns:
+ *     NOT_STACK: not at all on the stack
+ *     GOOD_FRAME: fully within a valid stack frame
+ *     GOOD_STACK: fully on the stack (when can't do frame-checking)
+ *     BAD_STACK: error condition (invalid stack position or bad stack frame)
+ */
+static noinline int check_stack_object(const void *obj, unsigned long len)
+{
+       const void * const stack = task_stack_page(current);
+       const void * const stackend = stack + THREAD_SIZE;
+       int ret;
+
+       /* Object is not on the stack at all. */
+       if (obj + len <= stack || stackend <= obj)
+               return NOT_STACK;
+
+       /*
+        * Reject: object partially overlaps the stack (passing the
+        * the check above means at least one end is within the stack,
+        * so if this check fails, the other end is outside the stack).
+        */
+       if (obj < stack || stackend < obj + len)
+               return BAD_STACK;
+
+       /* Check if object is safely within a valid frame. */
+       ret = arch_within_stack_frames(stack, stackend, obj, len);
+       if (ret)
+               return ret;
+
+       return GOOD_STACK;
+}
+
+static void report_usercopy(const void *ptr, unsigned long len,
+                           bool to_user, const char *type)
+{
+       pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
+               to_user ? "exposure" : "overwrite",
+               to_user ? "from" : "to", ptr, type ? : "unknown", len);
+       /*
+        * For greater effect, it would be nice to do do_group_exit(),
+        * but BUG() actually hooks all the lock-breaking and per-arch
+        * Oops code, so that is used here instead.
+        */
+       BUG();
+}
+
+/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */
+static bool overlaps(const void *ptr, unsigned long n, unsigned long low,
+                    unsigned long high)
+{
+       unsigned long check_low = (uintptr_t)ptr;
+       unsigned long check_high = check_low + n;
+
+       /* Does not overlap if entirely above or entirely below. */
+       if (check_low >= high || check_high <= low)
+               return false;
+
+       return true;
+}
+
+/* Is this address range in the kernel text area? */
+static inline const char *check_kernel_text_object(const void *ptr,
+                                                  unsigned long n)
+{
+       unsigned long textlow = (unsigned long)_stext;
+       unsigned long texthigh = (unsigned long)_etext;
+       unsigned long textlow_linear, texthigh_linear;
+
+       if (overlaps(ptr, n, textlow, texthigh))
+               return "<kernel text>";
+
+       /*
+        * Some architectures have virtual memory mappings with a secondary
+        * mapping of the kernel text, i.e. there is more than one virtual
+        * kernel address that points to the kernel image. It is usually
+        * when there is a separate linear physical memory mapping, in that
+        * __pa() is not just the reverse of __va(). This can be detected
+        * and checked:
+        */
+       textlow_linear = (unsigned long)__va(__pa(textlow));
+       /* No different mapping: we're done. */
+       if (textlow_linear == textlow)
+               return NULL;
+
+       /* Check the secondary mapping... */
+       texthigh_linear = (unsigned long)__va(__pa(texthigh));
+       if (overlaps(ptr, n, textlow_linear, texthigh_linear))
+               return "<linear kernel text>";
+
+       return NULL;
+}
+
+static inline const char *check_bogus_address(const void *ptr, unsigned long n)
+{
+       /* Reject if object wraps past end of memory. */
+       if ((unsigned long)ptr + n < (unsigned long)ptr)
+               return "<wrapped address>";
+
+       /* Reject if NULL or ZERO-allocation. */
+       if (ZERO_OR_NULL_PTR(ptr))
+               return "<null>";
+
+       return NULL;
+}
+
+/* Checks for allocs that are marked in some way as spanning multiple pages. */
+static inline const char *check_page_span(const void *ptr, unsigned long n,
+                                         struct page *page, bool to_user)
+{
+#ifdef CONFIG_HARDENED_USERCOPY_PAGESPAN
+       const void *end = ptr + n - 1;
+       struct page *endpage;
+       bool is_reserved, is_cma;
+
+       /*
+        * Sometimes the kernel data regions are not marked Reserved (see
+        * check below). And sometimes [_sdata,_edata) does not cover
+        * rodata and/or bss, so check each range explicitly.
+        */
+
+       /* Allow reads of kernel rodata region (if not marked as Reserved). */
+       if (ptr >= (const void *)__start_rodata &&
+           end <= (const void *)__end_rodata) {
+               if (!to_user)
+                       return "<rodata>";
+               return NULL;
+       }
+
+       /* Allow kernel data region (if not marked as Reserved). */
+       if (ptr >= (const void *)_sdata && end <= (const void *)_edata)
+               return NULL;
+
+       /* Allow kernel bss region (if not marked as Reserved). */
+       if (ptr >= (const void *)__bss_start &&
+           end <= (const void *)__bss_stop)
+               return NULL;
+
+       /* Is the object wholly within one base page? */
+       if (likely(((unsigned long)ptr & (unsigned long)PAGE_MASK) ==
+                  ((unsigned long)end & (unsigned long)PAGE_MASK)))
+               return NULL;
+
+       /* Allow if fully inside the same compound (__GFP_COMP) page. */
+       endpage = virt_to_head_page(end);
+       if (likely(endpage == page))
+               return NULL;
+
+       /*
+        * Reject if range is entirely either Reserved (i.e. special or
+        * device memory), or CMA. Otherwise, reject since the object spans
+        * several independently allocated pages.
+        */
+       is_reserved = PageReserved(page);
+       is_cma = is_migrate_cma_page(page);
+       if (!is_reserved && !is_cma)
+               return "<spans multiple pages>";
+
+       for (ptr += PAGE_SIZE; ptr <= end; ptr += PAGE_SIZE) {
+               page = virt_to_head_page(ptr);
+               if (is_reserved && !PageReserved(page))
+                       return "<spans Reserved and non-Reserved pages>";
+               if (is_cma && !is_migrate_cma_page(page))
+                       return "<spans CMA and non-CMA pages>";
+       }
+#endif
+
+       return NULL;
+}
+
+static inline const char *check_heap_object(const void *ptr, unsigned long n,
+                                           bool to_user)
+{
+       struct page *page;
+
+       /*
+        * Some architectures (arm64) return true for virt_addr_valid() on
+        * vmalloced addresses. Work around this by checking for vmalloc
+        * first.
+        */
+       if (is_vmalloc_addr(ptr))
+               return NULL;
+
+       if (!virt_addr_valid(ptr))
+               return NULL;
+
+       page = virt_to_head_page(ptr);
+
+       /* Check slab allocator for flags and size. */
+       if (PageSlab(page))
+               return __check_heap_object(ptr, n, page);
+
+       /* Verify object does not incorrectly span multiple pages. */
+       return check_page_span(ptr, n, page, to_user);
+}
+
+/*
+ * Validates that the given object is:
+ * - not bogus address
+ * - known-safe heap or stack object
+ * - not in kernel text
+ */
+void __check_object_size(const void *ptr, unsigned long n, bool to_user)
+{
+       const char *err;
+
+       /* Skip all tests if size is zero. */
+       if (!n)
+               return;
+
+       /* Check for invalid addresses. */
+       err = check_bogus_address(ptr, n);
+       if (err)
+               goto report;
+
+       /* Check for bad heap object. */
+       err = check_heap_object(ptr, n, to_user);
+       if (err)
+               goto report;
+
+       /* Check for bad stack object. */
+       switch (check_stack_object(ptr, n)) {
+       case NOT_STACK:
+               /* Object is not touching the current process stack. */
+               break;
+       case GOOD_FRAME:
+       case GOOD_STACK:
+               /*
+                * Object is either in the correct frame (when it
+                * is possible to check) or just generally on the
+                * process stack (when frame checking not available).
+                */
+               return;
+       default:
+               err = "<process stack>";
+               goto report;
+       }
+
+       /* Check for object in kernel to avoid text exposure. */
+       err = check_kernel_text_object(ptr, n);
+       if (!err)
+               return;
+
+report:
+       report_usercopy(ptr, n, to_user, err);
+}
+EXPORT_SYMBOL(__check_object_size);
index 9af1c12b310c7f092f030fc1a4303c287724b0a6..d5259b62f8d770eca8a9b1921fdd603f5f8be998 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -199,36 +199,11 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
 }
 
 /* Check if the vma is being used as a stack by this task */
-static int vm_is_stack_for_task(struct task_struct *t,
-                               struct vm_area_struct *vma)
+int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t)
 {
        return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
 }
 
-/*
- * Check if the vma is being used as a stack.
- * If is_group is non-zero, check in the entire thread group or else
- * just check in the current task. Returns the task_struct of the task
- * that the vma is stack for. Must be called under rcu_read_lock().
- */
-struct task_struct *task_of_stack(struct task_struct *task,
-                               struct vm_area_struct *vma, bool in_group)
-{
-       if (vm_is_stack_for_task(task, vma))
-               return task;
-
-       if (in_group) {
-               struct task_struct *t;
-
-               for_each_thread(task, t) {
-                       if (vm_is_stack_for_task(t, vma))
-                               return t;
-               }
-       }
-
-       return NULL;
-}
-
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
index 0c114e2b01d34a43721e11d9a766cae7c35ae485..0838e9f02b11e778afe0a3da51698f54c54d5051 100644 (file)
@@ -2159,23 +2159,6 @@ out:
        }
 }
 
-#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
-static void init_tlb_ubc(void)
-{
-       /*
-        * This deliberately does not clear the cpumask as it's expensive
-        * and unnecessary. If there happens to be data in there then the
-        * first SWAP_CLUSTER_MAX pages will send an unnecessary IPI and
-        * then will be cleared.
-        */
-       current->tlb_ubc.flush_required = false;
-}
-#else
-static inline void init_tlb_ubc(void)
-{
-}
-#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
-
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
@@ -2210,8 +2193,6 @@ static void shrink_lruvec(struct lruvec *lruvec, int swappiness,
        scan_adjusted = (global_reclaim(sc) && !current_is_kswapd() &&
                         sc->priority == DEF_PRIORITY);
 
-       init_tlb_ubc();
-
        blk_start_plug(&plug);
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
index c54fd2924f25af960462e474fa3583c633f9fcc8..83a003bc3cae54e3c2b1071249a5c282f70d3220 100644 (file)
@@ -460,7 +460,7 @@ static int fold_diff(int *diff)
  *
  * The function returns the number of global counters updated.
  */
-static int refresh_cpu_vm_stats(void)
+static int refresh_cpu_vm_stats(bool do_pagesets)
 {
        struct zone *zone;
        int i;
@@ -484,33 +484,35 @@ static int refresh_cpu_vm_stats(void)
 #endif
                        }
                }
-               cond_resched();
 #ifdef CONFIG_NUMA
-               /*
-                * Deal with draining the remote pageset of this
-                * processor
-                *
-                * Check if there are pages remaining in this pageset
-                * if not then there is nothing to expire.
-                */
-               if (!__this_cpu_read(p->expire) ||
+               if (do_pagesets) {
+                       cond_resched();
+                       /*
+                        * Deal with draining the remote pageset of this
+                        * processor
+                        *
+                        * Check if there are pages remaining in this pageset
+                        * if not then there is nothing to expire.
+                        */
+                       if (!__this_cpu_read(p->expire) ||
                               !__this_cpu_read(p->pcp.count))
-                       continue;
+                               continue;
 
-               /*
-                * We never drain zones local to this processor.
-                */
-               if (zone_to_nid(zone) == numa_node_id()) {
-                       __this_cpu_write(p->expire, 0);
-                       continue;
-               }
+                       /*
+                        * We never drain zones local to this processor.
+                        */
+                       if (zone_to_nid(zone) == numa_node_id()) {
+                               __this_cpu_write(p->expire, 0);
+                               continue;
+                       }
 
-               if (__this_cpu_dec_return(p->expire))
-                       continue;
+                       if (__this_cpu_dec_return(p->expire))
+                               continue;
 
-               if (__this_cpu_read(p->pcp.count)) {
-                       drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
-                       changes++;
+                       if (__this_cpu_read(p->pcp.count)) {
+                               drain_zone_pages(zone, this_cpu_ptr(&p->pcp));
+                               changes++;
+                       }
                }
 #endif
        }
@@ -1386,7 +1388,7 @@ static cpumask_var_t cpu_stat_off;
 
 static void vmstat_update(struct work_struct *w)
 {
-       if (refresh_cpu_vm_stats()) {
+       if (refresh_cpu_vm_stats(true)) {
                /*
                 * Counters were updated so we expect more updates
                 * to occur in the future. Keep on running the
@@ -1417,6 +1419,23 @@ static void vmstat_update(struct work_struct *w)
        }
 }
 
+/*
+ * Switch off vmstat processing and then fold all the remaining differentials
+ * until the diffs stay at zero. The function is used by NOHZ and can only be
+ * invoked when tick processing is not active.
+ */
+void quiet_vmstat(void)
+{
+       if (system_state != SYSTEM_RUNNING)
+               return;
+
+       do {
+               if (!cpumask_test_and_set_cpu(smp_processor_id(), cpu_stat_off))
+                       cancel_delayed_work(this_cpu_ptr(&vmstat_work));
+
+       } while (refresh_cpu_vm_stats(false));
+}
+
 /*
  * Check if the diffs for a certain cpu indicate that
  * an update is needed.
@@ -1449,7 +1468,7 @@ static bool need_update(int cpu)
  */
 static void vmstat_shepherd(struct work_struct *w);
 
-static DECLARE_DELAYED_WORK(shepherd, vmstat_shepherd);
+static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd);
 
 static void vmstat_shepherd(struct work_struct *w)
 {
index aa017133744b227bed7592ea6cc32f360c3e142c..df66f426fdcf523c4b0d6ccd9a63c2e4db823f17 100644 (file)
@@ -341,21 +341,19 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
         * no pages, so we expect to be able to remove them all and
         * delete and free the empty node afterwards.
         */
-
-       BUG_ON(!node->count);
-       BUG_ON(node->count & RADIX_TREE_COUNT_MASK);
+       BUG_ON(!workingset_node_shadows(node));
+       BUG_ON(workingset_node_pages(node));
 
        for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) {
                if (node->slots[i]) {
                        BUG_ON(!radix_tree_exceptional_entry(node->slots[i]));
                        node->slots[i] = NULL;
-                       BUG_ON(node->count < (1U << RADIX_TREE_COUNT_SHIFT));
-                       node->count -= 1U << RADIX_TREE_COUNT_SHIFT;
+                       workingset_node_shadows_dec(node);
                        BUG_ON(!mapping->nrshadows);
                        mapping->nrshadows--;
                }
        }
-       BUG_ON(node->count);
+       BUG_ON(workingset_node_shadows(node));
        inc_zone_state(page_zone(virt_to_page(node)), WORKINGSET_NODERECLAIM);
        if (!__radix_tree_delete_node(&mapping->page_tree, node))
                BUG();
index 17851d3aaf224626dc758a2b9b161e1a847444f2..6282f021ddfb68fd2a4ead55431b3e79b1f96192 100644 (file)
@@ -197,18 +197,12 @@ static void batadv_neigh_node_release(struct batadv_neigh_node *neigh_node)
 {
        struct hlist_node *node_tmp;
        struct batadv_neigh_ifinfo *neigh_ifinfo;
-       struct batadv_algo_ops *bao;
-
-       bao = neigh_node->orig_node->bat_priv->bat_algo_ops;
 
        hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
                                  &neigh_node->ifinfo_list, list) {
                batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
        }
 
-       if (bao->bat_neigh_free)
-               bao->bat_neigh_free(neigh_node);
-
        batadv_hardif_free_ref(neigh_node->if_incoming);
 
        kfree_rcu(neigh_node, rcu);
index d260efd70499bd62ceb7b86b57684f45a96612e9..cbd347c2e4a581c36405cb0b258ef0ad4ecb3e1e 100644 (file)
@@ -1136,8 +1136,6 @@ struct batadv_forw_packet {
  * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better
  *  than neigh2 for their respective outgoing interface from the metric
  *  prospective
- * @bat_neigh_free: free the resources allocated by the routing algorithm for a
- *  neigh_node object
  * @bat_orig_print: print the originator table (optional)
  * @bat_orig_free: free the resources allocated by the routing algorithm for an
  *  orig_node object
@@ -1165,7 +1163,6 @@ struct batadv_algo_ops {
                 struct batadv_hard_iface *if_outgoing1,
                 struct batadv_neigh_node *neigh2,
                 struct batadv_hard_iface *if_outgoing2);
-       void (*bat_neigh_free)(struct batadv_neigh_node *neigh);
        /* orig_node handling API */
        void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq,
                               struct batadv_hard_iface *hard_iface);
index 1bb5515270449e8115a0c169ea5b6380594c40a4..d9bbbded49ef87bb14c7e54c0731725bda6c8b32 100644 (file)
@@ -927,7 +927,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
                        break;
                }
 
-               if (get_user(opt, (u32 __user *) optval)) {
+               if (get_user(opt, (u16 __user *) optval)) {
                        err = -EFAULT;
                        break;
                }
index 7173a685309ac921a6b17eb92b637b6f51074214..9542e84a9455145dabcf7fc4c795f37d29958d6a 100644 (file)
@@ -1113,7 +1113,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
                } else {
                        err = br_ip6_multicast_add_group(br, port,
                                                         &grec->grec_mca, vid);
-                       if (!err)
+                       if (err)
                                break;
                }
        }
index f6c3b2137eeaacdc5cf38d1eac03e018d8f2d37b..59ce1fcc220ce0a71fb57733be7cc91e6b8ac7fc 100644 (file)
@@ -286,7 +286,7 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len)
                else
                        skb_trim(skb, len);
 
-                       return cfpkt_getlen(pkt);
+               return cfpkt_getlen(pkt);
        }
 
        /* Need to expand SKB */
index 7d8f581d9f1f7987b8d7051160c34f42ad2f5e73..ddc3573894b09cfe6ee9f6b9a5c81f6caf3cbfc9 100644 (file)
@@ -1191,6 +1191,115 @@ struct ceph_osdmap *ceph_osdmap_decode(void **p, void *end)
        return map;
 }
 
+/*
+ * Encoding order is (new_up_client, new_state, new_weight).  Need to
+ * apply in the (new_weight, new_state, new_up_client) order, because
+ * an incremental map may look like e.g.
+ *
+ *     new_up_client: { osd=6, addr=... } # set osd_state and addr
+ *     new_state: { osd=6, xorstate=EXISTS } # clear osd_state
+ */
+static int decode_new_up_state_weight(void **p, void *end,
+                                     struct ceph_osdmap *map)
+{
+       void *new_up_client;
+       void *new_state;
+       void *new_weight_end;
+       u32 len;
+
+       new_up_client = *p;
+       ceph_decode_32_safe(p, end, len, e_inval);
+       len *= sizeof(u32) + sizeof(struct ceph_entity_addr);
+       ceph_decode_need(p, end, len, e_inval);
+       *p += len;
+
+       new_state = *p;
+       ceph_decode_32_safe(p, end, len, e_inval);
+       len *= sizeof(u32) + sizeof(u8);
+       ceph_decode_need(p, end, len, e_inval);
+       *p += len;
+
+       /* new_weight */
+       ceph_decode_32_safe(p, end, len, e_inval);
+       while (len--) {
+               s32 osd;
+               u32 w;
+
+               ceph_decode_need(p, end, 2*sizeof(u32), e_inval);
+               osd = ceph_decode_32(p);
+               w = ceph_decode_32(p);
+               BUG_ON(osd >= map->max_osd);
+               pr_info("osd%d weight 0x%x %s\n", osd, w,
+                    w == CEPH_OSD_IN ? "(in)" :
+                    (w == CEPH_OSD_OUT ? "(out)" : ""));
+               map->osd_weight[osd] = w;
+
+               /*
+                * If we are marking in, set the EXISTS, and clear the
+                * AUTOOUT and NEW bits.
+                */
+               if (w) {
+                       map->osd_state[osd] |= CEPH_OSD_EXISTS;
+                       map->osd_state[osd] &= ~(CEPH_OSD_AUTOOUT |
+                                                CEPH_OSD_NEW);
+               }
+       }
+       new_weight_end = *p;
+
+       /* new_state (up/down) */
+       *p = new_state;
+       len = ceph_decode_32(p);
+       while (len--) {
+               s32 osd;
+               u8 xorstate;
+               int ret;
+
+               osd = ceph_decode_32(p);
+               xorstate = ceph_decode_8(p);
+               if (xorstate == 0)
+                       xorstate = CEPH_OSD_UP;
+               BUG_ON(osd >= map->max_osd);
+               if ((map->osd_state[osd] & CEPH_OSD_UP) &&
+                   (xorstate & CEPH_OSD_UP))
+                       pr_info("osd%d down\n", osd);
+               if ((map->osd_state[osd] & CEPH_OSD_EXISTS) &&
+                   (xorstate & CEPH_OSD_EXISTS)) {
+                       pr_info("osd%d does not exist\n", osd);
+                       map->osd_weight[osd] = CEPH_OSD_IN;
+                       ret = set_primary_affinity(map, osd,
+                                                  CEPH_OSD_DEFAULT_PRIMARY_AFFINITY);
+                       if (ret)
+                               return ret;
+                       memset(map->osd_addr + osd, 0, sizeof(*map->osd_addr));
+                       map->osd_state[osd] = 0;
+               } else {
+                       map->osd_state[osd] ^= xorstate;
+               }
+       }
+
+       /* new_up_client */
+       *p = new_up_client;
+       len = ceph_decode_32(p);
+       while (len--) {
+               s32 osd;
+               struct ceph_entity_addr addr;
+
+               osd = ceph_decode_32(p);
+               ceph_decode_copy(p, &addr, sizeof(addr));
+               ceph_decode_addr(&addr);
+               BUG_ON(osd >= map->max_osd);
+               pr_info("osd%d up\n", osd);
+               map->osd_state[osd] |= CEPH_OSD_EXISTS | CEPH_OSD_UP;
+               map->osd_addr[osd] = addr;
+       }
+
+       *p = new_weight_end;
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
 /*
  * decode and apply an incremental map update.
  */
@@ -1290,49 +1399,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                        __remove_pg_pool(&map->pg_pools, pi);
        }
 
-       /* new_up */
-       ceph_decode_32_safe(p, end, len, e_inval);
-       while (len--) {
-               u32 osd;
-               struct ceph_entity_addr addr;
-               ceph_decode_32_safe(p, end, osd, e_inval);
-               ceph_decode_copy_safe(p, end, &addr, sizeof(addr), e_inval);
-               ceph_decode_addr(&addr);
-               pr_info("osd%d up\n", osd);
-               BUG_ON(osd >= map->max_osd);
-               map->osd_state[osd] |= CEPH_OSD_UP | CEPH_OSD_EXISTS;
-               map->osd_addr[osd] = addr;
-       }
-
-       /* new_state */
-       ceph_decode_32_safe(p, end, len, e_inval);
-       while (len--) {
-               u32 osd;
-               u8 xorstate;
-               ceph_decode_32_safe(p, end, osd, e_inval);
-               xorstate = **(u8 **)p;
-               (*p)++;  /* clean flag */
-               if (xorstate == 0)
-                       xorstate = CEPH_OSD_UP;
-               if (xorstate & CEPH_OSD_UP)
-                       pr_info("osd%d down\n", osd);
-               if (osd < map->max_osd)
-                       map->osd_state[osd] ^= xorstate;
-       }
-
-       /* new_weight */
-       ceph_decode_32_safe(p, end, len, e_inval);
-       while (len--) {
-               u32 osd, off;
-               ceph_decode_need(p, end, sizeof(u32)*2, e_inval);
-               osd = ceph_decode_32(p);
-               off = ceph_decode_32(p);
-               pr_info("osd%d weight 0x%x %s\n", osd, off,
-                    off == CEPH_OSD_IN ? "(in)" :
-                    (off == CEPH_OSD_OUT ? "(out)" : ""));
-               if (osd < map->max_osd)
-                       map->osd_weight[osd] = off;
-       }
+       /* new_up_client, new_state, new_weight */
+       err = decode_new_up_state_weight(p, end, map);
+       if (err)
+               goto bad;
 
        /* new_pg_temp */
        err = decode_new_pg_temp(p, end, map);
index 9efbdb3ff78a0098b83f60e0c626da933035e983..0989fea88c4480ed88086c628dd7d7cf832e37eb 100644 (file)
@@ -3721,6 +3721,22 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb,
        return skb;
 }
 
+/**
+ *     netdev_is_rx_handler_busy - check if receive handler is registered
+ *     @dev: device to check
+ *
+ *     Check if a receive handler is already registered for a given device.
+ *     Return true if there one.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+bool netdev_is_rx_handler_busy(struct net_device *dev)
+{
+       ASSERT_RTNL();
+       return dev && rtnl_dereference(dev->rx_handler);
+}
+EXPORT_SYMBOL_GPL(netdev_is_rx_handler_busy);
+
 /**
  *     netdev_rx_handler_register - register receive handler
  *     @dev: device to register a handler for
@@ -4223,7 +4239,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
                NAPI_GRO_CB(skb)->free = 0;
-               NAPI_GRO_CB(skb)->udp_mark = 0;
+               NAPI_GRO_CB(skb)->encap_mark = 0;
                NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
 
                /* Setup for GRO checksum validation */
index eb12bd0ff9d336c801c89197989ed75ce6c38b9b..caa6f158a0775d5dd86b6e76198dbca5290c33b0 100644 (file)
@@ -1398,6 +1398,19 @@ out:
        return pp;
 }
 
+static struct sk_buff **ipip_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       if (NAPI_GRO_CB(skb)->encap_mark) {
+               NAPI_GRO_CB(skb)->flush = 1;
+               return NULL;
+       }
+
+       NAPI_GRO_CB(skb)->encap_mark = 1;
+
+       return inet_gro_receive(head, skb);
+}
+
 int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 {
        if (sk->sk_family == AF_INET)
@@ -1440,6 +1453,13 @@ out_unlock:
        return err;
 }
 
+static int ipip_gro_complete(struct sk_buff *skb, int nhoff)
+{
+       skb->encapsulation = 1;
+       skb_shinfo(skb)->gso_type |= SKB_GSO_IPIP;
+       return inet_gro_complete(skb, nhoff);
+}
+
 int inet_ctl_sock_create(struct sock **sk, unsigned short family,
                         unsigned short type, unsigned char protocol,
                         struct net *net)
@@ -1667,8 +1687,8 @@ static struct packet_offload ip_packet_offload __read_mostly = {
 static const struct net_offload ipip_offload = {
        .callbacks = {
                .gso_segment    = inet_gso_segment,
-               .gro_receive    = inet_gro_receive,
-               .gro_complete   = inet_gro_complete,
+               .gro_receive    = ipip_gro_receive,
+               .gro_complete   = ipip_gro_complete,
        },
 };
 
index 2b68418c7198009e2477961c4b34503dc1439526..ffe95d954007d8eb56be68a4f926ec715227b4e8 100644 (file)
@@ -479,6 +479,9 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
                if (!rtnh_ok(rtnh, remaining))
                        return -EINVAL;
 
+               if (rtnh->rtnh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
+                       return -EINVAL;
+
                nexthop_nh->nh_flags =
                        (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
                nexthop_nh->nh_oif = rtnh->rtnh_ifindex;
@@ -1003,6 +1006,9 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
        if (fib_props[cfg->fc_type].scope > cfg->fc_scope)
                goto err_inval;
 
+       if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
+               goto err_inval;
+
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        if (cfg->fc_mp) {
                nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len);
index 744e5936c10d7ec555d1ca621f5bd4be57f1c72b..e5a3ff210fec57aa835ba0a735509bbcb8f7afdd 100644 (file)
@@ -2453,9 +2453,7 @@ struct fib_route_iter {
 static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
                                            loff_t pos)
 {
-       struct fib_table *tb = iter->main_tb;
        struct key_vector *l, **tp = &iter->tnode;
-       struct trie *t;
        t_key key;
 
        /* use cache location of next-to-find key */
@@ -2463,8 +2461,6 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
                pos -= iter->pos;
                key = iter->key;
        } else {
-               t = (struct trie *)tb->tb_data;
-               iter->tnode = t->kv;
                iter->pos = 0;
                key = 0;
        }
@@ -2505,12 +2501,12 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
                return NULL;
 
        iter->main_tb = tb;
+       t = (struct trie *)tb->tb_data;
+       iter->tnode = t->kv;
 
        if (*pos != 0)
                return fib_route_get_idx(iter, *pos);
 
-       t = (struct trie *)tb->tb_data;
-       iter->tnode = t->kv;
        iter->pos = 0;
        iter->key = 0;
 
index bd903fe0f7508d9d7a94c4ce1e0a825f3e35c398..08d7de55e57edf23a8b1425e3dda1b6d51fb671b 100644 (file)
@@ -48,7 +48,7 @@ static inline struct fou *fou_from_sock(struct sock *sk)
        return sk->sk_user_data;
 }
 
-static void fou_recv_pull(struct sk_buff *skb, size_t len)
+static int fou_recv_pull(struct sk_buff *skb, size_t len)
 {
        struct iphdr *iph = ip_hdr(skb);
 
@@ -59,6 +59,7 @@ static void fou_recv_pull(struct sk_buff *skb, size_t len)
        __skb_pull(skb, len);
        skb_postpull_rcsum(skb, udp_hdr(skb), len);
        skb_reset_transport_header(skb);
+       return iptunnel_pull_offloads(skb);
 }
 
 static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
@@ -68,9 +69,14 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
        if (!fou)
                return 1;
 
-       fou_recv_pull(skb, sizeof(struct udphdr));
+       if (fou_recv_pull(skb, sizeof(struct udphdr)))
+               goto drop;
 
        return -fou->protocol;
+
+drop:
+       kfree_skb(skb);
+       return 0;
 }
 
 static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr,
@@ -170,6 +176,9 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
        __skb_pull(skb, sizeof(struct udphdr) + hdrlen);
        skb_reset_transport_header(skb);
 
+       if (iptunnel_pull_offloads(skb))
+               goto drop;
+
        return -guehdr->proto_ctype;
 
 drop:
index 5a8ee3282550880a7749b8d6a9086dc413661519..e603004c1af8293f0d8b919a5c1f2023bc4ceebd 100644 (file)
@@ -128,6 +128,11 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
        struct packet_offload *ptype;
        __be16 type;
 
+       if (NAPI_GRO_CB(skb)->encap_mark)
+               goto out;
+
+       NAPI_GRO_CB(skb)->encap_mark = 1;
+
        off = skb_gro_offset(skb);
        hlen = off + sizeof(*greh);
        greh = skb_gro_header_fast(skb, off);
index a403a676d452d050f4518cec52631aa6823800cf..fcb83b2a61f00681e1d918c0ec862c051d537e71 100644 (file)
@@ -44,6 +44,8 @@ struct inet_diag_entry {
        u16 dport;
        u16 family;
        u16 userlocks;
+       u32 ifindex;
+       u32 mark;
 };
 
 static DEFINE_MUTEX(inet_diag_table_mutex);
@@ -96,6 +98,7 @@ static size_t inet_sk_attr_size(void)
                + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
                + nla_total_size(1) /* INET_DIAG_TOS */
                + nla_total_size(1) /* INET_DIAG_TCLASS */
+               + nla_total_size(4) /* INET_DIAG_MARK */
                + nla_total_size(sizeof(struct inet_diag_meminfo))
                + nla_total_size(sizeof(struct inet_diag_msg))
                + nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
@@ -108,7 +111,8 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                      struct sk_buff *skb, const struct inet_diag_req_v2 *req,
                      struct user_namespace *user_ns,
                      u32 portid, u32 seq, u16 nlmsg_flags,
-                     const struct nlmsghdr *unlh)
+                     const struct nlmsghdr *unlh,
+                     bool net_admin)
 {
        const struct inet_sock *inet = inet_sk(sk);
        const struct tcp_congestion_ops *ca_ops;
@@ -158,6 +162,9 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
        }
 #endif
 
+       if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark))
+               goto errout;
+
        r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
        r->idiag_inode = sock_i_ino(sk);
 
@@ -256,10 +263,11 @@ static int inet_csk_diag_fill(struct sock *sk,
                              const struct inet_diag_req_v2 *req,
                              struct user_namespace *user_ns,
                              u32 portid, u32 seq, u16 nlmsg_flags,
-                             const struct nlmsghdr *unlh)
+                             const struct nlmsghdr *unlh,
+                             bool net_admin)
 {
-       return inet_sk_diag_fill(sk, inet_csk(sk), skb, req,
-                                user_ns, portid, seq, nlmsg_flags, unlh);
+       return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, user_ns,
+                                portid, seq, nlmsg_flags, unlh, net_admin);
 }
 
 static int inet_twsk_diag_fill(struct sock *sk,
@@ -301,8 +309,9 @@ static int inet_twsk_diag_fill(struct sock *sk,
 
 static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
                              u32 portid, u32 seq, u16 nlmsg_flags,
-                             const struct nlmsghdr *unlh)
+                             const struct nlmsghdr *unlh, bool net_admin)
 {
+       struct request_sock *reqsk = inet_reqsk(sk);
        struct inet_diag_msg *r;
        struct nlmsghdr *nlh;
        long tmo;
@@ -316,7 +325,7 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
        inet_diag_msg_common_fill(r, sk);
        r->idiag_state = TCP_SYN_RECV;
        r->idiag_timer = 1;
-       r->idiag_retrans = inet_reqsk(sk)->num_retrans;
+       r->idiag_retrans = reqsk->num_retrans;
 
        BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) !=
                     offsetof(struct sock, sk_cookie));
@@ -328,6 +337,10 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
        r->idiag_uid    = 0;
        r->idiag_inode  = 0;
 
+       if (net_admin && nla_put_u32(skb, INET_DIAG_MARK,
+                                    inet_rsk(reqsk)->ir_mark))
+               return -EMSGSIZE;
+
        nlmsg_end(skb, nlh);
        return 0;
 }
@@ -336,7 +349,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
                        const struct inet_diag_req_v2 *r,
                        struct user_namespace *user_ns,
                        u32 portid, u32 seq, u16 nlmsg_flags,
-                       const struct nlmsghdr *unlh)
+                       const struct nlmsghdr *unlh, bool net_admin)
 {
        if (sk->sk_state == TCP_TIME_WAIT)
                return inet_twsk_diag_fill(sk, skb, portid, seq,
@@ -344,10 +357,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
 
        if (sk->sk_state == TCP_NEW_SYN_RECV)
                return inet_req_diag_fill(sk, skb, portid, seq,
-                                         nlmsg_flags, unlh);
+                                         nlmsg_flags, unlh, net_admin);
 
        return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq,
-                                 nlmsg_flags, unlh);
+                                 nlmsg_flags, unlh, net_admin);
 }
 
 struct sock *inet_diag_find_one_icsk(struct net *net,
@@ -414,7 +427,8 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
        err = sk_diag_fill(sk, rep, req,
                           sk_user_ns(NETLINK_CB(in_skb).sk),
                           NETLINK_CB(in_skb).portid,
-                          nlh->nlmsg_seq, 0, nlh);
+                          nlh->nlmsg_seq, 0, nlh,
+                          netlink_net_capable(in_skb, CAP_NET_ADMIN));
        if (err < 0) {
                WARN_ON(err == -EMSGSIZE);
                nlmsg_free(rep);
@@ -552,6 +566,22 @@ static int inet_diag_bc_run(const struct nlattr *_bc,
                        yes = 0;
                        break;
                }
+               case INET_DIAG_BC_DEV_COND: {
+                       u32 ifindex;
+
+                       ifindex = *((const u32 *)(op + 1));
+                       if (ifindex != entry->ifindex)
+                               yes = 0;
+                       break;
+               }
+               case INET_DIAG_BC_MARK_COND: {
+                       struct inet_diag_markcond *cond;
+
+                       cond = (struct inet_diag_markcond *)(op + 1);
+                       if ((entry->mark & cond->mask) != cond->mark)
+                               yes = 0;
+                       break;
+               }
                }
 
                if (yes) {
@@ -594,7 +624,14 @@ int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk)
        entry_fill_addrs(&entry, sk);
        entry.sport = inet->inet_num;
        entry.dport = ntohs(inet->inet_dport);
+       entry.ifindex = sk->sk_bound_dev_if;
        entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0;
+       if (sk_fullsock(sk))
+               entry.mark = sk->sk_mark;
+       else if (sk->sk_state == TCP_NEW_SYN_RECV)
+               entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark;
+       else
+               entry.mark = 0;
 
        return inet_diag_bc_run(bc, &entry);
 }
@@ -617,6 +654,17 @@ static int valid_cc(const void *bc, int len, int cc)
        return 0;
 }
 
+/* data is u32 ifindex */
+static bool valid_devcond(const struct inet_diag_bc_op *op, int len,
+                         int *min_len)
+{
+       /* Check ifindex space. */
+       *min_len += sizeof(u32);
+       if (len < *min_len)
+               return false;
+
+       return true;
+}
 /* Validate an inet_diag_hostcond. */
 static bool valid_hostcond(const struct inet_diag_bc_op *op, int len,
                           int *min_len)
@@ -666,10 +714,25 @@ static bool valid_port_comparison(const struct inet_diag_bc_op *op,
        return true;
 }
 
-static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
+static bool valid_markcond(const struct inet_diag_bc_op *op, int len,
+                          int *min_len)
+{
+       *min_len += sizeof(struct inet_diag_markcond);
+       return len >= *min_len;
+}
+
+static int inet_diag_bc_audit(const struct nlattr *attr,
+                             const struct sk_buff *skb)
 {
-       const void *bc = bytecode;
-       int  len = bytecode_len;
+       bool net_admin = netlink_net_capable(skb, CAP_NET_ADMIN);
+       const void *bytecode, *bc;
+       int bytecode_len, len;
+
+       if (!attr || nla_len(attr) < sizeof(struct inet_diag_bc_op))
+               return -EINVAL;
+
+       bytecode = bc = nla_data(attr);
+       len = bytecode_len = nla_len(attr);
 
        while (len > 0) {
                int min_len = sizeof(struct inet_diag_bc_op);
@@ -681,6 +744,10 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
                        if (!valid_hostcond(bc, len, &min_len))
                                return -EINVAL;
                        break;
+               case INET_DIAG_BC_DEV_COND:
+                       if (!valid_devcond(bc, len, &min_len))
+                               return -EINVAL;
+                       break;
                case INET_DIAG_BC_S_GE:
                case INET_DIAG_BC_S_LE:
                case INET_DIAG_BC_D_GE:
@@ -688,6 +755,12 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
                        if (!valid_port_comparison(bc, len, &min_len))
                                return -EINVAL;
                        break;
+               case INET_DIAG_BC_MARK_COND:
+                       if (!net_admin)
+                               return -EPERM;
+                       if (!valid_markcond(bc, len, &min_len))
+                               return -EINVAL;
+                       break;
                case INET_DIAG_BC_AUTO:
                case INET_DIAG_BC_JMP:
                case INET_DIAG_BC_NOP:
@@ -716,7 +789,8 @@ static int inet_csk_diag_dump(struct sock *sk,
                              struct sk_buff *skb,
                              struct netlink_callback *cb,
                              const struct inet_diag_req_v2 *r,
-                             const struct nlattr *bc)
+                             const struct nlattr *bc,
+                             bool net_admin)
 {
        if (!inet_diag_bc_sk(bc, sk))
                return 0;
@@ -724,7 +798,8 @@ static int inet_csk_diag_dump(struct sock *sk,
        return inet_csk_diag_fill(sk, skb, r,
                                  sk_user_ns(NETLINK_CB(cb->skb).sk),
                                  NETLINK_CB(cb->skb).portid,
-                                 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
+                                 cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh,
+                                 net_admin);
 }
 
 static void twsk_build_assert(void)
@@ -760,6 +835,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
        struct net *net = sock_net(skb->sk);
        int i, num, s_i, s_num;
        u32 idiag_states = r->idiag_states;
+       bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
 
        if (idiag_states & TCPF_SYN_RECV)
                idiag_states |= TCPF_NEW_SYN_RECV;
@@ -801,7 +877,8 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
                                    cb->args[3] > 0)
                                        goto next_listen;
 
-                               if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
+                               if (inet_csk_diag_dump(sk, skb, cb, r,
+                                                      bc, net_admin) < 0) {
                                        spin_unlock_bh(&ilb->lock);
                                        goto done;
                                }
@@ -869,7 +946,7 @@ skip_listen_ht:
                                           sk_user_ns(NETLINK_CB(cb->skb).sk),
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                          cb->nlh);
+                                          cb->nlh, net_admin);
                        if (res < 0) {
                                spin_unlock_bh(lock);
                                goto done;
@@ -976,13 +1053,13 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
                if (nlmsg_attrlen(nlh, hdrlen)) {
                        struct nlattr *attr;
+                       int err;
 
                        attr = nlmsg_find_attr(nlh, hdrlen,
                                               INET_DIAG_REQ_BYTECODE);
-                       if (!attr ||
-                           nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
-                           inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
-                               return -EINVAL;
+                       err = inet_diag_bc_audit(attr, skb);
+                       if (err)
+                               return err;
                }
                {
                        struct netlink_dump_control c = {
@@ -1007,13 +1084,13 @@ static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h)
            h->nlmsg_flags & NLM_F_DUMP) {
                if (nlmsg_attrlen(h, hdrlen)) {
                        struct nlattr *attr;
+                       int err;
 
                        attr = nlmsg_find_attr(h, hdrlen,
                                               INET_DIAG_REQ_BYTECODE);
-                       if (!attr ||
-                           nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
-                           inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
-                               return -EINVAL;
+                       err = inet_diag_bc_audit(attr, skb);
+                       if (err)
+                               return err;
                }
                {
                        struct netlink_dump_control c = {
index 6cb9009c3d96785e566a3cb2cd065860e05980e1..dbda0565781cfe8ae1486994b3fe0795d736f71e 100644 (file)
@@ -116,7 +116,8 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
        skb->vlan_tci = 0;
        skb_set_queue_mapping(skb, 0);
        skb->pkt_type = PACKET_HOST;
-       return 0;
+
+       return iptunnel_pull_offloads(skb);
 }
 EXPORT_SYMBOL_GPL(iptunnel_pull_header);
 
index 4d8f0b6987777ab6c096fadbce538c53cbcad24b..65036891e080e56434f914b27a3f7c03885a2666 100644 (file)
@@ -540,6 +540,33 @@ static struct rtnl_link_ops vti_link_ops __read_mostly = {
        .get_link_net   = ip_tunnel_get_link_net,
 };
 
+static bool is_vti_tunnel(const struct net_device *dev)
+{
+       return dev->netdev_ops == &vti_netdev_ops;
+}
+
+static int vti_device_event(struct notifier_block *unused,
+                           unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+
+       if (!is_vti_tunnel(dev))
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_DOWN:
+               if (!net_eq(tunnel->net, dev_net(dev)))
+                       xfrm_garbage_collect(tunnel->net);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block vti_notifier_block __read_mostly = {
+       .notifier_call = vti_device_event,
+};
+
 static int __init vti_init(void)
 {
        const char *msg;
@@ -547,6 +574,8 @@ static int __init vti_init(void)
 
        pr_info("IPv4 over IPsec tunneling driver\n");
 
+       register_netdevice_notifier(&vti_notifier_block);
+
        msg = "tunnel device";
        err = register_pernet_device(&vti_net_ops);
        if (err < 0)
@@ -579,6 +608,7 @@ xfrm_proto_ah_failed:
 xfrm_proto_esp_failed:
        unregister_pernet_device(&vti_net_ops);
 pernet_dev_failed:
+       unregister_netdevice_notifier(&vti_notifier_block);
        pr_err("vti init: failed to register %s\n", msg);
        return err;
 }
@@ -590,6 +620,7 @@ static void __exit vti_fini(void)
        xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
        xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
        unregister_pernet_device(&vti_net_ops);
+       unregister_netdevice_notifier(&vti_notifier_block);
 }
 
 module_init(vti_init);
index da34f830f4bc17ba611a6151d4feebc4ae5faa72..2bf1110aa2ae74ee04728626334cc464a8cac060 100644 (file)
@@ -89,7 +89,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1;
 EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
 
 /* rfc5961 challenge ack rate limiting */
-int sysctl_tcp_challenge_ack_limit = 100;
+int sysctl_tcp_challenge_ack_limit = 1000;
 
 int sysctl_tcp_stdurg __read_mostly;
 int sysctl_tcp_rfc1337 __read_mostly;
@@ -3391,6 +3391,23 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32
        return flag;
 }
 
+static bool __tcp_oow_rate_limited(struct net *net, int mib_idx,
+                                  u32 *last_oow_ack_time)
+{
+       if (*last_oow_ack_time) {
+               s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time);
+
+               if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) {
+                       NET_INC_STATS_BH(net, mib_idx);
+                       return true;    /* rate-limited: don't send yet! */
+               }
+       }
+
+       *last_oow_ack_time = tcp_time_stamp;
+
+       return false;   /* not rate-limited: go ahead, send dupack now! */
+}
+
 /* Return true if we're currently rate-limiting out-of-window ACKs and
  * thus shouldn't send a dupack right now. We rate-limit dupacks in
  * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS
@@ -3404,21 +3421,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb,
        /* Data packets without SYNs are not likely part of an ACK loop. */
        if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) &&
            !tcp_hdr(skb)->syn)
-               goto not_rate_limited;
-
-       if (*last_oow_ack_time) {
-               s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time);
-
-               if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) {
-                       NET_INC_STATS_BH(net, mib_idx);
-                       return true;    /* rate-limited: don't send yet! */
-               }
-       }
-
-       *last_oow_ack_time = tcp_time_stamp;
+               return false;
 
-not_rate_limited:
-       return false;   /* not rate-limited: go ahead, send dupack now! */
+       return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time);
 }
 
 /* RFC 5961 7 [ACK Throttling] */
@@ -3428,21 +3433,26 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb)
        static u32 challenge_timestamp;
        static unsigned int challenge_count;
        struct tcp_sock *tp = tcp_sk(sk);
-       u32 now;
+       u32 count, now;
 
        /* First check our per-socket dupack rate limit. */
-       if (tcp_oow_rate_limited(sock_net(sk), skb,
-                                LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
-                                &tp->last_oow_ack_time))
+       if (__tcp_oow_rate_limited(sock_net(sk),
+                                  LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
+                                  &tp->last_oow_ack_time))
                return;
 
-       /* Then check the check host-wide RFC 5961 rate limit. */
+       /* Then check host-wide RFC 5961 rate limit. */
        now = jiffies / HZ;
        if (now != challenge_timestamp) {
+               u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1;
+
                challenge_timestamp = now;
-               challenge_count = 0;
+               WRITE_ONCE(challenge_count, half +
+                          prandom_u32_max(sysctl_tcp_challenge_ack_limit));
        }
-       if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
+       count = READ_ONCE(challenge_count);
+       if (count > 0) {
+               WRITE_ONCE(challenge_count, count - 1);
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
                tcp_send_ack(sk);
        }
index 7decaa4393605749796bcf96e4fc3e102182f1d5..364ba22ef2eabf42aa12181d469f7796ca6a13be 100644 (file)
@@ -808,8 +808,14 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
        u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 :
                                             tcp_sk(sk)->snd_nxt;
 
+       /* RFC 7323 2.3
+        * The window field (SEG.WND) of every outgoing segment, with the
+        * exception of <SYN> segments, MUST be right-shifted by
+        * Rcv.Wind.Shift bits:
+        */
        tcp_v4_send_ack(sock_net(sk), skb, seq,
-                       tcp_rsk(req)->rcv_nxt, req->rsk_rcv_wnd,
+                       tcp_rsk(req)->rcv_nxt,
+                       req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
                        tcp_time_stamp,
                        req->ts_recent,
                        0,
index 0dd207cd1f3880f193457a004ea7e2834ff15473..9eb81a4b0da20b55229d488f5e4e8a69e7f282d2 100644 (file)
@@ -239,7 +239,8 @@ void tcp_select_initial_window(int __space, __u32 mss,
                /* Set window scaling on max possible window
                 * See RFC1323 for an explanation of the limit to 14
                 */
-               space = max_t(u32, sysctl_tcp_rmem[2], sysctl_rmem_max);
+               space = max_t(u32, space, sysctl_tcp_rmem[2]);
+               space = max_t(u32, space, sysctl_rmem_max);
                space = min_t(u32, space, *window_clamp);
                while (space > 65535 && (*rcv_wscale) < 14) {
                        space >>= 1;
index 3e6a472e6b8831439d3f745b8efd43096612c39d..92ab5bc9159219d00914846460825bce9bd1743d 100644 (file)
@@ -75,7 +75,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
        if (!tcp_is_cwnd_limited(sk))
                return;
 
-       if (tp->snd_cwnd <= tp->snd_ssthresh)
+       if (tcp_in_slow_start(tp))
                tcp_slow_start(tp, acked);
 
        else if (!yeah->doing_reno_now) {
index 7473dad69c921c8974094e307fa1bef93e1da47f..defc9cad1797eb696653784fb1560652eb23d8d0 100644 (file)
@@ -1276,6 +1276,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
        int peeked, off = 0;
        int err;
        int is_udplite = IS_UDPLITE(sk);
+       bool checksum_valid = false;
        bool slow;
 
        if (flags & MSG_ERRQUEUE)
@@ -1301,11 +1302,12 @@ try_again:
         */
 
        if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
-               if (udp_lib_checksum_complete(skb))
+               checksum_valid = !udp_lib_checksum_complete(skb);
+               if (!checksum_valid)
                        goto csum_copy_err;
        }
 
-       if (skb_csum_unnecessary(skb))
+       if (checksum_valid || skb_csum_unnecessary(skb))
                err = skb_copy_datagram_msg(skb, sizeof(struct udphdr),
                                            msg, copied);
        else {
@@ -2263,6 +2265,20 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
 }
 EXPORT_SYMBOL(udp_poll);
 
+int udp_abort(struct sock *sk, int err)
+{
+       lock_sock(sk);
+
+       sk->sk_err = err;
+       sk->sk_error_report(sk);
+       udp_disconnect(sk, 0);
+
+       release_sock(sk);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(udp_abort);
+
 struct proto udp_prot = {
        .name              = "UDP",
        .owner             = THIS_MODULE,
@@ -2294,6 +2310,7 @@ struct proto udp_prot = {
        .compat_getsockopt = compat_udp_getsockopt,
 #endif
        .clear_sk          = sk_prot_clear_portaddr_nulls,
+       .diag_destroy      = udp_abort,
 };
 EXPORT_SYMBOL(udp_prot);
 
index 6116604bf6e8fd64d82b5d9496197cb7e4accef7..092aa60e8b92898a8d3612c447123a64604ac7aa 100644 (file)
@@ -20,7 +20,7 @@
 static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
                        struct netlink_callback *cb,
                        const struct inet_diag_req_v2 *req,
-                       struct nlattr *bc)
+                       struct nlattr *bc, bool net_admin)
 {
        if (!inet_diag_bc_sk(bc, sk))
                return 0;
@@ -28,7 +28,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
        return inet_sk_diag_fill(sk, NULL, skb, req,
                        sk_user_ns(NETLINK_CB(cb->skb).sk),
                        NETLINK_CB(cb->skb).portid,
-                       cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
+                       cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, net_admin);
 }
 
 static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
@@ -75,7 +75,8 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
        err = inet_sk_diag_fill(sk, NULL, rep, req,
                           sk_user_ns(NETLINK_CB(in_skb).sk),
                           NETLINK_CB(in_skb).portid,
-                          nlh->nlmsg_seq, 0, nlh);
+                          nlh->nlmsg_seq, 0, nlh,
+                          netlink_net_capable(in_skb, CAP_NET_ADMIN));
        if (err < 0) {
                WARN_ON(err == -EMSGSIZE);
                kfree_skb(rep);
@@ -98,6 +99,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb,
 {
        int num, s_num, slot, s_slot;
        struct net *net = sock_net(skb->sk);
+       bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
 
        s_slot = cb->args[0];
        num = s_num = cb->args[1];
@@ -132,7 +134,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb,
                            r->id.idiag_dport)
                                goto next;
 
-                       if (sk_diag_dump(sk, skb, cb, r, bc) < 0) {
+                       if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) {
                                spin_unlock_bh(&hslot->lock);
                                goto done;
                        }
@@ -165,12 +167,88 @@ static void udp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
        r->idiag_wqueue = sk_wmem_alloc_get(sk);
 }
 
+#ifdef CONFIG_INET_DIAG_DESTROY
+static int __udp_diag_destroy(struct sk_buff *in_skb,
+                             const struct inet_diag_req_v2 *req,
+                             struct udp_table *tbl)
+{
+       struct net *net = sock_net(in_skb->sk);
+       struct sock *sk;
+       int err;
+
+       rcu_read_lock();
+
+       if (req->sdiag_family == AF_INET)
+               sk = __udp4_lib_lookup(net,
+                               req->id.idiag_dst[0], req->id.idiag_dport,
+                               req->id.idiag_src[0], req->id.idiag_sport,
+                               req->id.idiag_if, tbl);
+#if IS_ENABLED(CONFIG_IPV6)
+       else if (req->sdiag_family == AF_INET6) {
+               if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
+                   ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
+                       sk = __udp4_lib_lookup(net,
+                                       req->id.idiag_dst[3], req->id.idiag_dport,
+                                       req->id.idiag_src[3], req->id.idiag_sport,
+                                       req->id.idiag_if, tbl);
+
+               else
+                       sk = __udp6_lib_lookup(net,
+                                       (struct in6_addr *)req->id.idiag_dst,
+                                       req->id.idiag_dport,
+                                       (struct in6_addr *)req->id.idiag_src,
+                                       req->id.idiag_sport,
+                                       req->id.idiag_if, tbl);
+       }
+#endif
+       else {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+
+       if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+               sk = NULL;
+
+       rcu_read_unlock();
+
+       if (!sk)
+               return -ENOENT;
+
+       if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) {
+               sock_put(sk);
+               return -ENOENT;
+       }
+
+       err = sock_diag_destroy(sk, ECONNABORTED);
+
+       sock_put(sk);
+
+       return err;
+}
+
+static int udp_diag_destroy(struct sk_buff *in_skb,
+                           const struct inet_diag_req_v2 *req)
+{
+       return __udp_diag_destroy(in_skb, req, &udp_table);
+}
+
+static int udplite_diag_destroy(struct sk_buff *in_skb,
+                               const struct inet_diag_req_v2 *req)
+{
+       return __udp_diag_destroy(in_skb, req, &udplite_table);
+}
+
+#endif
+
 static const struct inet_diag_handler udp_diag_handler = {
        .dump            = udp_diag_dump,
        .dump_one        = udp_diag_dump_one,
        .idiag_get_info  = udp_diag_get_info,
        .idiag_type      = IPPROTO_UDP,
        .idiag_info_size = 0,
+#ifdef CONFIG_INET_DIAG_DESTROY
+       .destroy         = udp_diag_destroy,
+#endif
 };
 
 static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
@@ -192,6 +270,9 @@ static const struct inet_diag_handler udplite_diag_handler = {
        .idiag_get_info  = udp_diag_get_info,
        .idiag_type      = IPPROTO_UDPLITE,
        .idiag_info_size = 0,
+#ifdef CONFIG_INET_DIAG_DESTROY
+       .destroy         = udplite_diag_destroy,
+#endif
 };
 
 static int __init udp_diag_init(void)
index f9386160cbee0288e294ea2cd8ba3b5be65cdbf6..0e36e56dfd225ad3757e14445f9364ecff33ff9b 100644 (file)
@@ -299,14 +299,14 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
        unsigned int off = skb_gro_offset(skb);
        int flush = 1;
 
-       if (NAPI_GRO_CB(skb)->udp_mark ||
+       if (NAPI_GRO_CB(skb)->encap_mark ||
            (skb->ip_summed != CHECKSUM_PARTIAL &&
             NAPI_GRO_CB(skb)->csum_cnt == 0 &&
             !NAPI_GRO_CB(skb)->csum_valid))
                goto out;
 
-       /* mark that this skb passed once through the udp gro layer */
-       NAPI_GRO_CB(skb)->udp_mark = 1;
+       /* mark that this skb passed once through the tunnel gro layer */
+       NAPI_GRO_CB(skb)->encap_mark = 1;
 
        rcu_read_lock();
        uo_priv = rcu_dereference(udp_offload_base);
index 3cdf59161a7efdf9d650305884a1cb572ef19385..563a91f15f68e706362a403364f5b13b9f3b3fc6 100644 (file)
@@ -1900,6 +1900,7 @@ errdad:
        spin_unlock_bh(&ifp->lock);
 
        addrconf_mod_dad_work(ifp, 0);
+       in6_ifa_put(ifp);
 }
 
 /* Join to solicited addr multicast group.
@@ -3636,6 +3637,7 @@ static void addrconf_dad_work(struct work_struct *w)
                addrconf_dad_begin(ifp);
                goto out;
        } else if (action == DAD_ABORT) {
+               in6_ifa_hold(ifp);
                addrconf_dad_stop(ifp, 1);
                goto out;
        }
index a3ec7a77a1ee9a7b9c9fe06dbc2421a928ae342c..41e5c9520c7d47d8753f3ab374511e7844192c4a 100644 (file)
@@ -98,7 +98,7 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        if (!(type & ICMPV6_INFOMSG_MASK))
                if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
-                       ping_err(skb, offset, info);
+                       ping_err(skb, offset, ntohl(info));
 }
 
 static int icmpv6_rcv(struct sk_buff *skb);
index eeca943f12dc083e195dde804c764c8732d11b9e..82e9f30760283aca2f3d9468573aea607bd5bf6b 100644 (file)
@@ -258,6 +258,19 @@ out:
        return pp;
 }
 
+static struct sk_buff **sit_gro_receive(struct sk_buff **head,
+                                       struct sk_buff *skb)
+{
+       if (NAPI_GRO_CB(skb)->encap_mark) {
+               NAPI_GRO_CB(skb)->flush = 1;
+               return NULL;
+       }
+
+       NAPI_GRO_CB(skb)->encap_mark = 1;
+
+       return ipv6_gro_receive(head, skb);
+}
+
 static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
 {
        const struct net_offload *ops;
@@ -302,7 +315,7 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
 static const struct net_offload sit_offload = {
        .callbacks = {
                .gso_segment    = ipv6_gso_segment,
-               .gro_receive    = ipv6_gro_receive,
+               .gro_receive    = sit_gro_receive,
                .gro_complete   = sit_gro_complete,
        },
 };
index 2cfaedf032528ab6cb3f45b644d32fd3e32748b0..fa65e92e9510b3369bddf874f0d1a9a0681e36a2 100644 (file)
@@ -84,7 +84,7 @@ int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        struct icmp6hdr user_icmph;
        int addr_type;
        struct in6_addr *daddr;
-       int iif = 0;
+       int oif = 0;
        struct flowi6 fl6;
        int err;
        int hlimit;
@@ -106,25 +106,30 @@ int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                if (u->sin6_family != AF_INET6) {
                        return -EAFNOSUPPORT;
                }
-               if (sk->sk_bound_dev_if &&
-                   sk->sk_bound_dev_if != u->sin6_scope_id) {
-                       return -EINVAL;
-               }
                daddr = &(u->sin6_addr);
-               iif = u->sin6_scope_id;
+               if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr)))
+                       oif = u->sin6_scope_id;
        } else {
                if (sk->sk_state != TCP_ESTABLISHED)
                        return -EDESTADDRREQ;
                daddr = &sk->sk_v6_daddr;
        }
 
-       if (!iif)
-               iif = sk->sk_bound_dev_if;
+       if (!oif)
+               oif = sk->sk_bound_dev_if;
+
+       if (!oif)
+               oif = np->sticky_pktinfo.ipi6_ifindex;
+
+       if (!oif && ipv6_addr_is_multicast(daddr))
+               oif = np->mcast_oif;
+       else if (!oif)
+               oif = np->ucast_oif;
 
        addr_type = ipv6_addr_type(daddr);
-       if (__ipv6_addr_needs_scope_id(addr_type) && !iif)
-               return -EINVAL;
-       if (addr_type & IPV6_ADDR_MAPPED)
+       if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) ||
+           (addr_type & IPV6_ADDR_MAPPED) ||
+           (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if))
                return -EINVAL;
 
        /* TODO: use ip6_datagram_send_ctl to get options from cmsg */
@@ -134,30 +139,23 @@ int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        fl6.flowi6_proto = IPPROTO_ICMPV6;
        fl6.saddr = np->saddr;
        fl6.daddr = *daddr;
+       fl6.flowi6_oif = oif;
        fl6.flowi6_mark = sk->sk_mark;
        fl6.flowi6_uid = sock_i_uid(sk);
        fl6.fl6_icmp_type = user_icmph.icmp6_type;
        fl6.fl6_icmp_code = user_icmph.icmp6_code;
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-       if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
-               fl6.flowi6_oif = np->mcast_oif;
-       else if (!fl6.flowi6_oif)
-               fl6.flowi6_oif = np->ucast_oif;
-
        dst = ip6_sk_dst_lookup_flow(sk, &fl6,  daddr);
        if (IS_ERR(dst))
                return PTR_ERR(dst);
        rt = (struct rt6_info *) dst;
 
        np = inet6_sk(sk);
-       if (!np)
-               return -EBADF;
-
-       if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
-               fl6.flowi6_oif = np->mcast_oif;
-       else if (!fl6.flowi6_oif)
-               fl6.flowi6_oif = np->ucast_oif;
+       if (!np) {
+               err = -EBADF;
+               goto dst_err_out;
+       }
 
        pfh.icmph.type = user_icmph.icmp6_type;
        pfh.icmph.code = user_icmph.icmp6_code;
@@ -187,6 +185,9 @@ int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        }
        release_sock(sk);
 
+dst_err_out:
+       dst_release(dst);
+
        if (err)
                return err;
 
index ba3d2f3d66d2b6c1f4668e49b71cc42d67121654..3da2b16356eb64a9ff33fdc95809a768a81917f6 100644 (file)
@@ -681,14 +681,15 @@ static int ipip6_rcv(struct sk_buff *skb)
                skb->mac_header = skb->network_header;
                skb_reset_network_header(skb);
                IPCB(skb)->flags = 0;
-               skb->protocol = htons(ETH_P_IPV6);
+               skb->dev = tunnel->dev;
 
                if (packet_is_spoofed(skb, iph, tunnel)) {
                        tunnel->dev->stats.rx_errors++;
                        goto out;
                }
 
-               __skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
+               if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6)))
+                       goto out;
 
                err = IP_ECN_decapsulate(iph, skb);
                if (unlikely(err)) {
index 3c6acb67d8e57cc3f9e7bcb4dfa1592e09db0c88..f58632cc45dc1e2367f2f1f7131a7e215f0d9dda 100644 (file)
@@ -933,9 +933,15 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
        /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
         * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
         */
+       /* RFC 7323 2.3
+        * The window field (SEG.WND) of every outgoing segment, with the
+        * exception of <SYN> segments, MUST be right-shifted by
+        * Rcv.Wind.Shift bits:
+        */
        tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ?
                        tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
-                       tcp_rsk(req)->rcv_nxt, req->rsk_rcv_wnd,
+                       tcp_rsk(req)->rcv_nxt,
+                       req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
                        tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
                        tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
                        0, 0);
index ed7f4a81a932bbb875308849e1495f350b9d6dbb..2415e55aaf8f590825f95cb236a3c1a496f4dbc2 100644 (file)
@@ -402,6 +402,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
        int peeked, off = 0;
        int err;
        int is_udplite = IS_UDPLITE(sk);
+       bool checksum_valid = false;
        int is_udp4;
        bool slow;
 
@@ -433,11 +434,12 @@ try_again:
         */
 
        if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
-               if (udp_lib_checksum_complete(skb))
+               checksum_valid = !udp_lib_checksum_complete(skb);
+               if (!checksum_valid)
                        goto csum_copy_err;
        }
 
-       if (skb_csum_unnecessary(skb))
+       if (checksum_valid || skb_csum_unnecessary(skb))
                err = skb_copy_datagram_msg(skb, sizeof(struct udphdr),
                                            msg, copied);
        else {
@@ -1550,6 +1552,7 @@ struct proto udpv6_prot = {
        .compat_getsockopt = compat_udpv6_getsockopt,
 #endif
        .clear_sk          = udp_v6_clear_sk,
+       .diag_destroy      = udp_abort,
 };
 
 static struct inet_protosw udpv6_protosw = {
index 923abd6b3064074f39f84644b2d3d1f068403f51..8d2f7c9b491da5b7e7b13f90f2aa9c5d88f84faf 100644 (file)
@@ -1024,8 +1024,11 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
        }
 
        /* Check if we have opened a local TSAP */
-       if (!self->tsap)
-               irda_open_tsap(self, LSAP_ANY, addr->sir_name);
+       if (!self->tsap) {
+               err = irda_open_tsap(self, LSAP_ANY, addr->sir_name);
+               if (err)
+                       goto out;
+       }
 
        /* Move to connecting socket, start sending Connect Requests */
        sock->state = SS_CONNECTING;
index 4a7ae32afa09b90fab1d57bcb807ca2b8a1200c6..1138eaf5c6829ac08431a91c31fb3339dfe6213d 100644 (file)
@@ -185,8 +185,12 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
 
        self->magic = IAS_MAGIC;
        self->mode = mode;
-       if (mode == IAS_CLIENT)
-               iriap_register_lsap(self, slsap_sel, mode);
+       if (mode == IAS_CLIENT) {
+               if (iriap_register_lsap(self, slsap_sel, mode)) {
+                       kfree(self);
+                       return NULL;
+               }
+       }
 
        self->confirm = callback;
        self->priv = priv;
index c12f348138acf7075297e5854b6e17391646d52b..19322c047386f2969eb0ff6847eef1bd69908dae 100644 (file)
@@ -865,7 +865,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 
        /* free all potentially still buffered bcast frames */
        local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
-       skb_queue_purge(&sdata->u.ap.ps.bc_buf);
+       ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf);
 
        mutex_lock(&local->mtx);
        ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
index bdc224d5053ae3478a01565754ec6942c2d197a6..e1225b395415efb457269d8a11740be273efbfd3 100644 (file)
@@ -365,7 +365,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
                skb = skb_dequeue(&ps->bc_buf);
                if (skb) {
                        purged++;
-                       dev_kfree_skb(skb);
+                       ieee80211_free_txskb(&local->hw, skb);
                }
                total += skb_queue_len(&ps->bc_buf);
        }
@@ -448,7 +448,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
                ps_dbg(tx->sdata,
                       "BC TX buffer full - dropping the oldest frame\n");
-               dev_kfree_skb(skb_dequeue(&ps->bc_buf));
+               ieee80211_free_txskb(&tx->local->hw, skb_dequeue(&ps->bc_buf));
        } else
                tx->local->total_ps_buffered++;
 
@@ -3781,7 +3781,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
                        sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
                if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
                        break;
-               dev_kfree_skb_any(skb);
+               ieee80211_free_txskb(hw, skb);
        }
 
        info = IEEE80211_SKB_CB(skb);
index 803001a45aa16e6b5a372ab385dba8e9c09bd2f0..1b07578bedf336c53e3b6072c8c3324f7f18081b 100644 (file)
@@ -1545,7 +1545,8 @@ error:
 /*
  *      Set up receiving multicast socket over UDP
  */
-static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id)
+static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id,
+                                       int ifindex)
 {
        /* multicast addr */
        union ipvs_sockaddr mcast_addr;
@@ -1566,6 +1567,7 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id)
                set_sock_size(sock->sk, 0, result);
 
        get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id);
+       sock->sk->sk_bound_dev_if = ifindex;
        result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen);
        if (result < 0) {
                pr_err("Error binding to the multicast addr\n");
@@ -1868,7 +1870,7 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
                if (state == IP_VS_STATE_MASTER)
                        sock = make_send_sock(ipvs, id);
                else
-                       sock = make_receive_sock(ipvs, id);
+                       sock = make_receive_sock(ipvs, id, dev->ifindex);
                if (IS_ERR(sock)) {
                        result = PTR_ERR(sock);
                        goto outtinfo;
index 77afe913d03db73c65631fba8c42732cb3f33f32..9adedba78eeaccafce9df7c9f851b7f8c19f7fe8 100644 (file)
@@ -326,10 +326,12 @@ replay:
                nlh = nlmsg_hdr(skb);
                err = 0;
 
-               if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) ||
-                   skb->len < nlh->nlmsg_len) {
-                       err = -EINVAL;
-                       goto ack;
+               if (nlh->nlmsg_len < NLMSG_HDRLEN ||
+                   skb->len < nlh->nlmsg_len ||
+                   nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
+                       nfnl_err_reset(&err_list);
+                       status |= NFNL_BATCH_FAILURE;
+                       goto done;
                }
 
                /* Only requests are handled by the kernel */
index 25391fb255162204b197895647f9c2f3c6d96507..2fc6ca9d12866432f09d01d8807698b77723e168 100644 (file)
@@ -897,6 +897,12 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
        struct xt_table_info *info = NULL;
        size_t sz = sizeof(*info) + size;
 
+       if (sz < sizeof(*info))
+               return NULL;
+
+       if (sz < sizeof(*info))
+               return NULL;
+
        /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
        if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
                return NULL;
index 28cddc85b7005aa6b6afa7b2c22f8f88a5b7fa46..bfa2b6d5b5cfa52dbe50279efc6a0944a314ec05 100644 (file)
@@ -824,7 +824,11 @@ socket_setattr_return:
  */
 void netlbl_sock_delattr(struct sock *sk)
 {
-       cipso_v4_sock_delattr(sk);
+       switch (sk->sk_family) {
+       case AF_INET:
+               cipso_v4_sock_delattr(sk);
+               break;
+       }
 }
 
 /**
@@ -987,7 +991,11 @@ req_setattr_return:
 */
 void netlbl_req_delattr(struct request_sock *req)
 {
-       cipso_v4_req_delattr(req);
+       switch (req->rsk_ops->family) {
+       case AF_INET:
+               cipso_v4_req_delattr(req);
+               break;
+       }
 }
 
 /**
index a00462b0d01de9ee2793d4fb273bf568b2eefc29..0514af3ab378ff1fd86bc6bdb4755334de2b8f6e 100644 (file)
@@ -545,5 +545,7 @@ void rds_inc_info_copy(struct rds_incoming *inc,
                minfo.fport = inc->i_hdr.h_dport;
        }
 
+       minfo.flags = 0;
+
        rds_info_copy(iter, &minfo, sizeof(minfo));
 }
index 9d6ddbacd8750e22b05986b37e40a8fe1bb95865..18e50a8fc05f2e31b09778ffc4a72a362aa4ed1c 100644 (file)
@@ -421,7 +421,7 @@ static int rds_tcp_init(void)
 
        ret = rds_tcp_recv_init();
        if (ret)
-               goto out_slab;
+               goto out_pernet;
 
        ret = rds_trans_register(&rds_tcp_transport);
        if (ret)
@@ -433,8 +433,9 @@ static int rds_tcp_init(void)
 
 out_recv:
        rds_tcp_recv_exit();
-out_slab:
+out_pernet:
        unregister_pernet_subsys(&rds_tcp_net_ops);
+out_slab:
        kmem_cache_destroy(rds_tcp_conn_slab);
 out:
        return ret;
index 799e65b944b9019cf7eee177f90f6d67a0fb66dd..06095cc8815eb4936ef3dd9ec4d22ccdba6d161d 100644 (file)
@@ -340,12 +340,14 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
 }
 
 static struct gss_upcall_msg *
-__gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid)
+__gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *auth)
 {
        struct gss_upcall_msg *pos;
        list_for_each_entry(pos, &pipe->in_downcall, list) {
                if (!uid_eq(pos->uid, uid))
                        continue;
+               if (auth && pos->auth->service != auth->service)
+                       continue;
                atomic_inc(&pos->count);
                dprintk("RPC:       %s found msg %p\n", __func__, pos);
                return pos;
@@ -365,7 +367,7 @@ gss_add_msg(struct gss_upcall_msg *gss_msg)
        struct gss_upcall_msg *old;
 
        spin_lock(&pipe->lock);
-       old = __gss_find_upcall(pipe, gss_msg->uid);
+       old = __gss_find_upcall(pipe, gss_msg->uid, gss_msg->auth);
        if (old == NULL) {
                atomic_inc(&gss_msg->count);
                list_add(&gss_msg->list, &pipe->in_downcall);
@@ -714,7 +716,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        err = -ENOENT;
        /* Find a matching upcall */
        spin_lock(&pipe->lock);
-       gss_msg = __gss_find_upcall(pipe, uid);
+       gss_msg = __gss_find_upcall(pipe, uid, NULL);
        if (gss_msg == NULL) {
                spin_unlock(&pipe->lock);
                goto err_put_ctx;
index cc9852897395c6f6db42653c773788446a9c5d3e..c5b0cb4f4056c4da0a0adc556cf46bebb48d2e7a 100644 (file)
@@ -1188,11 +1188,17 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
 
                /* Encode reply */
-               if (test_bit(RQ_DROPME, &rqstp->rq_flags)) {
+               if (*statp == rpc_drop_reply ||
+                   test_bit(RQ_DROPME, &rqstp->rq_flags)) {
                        if (procp->pc_release)
                                procp->pc_release(rqstp, NULL, rqstp->rq_resp);
                        goto dropit;
                }
+               if (*statp == rpc_autherr_badcred) {
+                       if (procp->pc_release)
+                               procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+                       goto err_bad_auth;
+               }
                if (*statp == rpc_success &&
                    (xdr = procp->pc_encode) &&
                    !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
index 027c9ef8a263fa63042afd1156dc8b1f59c2bc64..27b6f55fa43a87fe98fddb946aeac015ecd1f6ab 100644 (file)
@@ -474,7 +474,16 @@ static int xs_nospace(struct rpc_task *task)
        spin_unlock_bh(&xprt->transport_lock);
 
        /* Race breaker in case memory is freed before above code is called */
-       sk->sk_write_space(sk);
+       if (ret == -EAGAIN) {
+               struct socket_wq *wq;
+
+               rcu_read_lock();
+               wq = rcu_dereference(sk->sk_wq);
+               set_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags);
+               rcu_read_unlock();
+
+               sk->sk_write_space(sk);
+       }
        return ret;
 }
 
@@ -2286,6 +2295,10 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                /* SYN_SENT! */
                if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
                        xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
+               break;
+       case -EADDRNOTAVAIL:
+               /* Source port number is unavailable. Try a new one! */
+               transport->srcport = 0;
        }
 out:
        return ret;
index ed98c1fc3de1428560ea370413084102af9dff7f..46a71c701e7c44f5aa5fcc69e8571382434e385b 100644 (file)
@@ -46,7 +46,7 @@ static int net_ctl_permissions(struct ctl_table_header *head,
        kgid_t root_gid = make_kgid(net->user_ns, 0);
 
        /* Allow network administrator to have same access as root. */
-       if (ns_capable(net->user_ns, CAP_NET_ADMIN) ||
+       if (ns_capable_noaudit(net->user_ns, CAP_NET_ADMIN) ||
            uid_eq(root_uid, current_euid())) {
                int mode = (table->mode >> 6) & 7;
                return (mode << 6) | (mode << 3) | mode;
index 91aea071ab27fee550e3c88ecc4097adac399d83..72268eac4ec7237787f53f2dadf886325f8e5cf6 100644 (file)
@@ -1262,6 +1262,8 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
                /* fall thru' */
 
        case ACTIVATE_MSG:
+               skb_linearize(skb);
+               hdr = buf_msg(skb);
 
                /* Complete own link name with peer's interface name */
                if_name =  strrchr(l->name, ':') + 1;
index c07612bab95c0957b2e34434aa73b6ef02708fff..f51c8bdbea1c010a6f6405932c2d3e1144f75219 100644 (file)
@@ -397,6 +397,7 @@ void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq)
 
        spin_lock_bh(&tn->nametbl_lock);
        for (skb = skb_dequeue(inputq); skb; skb = skb_dequeue(inputq)) {
+               skb_linearize(skb);
                msg = buf_msg(skb);
                mtype = msg_type(msg);
                item = (struct distr_item *)msg_data(msg);
index 2ed732bfe94b4dc8d1eeae45492b5932484153f9..a0c90572d0e57900e969f94aba4767305a16ec96 100644 (file)
@@ -574,7 +574,8 @@ static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg,
 
        link_info.dest = nla_get_flag(link[TIPC_NLA_LINK_DEST]);
        link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP]));
-       strcpy(link_info.str, nla_data(link[TIPC_NLA_LINK_NAME]));
+       nla_strlcpy(link_info.str, link[TIPC_NLA_LINK_NAME],
+                   TIPC_MAX_LINK_NAME);
 
        return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO,
                            &link_info, sizeof(link_info));
index 9b713e0ce00dbb79487e979337f449248cc78a51..b26b7a1277736c1f8c780f25a9672fd98fe3383c 100644 (file)
@@ -2111,7 +2111,8 @@ restart:
                                              TIPC_CONN_MSG, SHORT_H_SIZE,
                                              0, dnode, onode, dport, oport,
                                              TIPC_CONN_SHUTDOWN);
-                       tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
+                       if (skb)
+                               tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
                }
                tsk->connected = 0;
                sock->state = SS_DISCONNECTING;
index 69ee2eeef968851192035cb166410f1f37e7722f..f9ff73a8d8154ff0a52f8c33a64077f5d8c57ae5 100644 (file)
@@ -296,7 +296,8 @@ static void tipc_subscrb_rcv_cb(struct net *net, int conid,
        if (tipc_subscrp_create(net, (struct tipc_subscr *)buf, subscrb, &sub))
                return tipc_conn_terminate(tn->topsrv, subscrb->conid);
 
-       tipc_nametbl_subscribe(sub);
+       if (sub)
+               tipc_nametbl_subscribe(sub);
 }
 
 /* Handle one request to establish a new subscriber */
index 70c03271b798f429d8d6faa5142fb2654753d342..6af78c6276b4b185be00d62370932bb1d816bfd4 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/tipc_netlink.h>
 #include "core.h"
 #include "bearer.h"
-#include "msg.h"
 
 /* IANA assigned UDP port */
 #define UDP_PORT_DEFAULT       6118
@@ -224,10 +223,6 @@ static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct udp_bearer *ub;
        struct tipc_bearer *b;
-       int usr = msg_user(buf_msg(skb));
-
-       if ((usr == LINK_PROTOCOL) || (usr == NAME_DISTRIBUTOR))
-               skb_linearize(skb);
 
        ub = rcu_dereference_sk_user_data(sk);
        if (!ub) {
index 6579fd6e7459bc3e1b40f2008f7bf4f32e02c0ca..824cc1e160bc1f79e54b1fcdb03a88b740abac27 100644 (file)
@@ -661,11 +661,11 @@ static int unix_set_peek_off(struct sock *sk, int val)
 {
        struct unix_sock *u = unix_sk(sk);
 
-       if (mutex_lock_interruptible(&u->readlock))
+       if (mutex_lock_interruptible(&u->iolock))
                return -EINTR;
 
        sk->sk_peek_off = val;
-       mutex_unlock(&u->readlock);
+       mutex_unlock(&u->iolock);
 
        return 0;
 }
@@ -778,7 +778,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
        spin_lock_init(&u->lock);
        atomic_long_set(&u->inflight, 0);
        INIT_LIST_HEAD(&u->link);
-       mutex_init(&u->readlock); /* single task reading lock */
+       mutex_init(&u->iolock); /* single task reading lock */
+       mutex_init(&u->bindlock); /* single task binding lock */
        init_waitqueue_head(&u->peer_wait);
        init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
        unix_insert_socket(unix_sockets_unbound(sk), sk);
@@ -847,7 +848,7 @@ static int unix_autobind(struct socket *sock)
        int err;
        unsigned int retries = 0;
 
-       err = mutex_lock_interruptible(&u->readlock);
+       err = mutex_lock_interruptible(&u->bindlock);
        if (err)
                return err;
 
@@ -894,7 +895,7 @@ retry:
        spin_unlock(&unix_table_lock);
        err = 0;
 
-out:   mutex_unlock(&u->readlock);
+out:   mutex_unlock(&u->bindlock);
        return err;
 }
 
@@ -953,20 +954,32 @@ fail:
        return NULL;
 }
 
-static int unix_mknod(struct dentry *dentry, struct path *path, umode_t mode,
-                     struct path *res)
+static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
 {
-       int err;
+       struct dentry *dentry;
+       struct path path;
+       int err = 0;
+       /*
+        * Get the parent directory, calculate the hash for last
+        * component.
+        */
+       dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
+       err = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
+               return err;
 
-       err = security_path_mknod(path, dentry, mode, 0);
+       /*
+        * All right, let's create it.
+        */
+       err = security_path_mknod(&path, dentry, mode, 0);
        if (!err) {
-               err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0);
+               err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);
                if (!err) {
-                       res->mnt = mntget(path->mnt);
+                       res->mnt = mntget(path.mnt);
                        res->dentry = dget(dentry);
                }
        }
-
+       done_path_create(&path, dentry);
        return err;
 }
 
@@ -977,12 +990,10 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        struct unix_sock *u = unix_sk(sk);
        struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
        char *sun_path = sunaddr->sun_path;
-       int err, name_err;
+       int err;
        unsigned int hash;
        struct unix_address *addr;
        struct hlist_head *list;
-       struct path path;
-       struct dentry *dentry;
 
        err = -EINVAL;
        if (sunaddr->sun_family != AF_UNIX)
@@ -998,34 +1009,14 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
        addr_len = err;
 
-       name_err = 0;
-       dentry = NULL;
-       if (sun_path[0]) {
-               /* Get the parent directory, calculate the hash for last
-                * component.
-                */
-               dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
-
-               if (IS_ERR(dentry)) {
-                       /* delay report until after 'already bound' check */
-                       name_err = PTR_ERR(dentry);
-                       dentry = NULL;
-               }
-       }
-
-       err = mutex_lock_interruptible(&u->readlock);
+       err = mutex_lock_interruptible(&u->bindlock);
        if (err)
-               goto out_path;
+               goto out;
 
        err = -EINVAL;
        if (u->addr)
                goto out_up;
 
-       if (name_err) {
-               err = name_err == -EEXIST ? -EADDRINUSE : name_err;
-               goto out_up;
-       }
-
        err = -ENOMEM;
        addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
        if (!addr)
@@ -1036,11 +1027,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        addr->hash = hash ^ sk->sk_type;
        atomic_set(&addr->refcnt, 1);
 
-       if (dentry) {
-               struct path u_path;
+       if (sun_path[0]) {
+               struct path path;
                umode_t mode = S_IFSOCK |
                       (SOCK_INODE(sock)->i_mode & ~current_umask());
-               err = unix_mknod(dentry, &path, mode, &u_path);
+               err = unix_mknod(sun_path, mode, &path);
                if (err) {
                        if (err == -EEXIST)
                                err = -EADDRINUSE;
@@ -1048,9 +1039,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                        goto out_up;
                }
                addr->hash = UNIX_HASH_SIZE;
-               hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
+               hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
                spin_lock(&unix_table_lock);
-               u->path = u_path;
+               u->path = path;
                list = &unix_socket_table[hash];
        } else {
                spin_lock(&unix_table_lock);
@@ -1072,11 +1063,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 out_unlock:
        spin_unlock(&unix_table_lock);
 out_up:
-       mutex_unlock(&u->readlock);
-out_path:
-       if (dentry)
-               done_path_create(&path, dentry);
-
+       mutex_unlock(&u->bindlock);
 out:
        return err;
 }
@@ -1971,17 +1958,17 @@ static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page,
        if (false) {
 alloc_skb:
                unix_state_unlock(other);
-               mutex_unlock(&unix_sk(other)->readlock);
+               mutex_unlock(&unix_sk(other)->iolock);
                newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT,
                                              &err, 0);
                if (!newskb)
                        goto err;
        }
 
-       /* we must acquire readlock as we modify already present
+       /* we must acquire iolock as we modify already present
         * skbs in the sk_receive_queue and mess with skb->len
         */
-       err = mutex_lock_interruptible(&unix_sk(other)->readlock);
+       err = mutex_lock_interruptible(&unix_sk(other)->iolock);
        if (err) {
                err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS;
                goto err;
@@ -2048,7 +2035,7 @@ alloc_skb:
        }
 
        unix_state_unlock(other);
-       mutex_unlock(&unix_sk(other)->readlock);
+       mutex_unlock(&unix_sk(other)->iolock);
 
        other->sk_data_ready(other);
        scm_destroy(&scm);
@@ -2057,7 +2044,7 @@ alloc_skb:
 err_state_unlock:
        unix_state_unlock(other);
 err_unlock:
-       mutex_unlock(&unix_sk(other)->readlock);
+       mutex_unlock(&unix_sk(other)->iolock);
 err:
        kfree_skb(newskb);
        if (send_sigpipe && !(flags & MSG_NOSIGNAL))
@@ -2122,7 +2109,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
        if (flags&MSG_OOB)
                goto out;
 
-       err = mutex_lock_interruptible(&u->readlock);
+       err = mutex_lock_interruptible(&u->iolock);
        if (unlikely(err)) {
                /* recvmsg() in non blocking mode is supposed to return -EAGAIN
                 * sk_rcvtimeo is not honored by mutex_lock_interruptible()
@@ -2198,7 +2185,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
 out_free:
        skb_free_datagram(sk, skb);
 out_unlock:
-       mutex_unlock(&u->readlock);
+       mutex_unlock(&u->iolock);
 out:
        return err;
 }
@@ -2293,7 +2280,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
        /* Lock the socket to prevent queue disordering
         * while sleeps in memcpy_tomsg
         */
-       mutex_lock(&u->readlock);
+       mutex_lock(&u->iolock);
 
        if (flags & MSG_PEEK)
                skip = sk_peek_offset(sk, flags);
@@ -2334,7 +2321,7 @@ again:
                                break;
                        }
 
-                       mutex_unlock(&u->readlock);
+                       mutex_unlock(&u->iolock);
 
                        timeo = unix_stream_data_wait(sk, timeo, last,
                                                      last_len);
@@ -2345,7 +2332,7 @@ again:
                                goto out;
                        }
 
-                       mutex_lock(&u->readlock);
+                       mutex_lock(&u->iolock);
                        continue;
 unlock:
                        unix_state_unlock(sk);
@@ -2448,7 +2435,7 @@ unlock:
                }
        } while (size);
 
-       mutex_unlock(&u->readlock);
+       mutex_unlock(&u->iolock);
        if (state->msg)
                scm_recv(sock, state->msg, &scm, flags);
        else
@@ -2489,9 +2476,9 @@ static ssize_t skb_unix_socket_splice(struct sock *sk,
        int ret;
        struct unix_sock *u = unix_sk(sk);
 
-       mutex_unlock(&u->readlock);
+       mutex_unlock(&u->iolock);
        ret = splice_to_pipe(pipe, spd);
-       mutex_lock(&u->readlock);
+       mutex_lock(&u->iolock);
 
        return ret;
 }
index 5d89f13a98dbafaa8b8921cd6df2ed7e570ccd66..bf65f31bd55ec61dce5d80f088dfd3c5a3d6cd1d 100644 (file)
@@ -6628,7 +6628,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 
                params.n_counter_offsets_presp = len / sizeof(u16);
                if (rdev->wiphy.max_num_csa_counters &&
-                   (params.n_counter_offsets_beacon >
+                   (params.n_counter_offsets_presp >
                     rdev->wiphy.max_num_csa_counters))
                        return -EINVAL;
 
index c753211cb83f8b0db3907af66e5bc708456000a6..b50ee5d622e14d4fb486ce0c533757e958702f54 100644 (file)
@@ -955,29 +955,8 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
                        return private(dev, iwr, cmd, info, handler);
        }
        /* Old driver API : call driver ioctl handler */
-       if (dev->netdev_ops->ndo_do_ioctl) {
-#ifdef CONFIG_COMPAT
-               if (info->flags & IW_REQUEST_FLAG_COMPAT) {
-                       int ret = 0;
-                       struct iwreq iwr_lcl;
-                       struct compat_iw_point *iwp_compat = (void *) &iwr->u.data;
-
-                       memcpy(&iwr_lcl, iwr, sizeof(struct iwreq));
-                       iwr_lcl.u.data.pointer = compat_ptr(iwp_compat->pointer);
-                       iwr_lcl.u.data.length = iwp_compat->length;
-                       iwr_lcl.u.data.flags = iwp_compat->flags;
-
-                       ret = dev->netdev_ops->ndo_do_ioctl(dev, (void *) &iwr_lcl, cmd);
-
-                       iwp_compat->pointer = ptr_to_compat(iwr_lcl.u.data.pointer);
-                       iwp_compat->length = iwr_lcl.u.data.length;
-                       iwp_compat->flags = iwr_lcl.u.data.flags;
-
-                       return ret;
-               } else
-#endif
-                       return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd);
-       }
+       if (dev->netdev_ops->ndo_do_ioctl)
+               return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd);
        return -EOPNOTSUPP;
 }
 
index 727eb21c9c5624f2998f321d59db1017339c69a3..83795435bd991b117324424d7a1a2cb2985786ad 100644 (file)
@@ -42,6 +42,11 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
                        " ex1 = 0x%lx\n",
                p->addr, regs->pc, regs->ex1);
 #endif
+#ifdef CONFIG_ARM64
+       pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx,"
+                       " pstate = 0x%lx\n",
+               p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
+#endif
 
        /* A dump_stack() here will give a stack backtrace */
        return 0;
@@ -67,6 +72,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs,
        printk(KERN_INFO "post_handler: p->addr = 0x%p, ex1 = 0x%lx\n",
                p->addr, regs->ex1);
 #endif
+#ifdef CONFIG_ARM64
+       pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n",
+               p->symbol_name, p->addr, (long)regs->pstate);
+#endif
 }
 
 /*
index e167592793a70e8a1bac057d58ca7456e064db8e..42396a74405df03002001d8f972599fa827bb3bf 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
+/*
+ * glibc synced up and added the metag number but didn't add the relocations.
+ * Work around this in a crude manner for now.
+ */
 #ifndef EM_METAG
-/* Remove this when these make it to the standard system elf.h. */
 #define EM_METAG      174
+#endif
+#ifndef R_METAG_ADDR32
 #define R_METAG_ADDR32                   2
+#endif
+#ifndef R_METAG_NONE
 #define R_METAG_NONE                     3
 #endif
 
index 30a2603e8c853a2b619eb6e1fffd60cd79d647ef..3aa60791f84d687eeab11e5b437e9e37c039d32c 100644 (file)
@@ -127,6 +127,46 @@ config LSM_MMAP_MIN_ADDR
          this low address space will need the permission specific to the
          systems running LSM.
 
+config HAVE_HARDENED_USERCOPY_ALLOCATOR
+       bool
+       help
+         The heap allocator implements __check_heap_object() for
+         validating memory ranges against heap object sizes in
+         support of CONFIG_HARDENED_USERCOPY.
+
+config HAVE_ARCH_HARDENED_USERCOPY
+       bool
+       help
+         The architecture supports CONFIG_HARDENED_USERCOPY by
+         calling check_object_size() just before performing the
+         userspace copies in the low level implementation of
+         copy_to_user() and copy_from_user().
+
+config HARDENED_USERCOPY
+       bool "Harden memory copies between kernel and userspace"
+       depends on HAVE_ARCH_HARDENED_USERCOPY
+       depends on HAVE_HARDENED_USERCOPY_ALLOCATOR
+       select BUG
+       help
+         This option checks for obviously wrong memory regions when
+         copying memory to/from the kernel (via copy_to_user() and
+         copy_from_user() functions) by rejecting memory ranges that
+         are larger than the specified heap object, span multiple
+         separately allocates pages, are not on the process stack,
+         or are part of the kernel text. This kills entire classes
+         of heap overflow exploits and similar kernel memory exposures.
+
+config HARDENED_USERCOPY_PAGESPAN
+       bool "Refuse to copy allocations that span multiple pages"
+       depends on HARDENED_USERCOPY
+       depends on !COMPILE_TEST
+       help
+         When a multi-page allocation is done without __GFP_COMP,
+         hardened usercopy will reject attempts to copy it. There are,
+         however, several cases of this in the kernel that have not all
+         been removed. This config is intended to be used only while
+         trying to find such users.
+
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
index ad4fa49ad1db23a70dfa16751a9c7f8ec006e854..9068369f8a1bc18b49e346bea2959473a078dbf4 100644 (file)
@@ -331,6 +331,7 @@ static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
                        seq_printf(seq, "%.2x", profile->hash[i]);
                seq_puts(seq, "\n");
        }
+       aa_put_profile(profile);
 
        return 0;
 }
index 1d950fbb2aecbb21c62b28233dba7a707a116a6b..2d1fe34781fa70f79f139969e01da15d3fb10a29 100644 (file)
@@ -202,7 +202,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
        } hash;
 
        if (xattr_value)
-               *xattr_len = ima_read_xattr(file->f_path.dentry, xattr_value);
+               *xattr_len = ima_read_xattr(file_dentry(file), xattr_value);
 
        if (!(iint->flags & IMA_COLLECTED)) {
                u64 i_version = file_inode(file)->i_version;
index 1873b5536f804c28cbb9452b5b1a8cc2f180828a..ed5a9c110b3a2238025a3be9d4a58787ceaea230 100644 (file)
@@ -189,7 +189,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
 {
        static const char op[] = "appraise_data";
        char *cause = "unknown";
-       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *dentry = file_dentry(file);
        struct inode *inode = d_backing_inode(dentry);
        enum integrity_status status = INTEGRITY_UNKNOWN;
        int rc = xattr_len, hash_start = 0;
@@ -289,7 +289,7 @@ out:
  */
 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
 {
-       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *dentry = file_dentry(file);
        int rc = 0;
 
        /* do not collect and update hash for digital signatures */
index cccbf3068cdca800eb53e49caf1d29de9d93b035..45d927ab807d82425b470d1e597b786fa91b7259 100644 (file)
@@ -220,7 +220,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
         */
        BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
 
-       audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
+       audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current));
        audit_log_untrustedstring(ab, memcpy(comm, current->comm, sizeof(comm)));
 
        switch (a->type) {
@@ -294,7 +294,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
        case LSM_AUDIT_DATA_TASK: {
                struct task_struct *tsk = a->u.tsk;
                if (tsk) {
-                       pid_t pid = task_pid_nr(tsk);
+                       pid_t pid = task_tgid_nr(tsk);
                        if (pid) {
                                char comm[sizeof(tsk->comm)];
                                audit_log_format(ab, " opid=%d ocomm=", pid);
index 795437b1008200cd534f9a46ad0272f3dbc20ca4..b450a27588c8e679cca28fe4384850b031c93168 100644 (file)
@@ -1633,11 +1633,13 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
                return -EBUSY;
        }
        list_add_tail(&rmidi->list, &snd_rawmidi_devices);
+       mutex_unlock(&register_mutex);
        err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
                                  rmidi->card, rmidi->device,
                                  &snd_rawmidi_f_ops, rmidi, &rmidi->dev);
        if (err < 0) {
                rmidi_err(rmidi, "unable to register\n");
+               mutex_lock(&register_mutex);
                list_del(&rmidi->list);
                mutex_unlock(&register_mutex);
                return err;
@@ -1645,6 +1647,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
        if (rmidi->ops && rmidi->ops->dev_register &&
            (err = rmidi->ops->dev_register(rmidi)) < 0) {
                snd_unregister_device(&rmidi->dev);
+               mutex_lock(&register_mutex);
                list_del(&rmidi->list);
                mutex_unlock(&register_mutex);
                return err;
@@ -1677,7 +1680,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
                }
        }
 #endif /* CONFIG_SND_OSSEMUL */
-       mutex_unlock(&register_mutex);
        sprintf(name, "midi%d", rmidi->device);
        entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
        if (entry) {
index 637d034bb084ffcd8865e934de91dca42a3d446d..ae4ea2e2e7fee752bc478846cc32e445d8e5f642 100644 (file)
@@ -296,8 +296,21 @@ int snd_timer_open(struct snd_timer_instance **ti,
                get_device(&timer->card->card_dev);
        timeri->slave_class = tid->dev_sclass;
        timeri->slave_id = slave_id;
-       if (list_empty(&timer->open_list_head) && timer->hw.open)
-               timer->hw.open(timer);
+
+       if (list_empty(&timer->open_list_head) && timer->hw.open) {
+               int err = timer->hw.open(timer);
+               if (err) {
+                       kfree(timeri->owner);
+                       kfree(timeri);
+
+                       if (timer->card)
+                               put_device(&timer->card->card_dev);
+                       module_put(timer->module);
+                       mutex_unlock(&register_mutex);
+                       return err;
+               }
+       }
+
        list_add_tail(&timeri->open_list, &timer->open_list_head);
        snd_timer_check_master(timeri);
        mutex_unlock(&register_mutex);
@@ -837,6 +850,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
        timer->tmr_subdevice = tid->subdevice;
        if (id)
                strlcpy(timer->id, id, sizeof(timer->id));
+       timer->sticks = 1;
        INIT_LIST_HEAD(&timer->device_list);
        INIT_LIST_HEAD(&timer->open_list_head);
        INIT_LIST_HEAD(&timer->active_list_head);
@@ -1967,6 +1981,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
                tu->qused--;
                spin_unlock_irq(&tu->qlock);
 
+               mutex_lock(&tu->ioctl_lock);
                if (tu->tread) {
                        if (copy_to_user(buffer, &tu->tqueue[qhead],
                                         sizeof(struct snd_timer_tread)))
@@ -1976,6 +1991,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
                                         sizeof(struct snd_timer_read)))
                                err = -EFAULT;
                }
+               mutex_unlock(&tu->ioctl_lock);
 
                spin_lock_irq(&tu->qlock);
                if (err < 0)
index c7cb7deafe48487fd802fbf5ce84e34c2f5ab2eb..2c316a9bc7f695cf35c2278145bb48808b766fe0 100644 (file)
@@ -106,7 +106,6 @@ struct snd_efw {
        u8 *resp_buf;
        u8 *pull_ptr;
        u8 *push_ptr;
-       unsigned int resp_queues;
 };
 
 int snd_efw_transaction_cmd(struct fw_unit *unit,
index 33df8655fe81f28872e01bbecd817ba7c37f8ede..2e1d9a23920c0c3ebf4b6edda5019b672dab4e82 100644 (file)
@@ -25,6 +25,7 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
 {
        unsigned int length, till_end, type;
        struct snd_efw_transaction *t;
+       u8 *pull_ptr;
        long count = 0;
 
        if (remained < sizeof(type) + sizeof(struct snd_efw_transaction))
@@ -38,8 +39,17 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
        buf += sizeof(type);
 
        /* write into buffer as many responses as possible */
-       while (efw->resp_queues > 0) {
-               t = (struct snd_efw_transaction *)(efw->pull_ptr);
+       spin_lock_irq(&efw->lock);
+
+       /*
+        * When another task reaches here during this task's access to user
+        * space, it picks up current position in buffer and can read the same
+        * series of responses.
+        */
+       pull_ptr = efw->pull_ptr;
+
+       while (efw->push_ptr != pull_ptr) {
+               t = (struct snd_efw_transaction *)(pull_ptr);
                length = be32_to_cpu(t->length) * sizeof(__be32);
 
                /* confirm enough space for this response */
@@ -49,26 +59,39 @@ hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
                /* copy from ring buffer to user buffer */
                while (length > 0) {
                        till_end = snd_efw_resp_buf_size -
-                               (unsigned int)(efw->pull_ptr - efw->resp_buf);
+                               (unsigned int)(pull_ptr - efw->resp_buf);
                        till_end = min_t(unsigned int, length, till_end);
 
-                       if (copy_to_user(buf, efw->pull_ptr, till_end))
+                       spin_unlock_irq(&efw->lock);
+
+                       if (copy_to_user(buf, pull_ptr, till_end))
                                return -EFAULT;
 
-                       efw->pull_ptr += till_end;
-                       if (efw->pull_ptr >= efw->resp_buf +
-                                            snd_efw_resp_buf_size)
-                               efw->pull_ptr -= snd_efw_resp_buf_size;
+                       spin_lock_irq(&efw->lock);
+
+                       pull_ptr += till_end;
+                       if (pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
+                               pull_ptr -= snd_efw_resp_buf_size;
 
                        length -= till_end;
                        buf += till_end;
                        count += till_end;
                        remained -= till_end;
                }
-
-               efw->resp_queues--;
        }
 
+       /*
+        * All of tasks can read from the buffer nearly simultaneously, but the
+        * last position for each task is different depending on the length of
+        * given buffer. Here, for simplicity, a position of buffer is set by
+        * the latest task. It's better for a listening application to allow one
+        * thread to read from the buffer. Unless, each task can read different
+        * sequence of responses depending on variation of buffer length.
+        */
+       efw->pull_ptr = pull_ptr;
+
+       spin_unlock_irq(&efw->lock);
+
        return count;
 }
 
@@ -76,14 +99,17 @@ static long
 hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
                  loff_t *offset)
 {
-       union snd_firewire_event event;
+       union snd_firewire_event event = {
+               .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
+       };
 
-       memset(&event, 0, sizeof(event));
+       spin_lock_irq(&efw->lock);
 
-       event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
        event.lock_status.status = (efw->dev_lock_count > 0);
        efw->dev_lock_changed = false;
 
+       spin_unlock_irq(&efw->lock);
+
        count = min_t(long, count, sizeof(event.lock_status));
 
        if (copy_to_user(buf, &event, count))
@@ -98,10 +124,15 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
 {
        struct snd_efw *efw = hwdep->private_data;
        DEFINE_WAIT(wait);
+       bool dev_lock_changed;
+       bool queued;
 
        spin_lock_irq(&efw->lock);
 
-       while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) {
+       dev_lock_changed = efw->dev_lock_changed;
+       queued = efw->push_ptr != efw->pull_ptr;
+
+       while (!dev_lock_changed && !queued) {
                prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
                spin_unlock_irq(&efw->lock);
                schedule();
@@ -109,15 +140,17 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                if (signal_pending(current))
                        return -ERESTARTSYS;
                spin_lock_irq(&efw->lock);
+               dev_lock_changed = efw->dev_lock_changed;
+               queued = efw->push_ptr != efw->pull_ptr;
        }
 
-       if (efw->dev_lock_changed)
+       spin_unlock_irq(&efw->lock);
+
+       if (dev_lock_changed)
                count = hwdep_read_locked(efw, buf, count, offset);
-       else if (efw->resp_queues > 0)
+       else if (queued)
                count = hwdep_read_resp_buf(efw, buf, count, offset);
 
-       spin_unlock_irq(&efw->lock);
-
        return count;
 }
 
@@ -160,7 +193,7 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
        poll_wait(file, &efw->hwdep_wait, wait);
 
        spin_lock_irq(&efw->lock);
-       if (efw->dev_lock_changed || (efw->resp_queues > 0))
+       if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr)
                events = POLLIN | POLLRDNORM;
        else
                events = 0;
index 0639dcb13f7df76ab2199259716bd22ba2e308de..beb0a0ffee57c4cfbb72845dd16a6f27b1c165ba 100644 (file)
@@ -188,8 +188,8 @@ proc_read_queues_state(struct snd_info_entry *entry,
        else
                consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr);
 
-       snd_iprintf(buffer, "%d %d/%d\n",
-                   efw->resp_queues, consumed, snd_efw_resp_buf_size);
+       snd_iprintf(buffer, "%d/%d\n",
+                   consumed, snd_efw_resp_buf_size);
 }
 
 static void
index f550808d178416cfd8c67cb9b78722687b2001e5..36a08ba51ec793ddd520ef5be9259b8fffaa0ed2 100644 (file)
@@ -121,11 +121,11 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
        size_t capacity, till_end;
        struct snd_efw_transaction *t;
 
-       spin_lock_irq(&efw->lock);
-
        t = (struct snd_efw_transaction *)data;
        length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
 
+       spin_lock_irq(&efw->lock);
+
        if (efw->push_ptr < efw->pull_ptr)
                capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
        else
@@ -155,7 +155,6 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
        }
 
        /* for hwdep */
-       efw->resp_queues++;
        wake_up(&efw->hwdep_wait);
 
        *rcode = RCODE_COMPLETE;
index 131267c3a04254fac3bd00767810abbb5fa9c7a3..106406cbfaa3926f294ad0831180472a1e50523d 100644 (file)
 
 #include "tascam.h"
 
-static long hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
-                             long count)
-{
-       union snd_firewire_event event;
-
-       memset(&event, 0, sizeof(event));
-
-       event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
-       event.lock_status.status = (tscm->dev_lock_count > 0);
-       tscm->dev_lock_changed = false;
-
-       count = min_t(long, count, sizeof(event.lock_status));
-
-       if (copy_to_user(buf, &event, count))
-               return -EFAULT;
-
-       return count;
-}
-
 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                       loff_t *offset)
 {
        struct snd_tscm *tscm = hwdep->private_data;
        DEFINE_WAIT(wait);
-       union snd_firewire_event event;
+       union snd_firewire_event event = {
+               .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
+       };
 
        spin_lock_irq(&tscm->lock);
 
@@ -54,10 +37,16 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                spin_lock_irq(&tscm->lock);
        }
 
-       memset(&event, 0, sizeof(event));
-       count = hwdep_read_locked(tscm, buf, count);
+       event.lock_status.status = (tscm->dev_lock_count > 0);
+       tscm->dev_lock_changed = false;
+
        spin_unlock_irq(&tscm->lock);
 
+       count = min_t(long, count, sizeof(event.lock_status));
+
+       if (copy_to_user(buf, &event, count))
+               return -EFAULT;
+
        return count;
 }
 
index 516795baa7db60ad37aec14d4886b4ce5da4f78d..5dfa610e4471887c1c1570a61cd921c6493372de 100644 (file)
@@ -21,13 +21,15 @@ void *snd_array_new(struct snd_array *array)
                return NULL;
        if (array->used >= array->alloced) {
                int num = array->alloced + array->alloc_align;
+               int oldsize = array->alloced * array->elem_size;
                int size = (num + 1) * array->elem_size;
                void *nlist;
                if (snd_BUG_ON(num >= 4096))
                        return NULL;
-               nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
+               nlist = krealloc(array->list, size, GFP_KERNEL);
                if (!nlist)
                        return NULL;
+               memset(nlist + oldsize, 0, size - oldsize);
                array->list = nlist;
                array->alloced = num;
        }
index 36470af7eda70689619388f6b2e774cf850492cd..92b819e4f7290c7ac056d72e35ce553829dce64a 100644 (file)
@@ -1408,6 +1408,7 @@ snd_ali_playback_pointer(struct snd_pcm_substream *substream)
        spin_unlock(&codec->reg_lock);
        dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso);
 
+       cso %= runtime->buffer_size;
        return cso;
 }
 
@@ -1428,6 +1429,7 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream)
        cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));
        spin_unlock(&codec->reg_lock);
 
+       cso %= runtime->buffer_size;
        return cso;
 }
 
index 9c22f95838efbd31d23448cc26321918c03bd5e1..19d41da79f93cc95500859c9e1690a2d89935d23 100644 (file)
@@ -49,7 +49,7 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec,
                removefunc = true;
                if (dell_led_set_func(DELL_LED_MICMUTE, false) >= 0) {
                        dell_led_value = 0;
-                       if (spec->gen.num_adc_nids > 1)
+                       if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch)
                                codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
                        else {
                                dell_old_cap_hook = spec->gen.cap_sync_hook;
index 8218cace8fea0976eb59380169b8a256e93a2090..d4671973d8890626555eac72e24a10f74cea8423 100644 (file)
@@ -944,20 +944,23 @@ static int azx_resume(struct device *dev)
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
        struct hda_intel *hda;
+       struct hdac_bus *bus;
 
        if (!card)
                return 0;
 
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
+       bus = azx_bus(chip);
        if (chip->disabled || hda->init_failed || !chip->running)
                return 0;
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
-               && hda->need_i915_power) {
-               snd_hdac_display_power(azx_bus(chip), true);
-               haswell_set_bclk(hda);
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+               snd_hdac_display_power(bus, true);
+               if (hda->need_i915_power)
+                       haswell_set_bclk(hda);
        }
+
        if (chip->msi)
                if (pci_enable_msi(pci) < 0)
                        chip->msi = 0;
@@ -967,6 +970,11 @@ static int azx_resume(struct device *dev)
 
        hda_intel_init_chip(chip, true);
 
+       /* power down again for link-controlled chips */
+       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
+           !hda->need_i915_power)
+               snd_hdac_display_power(bus, false);
+
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
        trace_azx_resume(chip);
@@ -1046,6 +1054,7 @@ static int azx_runtime_resume(struct device *dev)
 
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
+       bus = azx_bus(chip);
        if (chip->disabled || hda->init_failed)
                return 0;
 
@@ -1053,15 +1062,9 @@ static int azx_runtime_resume(struct device *dev)
                return 0;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               bus = azx_bus(chip);
-               if (hda->need_i915_power) {
-                       snd_hdac_display_power(bus, true);
+               snd_hdac_display_power(bus, true);
+               if (hda->need_i915_power)
                        haswell_set_bclk(hda);
-               } else {
-                       /* toggle codec wakeup bit for STATESTS read */
-                       snd_hdac_set_codec_wakeup(bus, true);
-                       snd_hdac_set_codec_wakeup(bus, false);
-               }
        }
 
        /* Read STATESTS before controller reset */
@@ -1081,6 +1084,11 @@ static int azx_runtime_resume(struct device *dev)
        azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
                        ~STATESTS_INT_MASK);
 
+       /* power down again for link-controlled chips */
+       if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
+           !hda->need_i915_power)
+               snd_hdac_display_power(bus, false);
+
        trace_azx_runtime_resume(chip);
        return 0;
 }
@@ -2288,6 +2296,8 @@ static const struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x1022, 0x780d),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* ATI HDMI */
+       { PCI_DEVICE(0x1002, 0x0002),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0x1308),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0x157a),
@@ -2356,6 +2366,10 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaae8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaae0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaaf0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        /* VIA VT8251/VT8237A */
        { PCI_DEVICE(0x1106, 0x3288),
          .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
index 600af5878e7545563384e387966062a9691bd33b..36cd715986bc53a40b61f4cd27bc927e114bec64 100644 (file)
@@ -261,6 +261,7 @@ enum {
        CXT_FIXUP_HP_530,
        CXT_FIXUP_CAP_MIX_AMP_5047,
        CXT_FIXUP_MUTE_LED_EAPD,
+       CXT_FIXUP_HP_SPECTRE,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -765,6 +766,14 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_mute_led_eapd,
        },
+       [CXT_FIXUP_HP_SPECTRE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* enable NID 0x1d for the speaker on top */
+                       { 0x1d, 0x91170111 },
+                       { }
+               }
+       },
 };
 
 static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -814,6 +823,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
        SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
+       SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
index f7bcd8dbac14f91c6ccfd409d8e898c27ba2d3bb..a8045b8a2a1898178d9656bd6185d81b394aab97 100644 (file)
@@ -51,8 +51,10 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 #define is_broadwell(codec)    ((codec)->core.vendor_id == 0x80862808)
 #define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809)
 #define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a)
+#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b)
 #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
-                               || is_skylake(codec) || is_broxton(codec))
+                               || is_skylake(codec) || is_broxton(codec) \
+                               || is_kabylake(codec))
 
 #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
 #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
@@ -3584,6 +3586,7 @@ HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",       patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",  patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",    patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",   patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_generic_hdmi),
index abcb5a6a1cd9547db9c83e1cada1456615d47db8..b1fa50aed88878b535a39b4c8f2016c5e361c198 100644 (file)
@@ -4674,6 +4674,22 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec,
        }
 }
 
+static void alc298_fixup_speaker_volume(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* The speaker is routed to the Node 0x06 by a mistake, as a result
+                  we can't adjust the speaker's volume since this node does not has
+                  Amp-out capability. we change the speaker's route to:
+                  Node 0x02 (Audio Output) -> Node 0x0c (Audio Mixer) -> Node 0x17 (
+                  Pin Complex), since Node 0x02 has Amp-out caps, we can adjust
+                  speaker's volume now. */
+
+               hda_nid_t conn1[1] = { 0x0c };
+               snd_hda_override_conn_list(codec, 0x17, 1, conn1);
+       }
+}
+
 /* Hook to update amp GPIO4 for automute */
 static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
                                          struct hda_jack_callback *jack)
@@ -4823,6 +4839,8 @@ enum {
        ALC280_FIXUP_HP_HEADSET_MIC,
        ALC221_FIXUP_HP_FRONT_MIC,
        ALC292_FIXUP_TPT460,
+       ALC298_FIXUP_SPK_VOLUME,
+       ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5478,6 +5496,21 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE,
        },
+       [ALC298_FIXUP_SPK_VOLUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_speaker_volume,
+               .chained = true,
+               .chain_id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+       },
+       [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170151 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5522,8 +5555,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
        SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
        SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
        SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
        SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5755,6 +5790,13 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x14, 0x90170110}, \
        {0x15, 0x0221401f}
 
+#define ALC295_STANDARD_PINS \
+       {0x12, 0xb7a60130}, \
+       {0x14, 0x90170110}, \
+       {0x17, 0x21014020}, \
+       {0x18, 0x21a19030}, \
+       {0x21, 0x04211020}
+
 #define ALC298_STANDARD_PINS \
        {0x12, 0x90a60130}, \
        {0x21, 0x03211020}
@@ -5794,10 +5836,18 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x12, 0x90a60160},
                {0x14, 0x90170120},
                {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x1b, 0x02011020},
+               {0x21, 0x0221101f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x14, 0x90170130},
                {0x1b, 0x01014020},
                {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x1b, 0x02011020},
+               {0x21, 0x0221103f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x14, 0x90170150},
                {0x1b, 0x02011020},
@@ -5851,6 +5901,14 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x12, 0x90a60170},
                {0x14, 0x90170120},
                {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell Inspiron 5468", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60180},
+               {0x14, 0x90170120},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0xb7a60130},
+               {0x14, 0x90170110},
+               {0x21, 0x02211020}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
@@ -5962,6 +6020,8 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x13, 0x90a60140}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC295_STANDARD_PINS),
        SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC298_STANDARD_PINS,
                {0x17, 0x90170110}),
index 0a4ad5feb82e7817f7036f86c973d02b1dfecb9b..12826ac0381f03f428a74216d52c1009837b2ae0 100644 (file)
@@ -75,7 +75,7 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
                        removefunc = false;
                }
                if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
-                       if (spec->num_adc_nids > 1)
+                       if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
                                codec_dbg(codec,
                                          "Skipping micmute LED control due to several ADCs");
                        else {
index ba8def5665c458842d2f333d35e34c2974b2136e..6726143c7fc5795e6e07d3fcf617d0e7523e5cbb 100644 (file)
@@ -298,8 +298,9 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        clk_enable(ssc_p->ssc->clk);
        ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
 
-       /* Reset the SSC to keep it at a clean status */
-       ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+       /* Reset the SSC unless initialized to keep it in a clean state */
+       if (!ssc_p->initialized)
+               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                dir = 0;
index adb32fefd693a059574674b414abc7d2811985e7..b1e6b8f34a6a797d335e9630b4972842400977f2 100644 (file)
@@ -279,17 +279,15 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
 
        if (response) {
                ret = sst_wait_timeout(sst, block);
-               if (ret < 0) {
+               if (ret < 0)
                        goto out;
-               } else if(block->data) {
-                       if (!data)
-                               goto out;
-                       *data = kzalloc(block->size, GFP_KERNEL);
-                       if (!(*data)) {
+
+               if (data && block->data) {
+                       *data = kmemdup(block->data, block->size, GFP_KERNEL);
+                       if (!*data) {
                                ret = -ENOMEM;
                                goto out;
-                       } else
-                               memcpy(data, (void *) block->data, block->size);
+                       }
                }
        }
 out:
index caa69c4598a6f14eb27c91575b49aae9fd7d3e8a..b4844f78266f7612b768743941b2bfbbf88e6d15 100644 (file)
@@ -464,8 +464,10 @@ static int skl_probe(struct pci_dev *pci,
 
        skl->nhlt = skl_nhlt_init(bus->dev);
 
-       if (skl->nhlt == NULL)
+       if (skl->nhlt == NULL) {
+               err = -ENODEV;
                goto out_free;
+       }
 
        pci_set_drvdata(skl->pci, ebus);
 
index b837265ac3e9afd90dc26e5e00b2b52d0d1d9239..8d0d45d330e762d4bc7b21aea779dab39f6a4c9a 100644 (file)
@@ -390,8 +390,8 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
        pm_runtime_get_sync(mcpdm->dev);
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
 
-       ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
-                               0, "McPDM", (void *)mcpdm);
+       ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM",
+                         (void *)mcpdm);
 
        pm_runtime_put_sync(mcpdm->dev);
 
@@ -416,6 +416,7 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
 {
        struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
+       free_irq(mcpdm->irq, (void *)mcpdm);
        pm_runtime_disable(mcpdm->dev);
 
        return 0;
index afb70a5d4fd3552964917abe09a88c60e0f8c8d7..b8a256dfed7eb74c56791ee9e56b235590ae0f51 100644 (file)
@@ -823,6 +823,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
                        case snd_soc_dapm_switch:
                        case snd_soc_dapm_mixer:
                        case snd_soc_dapm_pga:
+                       case snd_soc_dapm_out_drv:
                                wname_in_long_name = true;
                                kcname_in_long_name = true;
                                break;
@@ -3015,6 +3016,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        }
        mutex_unlock(&card->dapm_mutex);
 
+       if (ret)
+               return ret;
+
        if (invert)
                ucontrol->value.integer.value[0] = max - val;
        else
@@ -3166,7 +3170,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        if (e->shift_l != e->shift_r) {
                if (item[1] > e->items)
                        return -EINVAL;
-               val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
+               val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
                mask |= e->mask << e->shift_r;
        }
 
index 6963ba20991c10066fdad2ad65f3102fc5752424..70396d3f64728bad98d7f5a665ebfb66351bfdf9 100644 (file)
@@ -1484,6 +1484,7 @@ widget:
        if (widget == NULL) {
                dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n",
                        w->name);
+               ret = -ENOMEM;
                goto hdr_err;
        }
 
index 81b7da8e56d39e352a5b629bbdf73aa460889b4d..183311cb849ede12bb5f2e9c68f9c7ff40e3281b 100644 (file)
@@ -29,7 +29,7 @@
 /*
        This is Line 6's MIDI manufacturer ID.
 */
-const unsigned char line6_midi_id[] = {
+const unsigned char line6_midi_id[3] = {
        0x00, 0x01, 0x0c
 };
 EXPORT_SYMBOL_GPL(line6_midi_id);
index 204cc074adb96f8f99ebd9d69bd7e1e4cf91f98e..41aa3355e920499830aeefdaf961659dfcabdba3 100644 (file)
@@ -55,7 +55,6 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
                err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE);
                if (err < 0) {
                        line6pcm->impulse_volume = 0;
-                       line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
                        return err;
                }
        } else {
@@ -211,7 +210,9 @@ static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
        spin_lock_irqsave(&pstr->lock, flags);
        clear_bit(type, &pstr->running);
        if (!pstr->running) {
+               spin_unlock_irqrestore(&pstr->lock, flags);
                line6_unlink_audio_urbs(line6pcm, pstr);
+               spin_lock_irqsave(&pstr->lock, flags);
                if (direction == SNDRV_PCM_STREAM_CAPTURE) {
                        line6pcm->prev_fbuf = NULL;
                        line6pcm->prev_fsize = 0;
index daf81d169a42043f265a48df58afcc5490d40f97..45dd34874f43a7f00fc481b25d7b5bf80ffb6c02 100644 (file)
@@ -244,8 +244,8 @@ static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
 static ssize_t serial_number_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
+       struct snd_card *card = dev_to_snd_card(dev);
+       struct usb_line6_pod *pod = card->private_data;
 
        return sprintf(buf, "%u\n", pod->serial_number);
 }
@@ -256,8 +256,8 @@ static ssize_t serial_number_show(struct device *dev,
 static ssize_t firmware_version_show(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
+       struct snd_card *card = dev_to_snd_card(dev);
+       struct usb_line6_pod *pod = card->private_data;
 
        return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
                       pod->firmware_version % 100);
@@ -269,8 +269,8 @@ static ssize_t firmware_version_show(struct device *dev,
 static ssize_t device_id_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
+       struct snd_card *card = dev_to_snd_card(dev);
+       struct usb_line6_pod *pod = card->private_data;
 
        return sprintf(buf, "%d\n", pod->device_id);
 }
index f6c3bf79af9a7d9f7cabe6b83c3573a59964b826..04991b00913222f07f4d6dbcb0dc6b955db4f5a5 100644 (file)
@@ -1831,6 +1831,7 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
 }
 
 static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
+                                        struct usb_mixer_elem_info *cval,
                                         struct snd_kcontrol *kctl)
 {
        /* Approximation using 10 ranges based on output measurement on hw v1.2.
@@ -1848,10 +1849,19 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
                41, 50, TLV_DB_MINMAX_ITEM(-441, 0),
        );
 
-       usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk\n");
-       kctl->tlv.p = scale;
-       kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-       kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+       if (cval->min == 0 && cval->max == 50) {
+               usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk (0-50 variant)\n");
+               kctl->tlv.p = scale;
+               kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+               kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+
+       } else if (cval->min == 0 && cval->max <= 1000) {
+               /* Some other clearly broken DragonFly variant.
+                * At least a 0..53 variant (hw v1.0) exists.
+                */
+               usb_audio_info(mixer->chip, "ignoring too narrow dB range on a DragonFly device");
+               kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+       }
 }
 
 void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
@@ -1860,8 +1870,8 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
 {
        switch (mixer->chip->usb_id) {
        case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
-               if (unitid == 7 && cval->min == 0 && cval->max == 50)
-                       snd_dragonfly_quirk_db_scale(mixer, kctl);
+               if (unitid == 7 && cval->control == UAC_FU_VOLUME)
+                       snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
                break;
        }
 }
index 85d54920390368c7a0ebc1bdccb348f1abce65a3..10e5fb9cdd8bbfc984eec84b6d2954bb2123647e 100644 (file)
@@ -1129,6 +1129,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
 {
        /* devices which do not support reading the sample rate. */
        switch (chip->usb_id) {
+       case USB_ID(0x041E, 0x4080): /* Creative Live Cam VF0610 */
        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 */
@@ -1139,10 +1140,12 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
        case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
        case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */
+       case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */
 #ifdef CONFIG_HID_RKVR
        case USB_ID(0x071B, 0x3205): /* RockChip NanoC VR */
 #endif
        case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+       case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
        case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */
        case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */
        case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */
index 5480e4e424eb1906a2cd4118792d97bc6b6f365c..f1d74268231792e7b41fbc7200de0a043351b62c 100644 (file)
 
 static int target_fd;
 static char target_fname[W_MAX_PATH];
+static unsigned long long filesize;
 
 static int hv_start_fcopy(struct hv_start_fcopy *smsg)
 {
        int error = HV_E_FAIL;
        char *q, *p;
 
+       filesize = 0;
        p = (char *)smsg->path_name;
        snprintf(target_fname, sizeof(target_fname), "%s/%s",
                 (char *)smsg->path_name, (char *)smsg->file_name);
@@ -98,14 +100,26 @@ done:
 static int hv_copy_data(struct hv_do_fcopy *cpmsg)
 {
        ssize_t bytes_written;
+       int ret = 0;
 
        bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size,
                                cpmsg->offset);
 
-       if (bytes_written != cpmsg->size)
-               return HV_E_FAIL;
+       filesize += cpmsg->size;
+       if (bytes_written != cpmsg->size) {
+               switch (errno) {
+               case ENOSPC:
+                       ret = HV_ERROR_DISK_FULL;
+                       break;
+               default:
+                       ret = HV_E_FAIL;
+                       break;
+               }
+               syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)",
+                      filesize, (long)bytes_written, strerror(errno));
+       }
 
-       return 0;
+       return ret;
 }
 
 static int hv_copy_finished(void)
index e5c1f2e21f870bf53047c311829a2c653ddbee56..de3965c4e4aabecb5508999eb5ca99619da8d0f9 100644 (file)
@@ -501,7 +501,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
        struct intel_pt_recording *ptr =
                        container_of(itr, struct intel_pt_recording, itr);
        struct perf_pmu *intel_pt_pmu = ptr->intel_pt_pmu;
-       bool have_timing_info;
+       bool have_timing_info, need_immediate = false;
        struct perf_evsel *evsel, *intel_pt_evsel = NULL;
        const struct cpu_map *cpus = evlist->cpus;
        bool privileged = geteuid() == 0 || perf_event_paranoid() < 0;
@@ -655,6 +655,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
                                ptr->have_sched_switch = 3;
                        } else {
                                opts->record_switch_events = true;
+                               need_immediate = true;
                                if (cpu_wide)
                                        ptr->have_sched_switch = 3;
                                else
@@ -700,6 +701,9 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
                tracking_evsel->attr.freq = 0;
                tracking_evsel->attr.sample_period = 1;
 
+               if (need_immediate)
+                       tracking_evsel->immediate = true;
+
                /* In per-cpu case, always need the time of mmap events etc */
                if (!cpu_map__empty(cpus)) {
                        perf_evsel__set_sample_bit(tracking_evsel, TIME);
index 3900386a3629410b903223642b449159ecd18e13..d802938644b5cbe2df67afcb4af2db273b7e9dd4 100644 (file)
@@ -684,7 +684,6 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
        ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
        ui_browser__printf(arg->b, "%s", hpp->buf);
 
-       advance_hpp(hpp, ret);
        return ret;
 }
 
index 9409d014b46c713de02df828cf9ad7ff726881e8..71df7acf86435bd000567b9a00acec9562b7e417 100644 (file)
@@ -89,6 +89,7 @@ struct intel_pt_decoder {
        bool pge;
        bool have_tma;
        bool have_cyc;
+       bool fixup_last_mtc;
        uint64_t pos;
        uint64_t last_ip;
        uint64_t ip;
@@ -584,10 +585,31 @@ struct intel_pt_calc_cyc_to_tsc_info {
        uint64_t        tsc_timestamp;
        uint64_t        timestamp;
        bool            have_tma;
+       bool            fixup_last_mtc;
        bool            from_mtc;
        double          cbr_cyc_to_tsc;
 };
 
+/*
+ * MTC provides a 8-bit slice of CTC but the TMA packet only provides the lower
+ * 16 bits of CTC. If mtc_shift > 8 then some of the MTC bits are not in the CTC
+ * provided by the TMA packet. Fix-up the last_mtc calculated from the TMA
+ * packet by copying the missing bits from the current MTC assuming the least
+ * difference between the two, and that the current MTC comes after last_mtc.
+ */
+static void intel_pt_fixup_last_mtc(uint32_t mtc, int mtc_shift,
+                                   uint32_t *last_mtc)
+{
+       uint32_t first_missing_bit = 1U << (16 - mtc_shift);
+       uint32_t mask = ~(first_missing_bit - 1);
+
+       *last_mtc |= mtc & mask;
+       if (*last_mtc >= mtc) {
+               *last_mtc -= first_missing_bit;
+               *last_mtc &= 0xff;
+       }
+}
+
 static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
 {
        struct intel_pt_decoder *decoder = pkt_info->decoder;
@@ -617,6 +639,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
                        return 0;
 
                mtc = pkt_info->packet.payload;
+               if (decoder->mtc_shift > 8 && data->fixup_last_mtc) {
+                       data->fixup_last_mtc = false;
+                       intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
+                                               &data->last_mtc);
+               }
                if (mtc > data->last_mtc)
                        mtc_delta = mtc - data->last_mtc;
                else
@@ -685,6 +712,7 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
 
                data->ctc_delta = 0;
                data->have_tma = true;
+               data->fixup_last_mtc = true;
 
                return 0;
 
@@ -751,6 +779,7 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder,
                .tsc_timestamp  = decoder->tsc_timestamp,
                .timestamp      = decoder->timestamp,
                .have_tma       = decoder->have_tma,
+               .fixup_last_mtc = decoder->fixup_last_mtc,
                .from_mtc       = from_mtc,
                .cbr_cyc_to_tsc = 0,
        };
@@ -1241,6 +1270,7 @@ static void intel_pt_calc_tma(struct intel_pt_decoder *decoder)
        }
        decoder->ctc_delta = 0;
        decoder->have_tma = true;
+       decoder->fixup_last_mtc = true;
        intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x  CTC rem %#x\n",
                     decoder->ctc_timestamp, decoder->last_mtc, ctc_rem);
 }
@@ -1255,6 +1285,12 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
 
        mtc = decoder->packet.payload;
 
+       if (decoder->mtc_shift > 8 && decoder->fixup_last_mtc) {
+               decoder->fixup_last_mtc = false;
+               intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
+                                       &decoder->last_mtc);
+       }
+
        if (mtc > decoder->last_mtc)
                mtc_delta = mtc - decoder->last_mtc;
        else
@@ -1323,6 +1359,8 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
                             timestamp, decoder->timestamp);
        else
                decoder->timestamp = timestamp;
+
+       decoder->timestamp_insn_cnt = 0;
 }
 
 /* Walk PSB+ packets when already in sync. */
index 9227c2f076c36195ec476dc64d6236341026decd..89927b5beebf622cfb20c24cca22f599f74e3cbd 100644 (file)
@@ -238,7 +238,7 @@ static int intel_pt_get_trace(struct intel_pt_buffer *b, void *data)
        }
 
        queue = &ptq->pt->queues.queue_array[ptq->queue_nr];
-
+next:
        buffer = auxtrace_buffer__next(queue, buffer);
        if (!buffer) {
                if (old_buffer)
@@ -261,9 +261,6 @@ static int intel_pt_get_trace(struct intel_pt_buffer *b, void *data)
            intel_pt_do_fix_overlap(ptq->pt, old_buffer, buffer))
                return -ENOMEM;
 
-       if (old_buffer)
-               auxtrace_buffer__drop_data(old_buffer);
-
        if (buffer->use_data) {
                b->len = buffer->use_size;
                b->buf = buffer->use_data;
@@ -273,6 +270,16 @@ static int intel_pt_get_trace(struct intel_pt_buffer *b, void *data)
        }
        b->ref_timestamp = buffer->reference;
 
+       /*
+        * If in snapshot mode and the buffer has no usable data, get next
+        * buffer and again check overlap against old_buffer.
+        */
+       if (ptq->pt->snapshot_mode && !b->len)
+               goto next;
+
+       if (old_buffer)
+               auxtrace_buffer__drop_data(old_buffer);
+
        if (!old_buffer || ptq->pt->sampling_mode || (ptq->pt->snapshot_mode &&
                                                      !buffer->consecutive)) {
                b->consecutive = false;
index 4a3a72cb5805e256871abda351792ba23b2d30cd..6ce624cb7001249d703248e7aa566e7941117f04 100644 (file)
@@ -311,6 +311,16 @@ int perf_stat_process_counter(struct perf_stat_config *config,
 
        aggr->val = aggr->ena = aggr->run = 0;
 
+       /*
+        * We calculate counter's data every interval,
+        * and the display code shows ps->res_stats
+        * avg value. We need to zero the stats for
+        * interval mode, otherwise overall avg running
+        * averages will be shown for each interval.
+        */
+       if (config->interval)
+               init_stats(ps->res_stats);
+
        if (counter->per_pkg)
                zero_per_pkg(counter);
 
index 475d88d0a1c9a772323b3218cfcf5f5900c0e809..27ae382feb2d780238eb3f0dfe083589070fb4c7 100644 (file)
@@ -1091,9 +1091,8 @@ new_symbol:
         * For misannotated, zeroed, ASM function sizes.
         */
        if (nr > 0) {
-               if (!symbol_conf.allow_aliases)
-                       symbols__fixup_duplicate(&dso->symbols[map->type]);
                symbols__fixup_end(&dso->symbols[map->type]);
+               symbols__fixup_duplicate(&dso->symbols[map->type]);
                if (kmap) {
                        /*
                         * We need to fixup this here too because we create new
index 1d0d8bff4a5b94a1e92af5ab903df30dd73a2e25..754711be8b251b2c0e33d1a57053710b20dc8edf 100644 (file)
@@ -151,6 +151,9 @@ void symbols__fixup_duplicate(struct rb_root *symbols)
        struct rb_node *nd;
        struct symbol *curr, *next;
 
+       if (symbol_conf.allow_aliases)
+               return;
+
        nd = rb_first(symbols);
 
        while (nd) {
@@ -1275,8 +1278,8 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
        if (kallsyms__delta(map, filename, &delta))
                return -1;
 
-       symbols__fixup_duplicate(&dso->symbols[map->type]);
        symbols__fixup_end(&dso->symbols[map->type]);
+       symbols__fixup_duplicate(&dso->symbols[map->type]);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
index 51cf8256c6cda1b8c28cf4393496a77b63e0c171..f0d1c8ff8e8ab91074c79f68038723bf4112743c 100644 (file)
@@ -13,6 +13,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
 #include <linux/libnvdimm.h>
 #include <linux/vmalloc.h>
 #include <linux/device.h>
@@ -1246,6 +1247,7 @@ static int nfit_test_probe(struct platform_device *pdev)
        if (nfit_test->setup != nfit_test0_setup)
                return 0;
 
+       flush_work(&acpi_desc->work);
        nfit_test->setup_hotplug = 1;
        nfit_test->setup(nfit_test);
 
index 86e698d07e20d66931f7846b8061c82018927382..499b8819d4c6ab85b2e9ce677b0116b32fa8ff3e 100644 (file)
@@ -510,10 +510,11 @@ static void slab_stats(struct slabinfo *s)
                        s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
        }
 
-       if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail)
+       if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) {
                printf("\nCmpxchg_double Looping\n------------------------\n");
                printf("Locked Cmpxchg Double redos   %lu\nUnlocked Cmpxchg Double redos %lu\n",
                        s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
+       }
 }
 
 static void report(struct slabinfo *s)
index 510df220d1b5d92850c7eb3f9e8d3ac0aa890a21..336ed267c4070d4ee661ee4eb3a6c7c7affbd796 100644 (file)
@@ -142,6 +142,7 @@ int vcpu_load(struct kvm_vcpu *vcpu)
        put_cpu();
        return 0;
 }
+EXPORT_SYMBOL_GPL(vcpu_load);
 
 void vcpu_put(struct kvm_vcpu *vcpu)
 {
@@ -151,6 +152,7 @@ void vcpu_put(struct kvm_vcpu *vcpu)
        preempt_enable();
        mutex_unlock(&vcpu->mutex);
 }
+EXPORT_SYMBOL_GPL(vcpu_put);
 
 static void ack_flush(void *_completed)
 {