Merge branch 'core' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu into...
authorVlastimil Babka <vbabka@suse.cz>
Thu, 6 Jan 2022 17:03:29 +0000 (18:03 +0100)
committerVlastimil Babka <vbabka@suse.cz>
Thu, 6 Jan 2022 17:03:29 +0000 (18:03 +0100)
Merge iommu tree for a series that removes usage of struct page
'freelist' field.

606 files changed:
.mailmap
Documentation/admin-guide/blockdev/drbd/figures.rst
Documentation/admin-guide/blockdev/drbd/peer-states-8.dot [moved from Documentation/admin-guide/blockdev/drbd/node-states-8.dot with 71% similarity]
Documentation/conf.py
Documentation/devicetree/bindings/i2c/apple,i2c.yaml
Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml
Documentation/devicetree/bindings/input/gpio-keys.yaml
Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
Documentation/devicetree/bindings/net/ethernet-phy.yaml
Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
Documentation/devicetree/bindings/power/supply/bq25980.yaml
Documentation/devicetree/bindings/sound/wlf,wm8962.yaml
Documentation/devicetree/bindings/spi/spi-rockchip.yaml
Documentation/locking/locktypes.rst
Documentation/networking/device_drivers/ethernet/intel/ixgbe.rst
Documentation/process/changes.rst
Documentation/process/submitting-patches.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/imx6qp-prtwd3.dts
arch/arm/boot/dts/imx6ull-pinfunc.h
arch/arm/boot/dts/ls1021a-tsn.dts
arch/arm/boot/dts/socfpga_arria10_socdk_qspi.dts
arch/arm/boot/dts/socfpga_arria5_socdk.dts
arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
arch/arm/boot/dts/socfpga_cyclone5_socrates.dts
arch/arm/boot/dts/socfpga_cyclone5_sodia.dts
arch/arm/boot/dts/socfpga_cyclone5_vining_fpga.dts
arch/arm/mach-rockchip/platsmp.c
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j100.dts
arch/arm64/boot/dts/apple/t8103-j274.dts
arch/arm64/boot/dts/apple/t8103.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
arch/arm64/boot/dts/freescale/fsl-lx2160a-bluebox3.dts
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts
arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi
arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts
arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts
arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi
arch/arm64/kernel/machine_kexec_file.c
arch/csky/kernel/traps.c
arch/mips/include/asm/mach-ralink/spaces.h
arch/mips/include/asm/pci.h
arch/mips/net/bpf_jit_comp.h
arch/mips/pci/pci-generic.c
arch/powerpc/kernel/module_64.c
arch/powerpc/platforms/85xx/smp.c
arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
arch/riscv/boot/dts/sifive/hifive-unmatched-a00.dts
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/kernel/ftrace.c
arch/s390/kernel/irq.c
arch/s390/kernel/machine_kexec_file.c
arch/x86/Kconfig
arch/x86/include/asm/kvm_host.h
arch/x86/kernel/smpboot.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/init_64.c
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/quirks.c
block/blk-iocost.c
block/fops.c
block/ioprio.c
drivers/Makefile
drivers/android/binder.c
drivers/ata/ahci_ceva.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/bus/mhi/core/pm.c
drivers/bus/mhi/pci_generic.c
drivers/clk/clk.c
drivers/clk/imx/clk-imx8qxp-lpcg.c
drivers/clk/imx/clk-imx8qxp.c
drivers/clk/qcom/clk-alpha-pll.c
drivers/clk/qcom/clk-regmap-mux.c
drivers/clk/qcom/common.c
drivers/clk/qcom/common.h
drivers/clk/qcom/gcc-sm6125.c
drivers/clk/versatile/clk-icst.c
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/dw_apb_timer_of.c
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/dw-edma/dw-edma-pcie.c
drivers/dma/idxd/irq.c
drivers/dma/idxd/submit.c
drivers/dma/st_fdma.c
drivers/dma/ti/k3-udma.c
drivers/firmware/scpi_pm_domain.c
drivers/firmware/tegra/bpmp-debugfs.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/drm_syncobj.c
drivers/gpu/drm/i915/display/intel_dmc.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gt/intel_gtt.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/lima/lima_device.c
drivers/gpu/drm/msm/msm_gem_shrinker.c
drivers/gpu/drm/tiny/simpledrm.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/hid/Kconfig
drivers/hid/hid-asus.c
drivers/hid/hid-bigbenff.c
drivers/hid/hid-chicony.c
drivers/hid/hid-corsair.c
drivers/hid/hid-elan.c
drivers/hid/hid-elo.c
drivers/hid/hid-ft260.c
drivers/hid/hid-google-hammer.c
drivers/hid/hid-holtek-kbd.c
drivers/hid/hid-holtek-mouse.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lg.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-prodikeys.c
drivers/hid/hid-quirks.c
drivers/hid/hid-roccat-arvo.c
drivers/hid/hid-roccat-isku.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-koneplus.c
drivers/hid/hid-roccat-konepure.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/hid-roccat-lua.c
drivers/hid/hid-roccat-pyra.c
drivers/hid/hid-roccat-ryos.c
drivers/hid/hid-roccat-savu.c
drivers/hid/hid-samsung.c
drivers/hid/hid-sony.c
drivers/hid/hid-thrustmaster.c
drivers/hid/hid-u2fzero.c
drivers/hid/hid-uclogic-core.c
drivers/hid/hid-uclogic-params.c
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/wacom_sys.c
drivers/hv/Kconfig
drivers/hwmon/corsair-psu.c
drivers/hwmon/dell-smm-hwmon.c
drivers/hwmon/nct6775.c
drivers/hwmon/pwm-fan.c
drivers/hwmon/sht4x.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-virtio.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/kxsd9.c
drivers/iio/accel/mma8452.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ad7768-1.c
drivers/iio/adc/at91-sama5d2_adc.c
drivers/iio/adc/axp20x_adc.c
drivers/iio/adc/dln2-adc.c
drivers/iio/adc/stm32-adc.c
drivers/iio/gyro/adxrs290.c
drivers/iio/gyro/itg3200_buffer.c
drivers/iio/industrialio-trigger.c
drivers/iio/light/ltr501.c
drivers/iio/light/stk3310.c
drivers/iio/trigger/stm32-timer-trigger.c
drivers/infiniband/hw/hfi1/chip.c
drivers/infiniband/hw/hfi1/driver.c
drivers/infiniband/hw/hfi1/init.c
drivers/infiniband/hw/hfi1/sdma.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/irdma/hw.c
drivers/infiniband/hw/irdma/main.h
drivers/infiniband/hw/irdma/pble.c
drivers/infiniband/hw/irdma/pble.h
drivers/infiniband/hw/irdma/utils.c
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/hw/irdma/verbs.h
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/sw/rxe/rxe_qp.c
drivers/infiniband/ulp/rtrs/rtrs-clt-stats.c
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-armada-370-xp.c
drivers/irqchip/irq-aspeed-scu-ic.c
drivers/irqchip/irq-bcm7120-l2.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/irq-nvic.c
drivers/md/bcache/super.c
drivers/md/dm-integrity.c
drivers/md/md.c
drivers/md/persistent-data/dm-btree-remove.c
drivers/misc/cardreader/rtsx_pcr.c
drivers/misc/eeprom/at25.c
drivers/misc/fastrpc.c
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/net/bonding/bond_alb.c
drivers/net/can/kvaser_pciefd.c
drivers/net/can/m_can/m_can.c
drivers/net/can/m_can/m_can.h
drivers/net/can/m_can/m_can_pci.c
drivers/net/can/pch_can.c
drivers/net/can/sja1000/ems_pcmcia.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/port.c
drivers/net/dsa/mv88e6xxx/serdes.c
drivers/net/dsa/ocelot/felix.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/broadcom/bcm4908_enet.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bcmsysport.h
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/google/gve/gve_utils.c
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c
drivers/net/ethernet/huawei/hinic/hinic_sriov.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/iavf/iavf_ethtool.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/ice/ice_dcb_nl.c
drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
drivers/net/ethernet/intel/ice/ice_fdir.c
drivers/net/ethernet/intel/ice/ice_flex_pipe.c
drivers/net/ethernet/intel/ice/ice_flex_pipe.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_ptp.c
drivers/net/ethernet/intel/ice/ice_ptp.h
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/intel/ice/ice_tc_lib.c
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/igc/igc_i225.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/microsoft/mana/hw_channel.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cppcore.c
drivers/net/ethernet/qlogic/qede/qede_fp.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/sfc/ef100_nic.c
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/netdevsim/bpf.c
drivers/net/netdevsim/ethtool.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/phylink.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/lan78xx.c
drivers/net/usb/qmi_wwan.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vrf.c
drivers/net/wireless/ath/ath11k/mhi.c
drivers/net/wireless/broadcom/brcm80211/Kconfig
drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile
drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
drivers/net/wireless/intel/iwlegacy/Kconfig
drivers/net/wireless/intel/iwlwifi/Kconfig
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/mediatek/mt76/Makefile
drivers/net/wwan/iosm/iosm_ipc_imem.c
drivers/net/wwan/iosm/iosm_ipc_imem.h
drivers/net/wwan/iosm/iosm_ipc_imem_ops.c
drivers/nvme/host/core.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/zns.c
drivers/nvme/target/tcp.c
drivers/of/irq.c
drivers/pci/controller/Kconfig
drivers/pci/controller/dwc/pci-exynos.c
drivers/pci/controller/dwc/pcie-qcom-ep.c
drivers/pci/controller/pci-aardvark.c
drivers/pci/controller/pcie-apple.c
drivers/pci/msi.c
drivers/phy/hisilicon/phy-hi3670-pcie.c
drivers/phy/marvell/phy-mvebu-cp110-utmi.c
drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c
drivers/phy/qualcomm/phy-qcom-qmp.c
drivers/phy/qualcomm/phy-qcom-usb-hsic.c
drivers/phy/st/phy-stm32-usbphyc.c
drivers/phy/ti/phy-am654-serdes.c
drivers/phy/ti/phy-j721e-wiz.c
drivers/phy/ti/phy-omap-usb2.c
drivers/phy/ti/phy-tusb1210.c
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/intel/hid.c
drivers/platform/x86/lg-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/reset/tegra/reset-bpmp.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/qedi/qedi_iscsi.c
drivers/scsi/qedi/qedi_iscsi.h
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/scsi_debug.c
drivers/soc/imx/imx8m-blk-ctrl.c
drivers/soc/imx/soc-imx.c
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse.h
drivers/tee/amdtee/core.c
drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
drivers/tty/n_hdlc.c
drivers/tty/serial/8250/8250_fintek.c
drivers/usb/cdns3/cdnsp-gadget.c
drivers/usb/cdns3/cdnsp-ring.c
drivers/usb/cdns3/cdnsp-trace.h
drivers/usb/cdns3/host.c
drivers/usb/core/config.c
drivers/usb/core/quirks.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/early/xhci-dbc.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/legacy/dbgp.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mtk-sch.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/option.c
drivers/usb/typec/tcpm/tcpm.c
drivers/vdpa/vdpa.c
drivers/vdpa/vdpa_user/vduse_dev.c
drivers/vhost/vdpa.c
drivers/virtio/virtio_ring.c
fs/afs/file.c
fs/afs/super.c
fs/aio.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delalloc-space.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/free-space-tree.c
fs/btrfs/ioctl.c
fs/btrfs/qgroup.c
fs/btrfs/root-tree.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/zoned.c
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/mds_client.c
fs/cifs/connect.c
fs/cifs/fs_context.c
fs/cifs/inode.c
fs/cifs/sess.c
fs/file.c
fs/io-wq.c
fs/io_uring.c
fs/netfs/read_helper.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfsctl.c
fs/signalfd.c
fs/smbfs_common/cifs_arc4.c
fs/tracefs/inode.c
fs/xfs/xfs_super.c
fs/zonefs/super.c
include/linux/bootmem_info.h
include/linux/bpf.h
include/linux/btf.h
include/linux/cacheinfo.h
include/linux/delay.h
include/linux/device/driver.h
include/linux/filter.h
include/linux/hid.h
include/linux/kasan.h
include/linux/memcontrol.h
include/linux/mhi.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/percpu-refcount.h
include/linux/phy.h
include/linux/pm_runtime.h
include/linux/regulator/driver.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/wait.h
include/net/bond_alb.h
include/net/busy_poll.h
include/net/netfilter/nf_conntrack.h
include/uapi/asm-generic/poll.h
include/uapi/linux/mptcp.h
include/uapi/linux/resource.h
kernel/audit.c
kernel/bpf/btf.c
kernel/bpf/verifier.c
kernel/locking/rtmutex.c
kernel/sched/wait.c
kernel/signal.c
kernel/time/timekeeping.c
kernel/time/timer.c
kernel/trace/ftrace.c
kernel/trace/trace_events_synth.c
lib/Kconfig.debug
mm/Kconfig
mm/backing-dev.c
mm/bootmem_info.c
mm/damon/core.c
mm/damon/dbgfs.c
mm/damon/vaddr-test.h
mm/damon/vaddr.c
mm/filemap.c
mm/hugetlb.c
mm/kasan/common.c
mm/kasan/generic.c
mm/kasan/kasan.h
mm/kasan/quarantine.c
mm/kasan/report.c
mm/kasan/report_tags.c
mm/kfence/core.c
mm/kfence/kfence_test.c
mm/memcontrol.c
mm/memory_hotplug.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/swap_slots.c
mm/usercopy.c
mm/zsmalloc.c
net/core/devlink.c
net/core/neighbour.c
net/core/skbuff.c
net/core/skmsg.c
net/core/sock_map.c
net/ethtool/netlink.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/tcp_minisocks.c
net/ipv4/udp.c
net/ipv6/seg6_iptunnel.c
net/ipv6/sit.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/driver-ops.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mptcp/pm_netlink.c
net/mptcp/protocol.c
net/mptcp/sockopt.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_exthdr.c
net/netfilter/nft_set_pipapo_avx2.c
net/nfc/netlink.c
net/packet/af_packet.c
net/phonet/pep.c
net/rds/connection.c
net/sched/cls_api.c
net/sched/sch_cake.c
net/sched/sch_ets.c
net/sched/sch_fq_pie.c
net/smc/af_smc.c
net/vmw_vsock/virtio_transport_common.c
net/wireless/reg.c
net/xdp/xsk.c
samples/ftrace/Makefile
samples/ftrace/ftrace-direct-multi-modify.c [new file with mode: 0644]
scripts/recordmcount.pl
security/selinux/hooks.c
sound/core/control_compat.c
sound/core/oss/pcm_oss.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/yc/pci-acp6x.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682s.c
sound/soc/codecs/wcd934x.c
sound/soc/codecs/wsa881x.c
sound/soc/qcom/qdsp6/q6routing.c
sound/soc/rockchip/rockchip_i2s_tdm.c
sound/soc/sof/intel/hda-codec.c
sound/soc/tegra/tegra210_adx.c
sound/soc/tegra/tegra210_amx.c
sound/soc/tegra/tegra210_mixer.c
sound/soc/tegra/tegra210_mvc.c
sound/soc/tegra/tegra210_sfc.c
sound/usb/mixer_quirks.c
tools/bpf/resolve_btfids/main.c
tools/build/Makefile.feature
tools/build/feature/Makefile
tools/build/feature/test-all.c
tools/build/feature/test-libpython-version.c [deleted file]
tools/include/linux/debug_locks.h [deleted file]
tools/include/linux/hardirq.h [deleted file]
tools/include/linux/irqflags.h [deleted file]
tools/include/linux/lockdep.h [deleted file]
tools/include/linux/proc_fs.h [deleted file]
tools/include/linux/spinlock.h
tools/include/linux/stacktrace.h [deleted file]
tools/perf/Makefile.config
tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
tools/perf/arch/s390/entry/syscalls/syscall.tbl
tools/perf/bench/sched-messaging.c
tools/perf/builtin-inject.c
tools/perf/tests/expr.c
tools/perf/tests/parse-metric.c
tools/perf/util/bpf_skel/bperf.h [deleted file]
tools/perf/util/bpf_skel/bperf_follower.bpf.c
tools/perf/util/bpf_skel/bperf_leader.bpf.c
tools/perf/util/bpf_skel/bpf_prog_profiler.bpf.c
tools/perf/util/event.h
tools/perf/util/expr.c
tools/perf/util/header.c
tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
tools/perf/util/intel-pt.c
tools/perf/util/perf_regs.c
tools/perf/util/python.c
tools/perf/util/smt.c
tools/power/acpi/Makefile.config
tools/power/acpi/Makefile.rules
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
tools/testing/selftests/bpf/progs/test_module_attach.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c
tools/testing/selftests/bpf/verifier/atomic_fetch.c
tools/testing/selftests/bpf/verifier/search_pruning.c
tools/testing/selftests/bpf/verifier/spill_fill.c
tools/testing/selftests/bpf/verifier/value_ptr_arith.c
tools/testing/selftests/bpf/verifier/xdp_direct_packet_access.c
tools/testing/selftests/damon/.gitignore [new file with mode: 0644]
tools/testing/selftests/damon/Makefile
tools/testing/selftests/damon/_debugfs_common.sh [new file with mode: 0644]
tools/testing/selftests/damon/debugfs_attrs.sh
tools/testing/selftests/damon/debugfs_empty_targets.sh [new file with mode: 0644]
tools/testing/selftests/damon/debugfs_huge_count_read_write.sh [new file with mode: 0644]
tools/testing/selftests/damon/debugfs_schemes.sh [new file with mode: 0644]
tools/testing/selftests/damon/debugfs_target_ids.sh [new file with mode: 0644]
tools/testing/selftests/damon/huge_count_read_write.c [new file with mode: 0644]
tools/testing/selftests/drivers/net/mlxsw/rif_mac_profiles_occ.sh
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c
tools/testing/selftests/kvm/x86_64/userspace_io_test.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c
tools/testing/selftests/net/fcnal-test.sh
tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/net/forwarding/forwarding.config.sample
tools/testing/selftests/net/icmp_redirect.sh
tools/testing/selftests/net/tls.c
tools/testing/selftests/net/toeplitz.c
tools/testing/selftests/netfilter/conntrack_vrf.sh
tools/testing/selftests/netfilter/nft_concat_range.sh
tools/testing/selftests/netfilter/nft_zones_many.sh
tools/testing/selftests/tc-testing/config
tools/testing/selftests/tc-testing/tdc.py
tools/testing/selftests/tc-testing/tdc.sh

index 6277bb2..b344067 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -126,6 +126,8 @@ Greg Kroah-Hartman <gregkh@suse.de>
 Greg Kroah-Hartman <greg@kroah.com>
 Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
 Gregory CLEMENT <gregory.clement@bootlin.com> <gregory.clement@free-electrons.com>
+Guo Ren <guoren@kernel.org> <guoren@linux.alibaba.com>
+Guo Ren <guoren@kernel.org> <ren_guo@c-sky.com>
 Gustavo Padovan <gustavo@las.ic.unicamp.br>
 Gustavo Padovan <padovan@profusion.mobi>
 Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org>
index bd9a490..9f73253 100644 (file)
@@ -25,6 +25,6 @@ Sub graphs of DRBD's state transitions
     :alt:   disk-states-8.dot
     :align: center
 
-.. kernel-figure:: node-states-8.dot
-    :alt:   node-states-8.dot
+.. kernel-figure:: peer-states-8.dot
+    :alt:   peer-states-8.dot
     :align: center
@@ -1,8 +1,3 @@
-digraph node_states {
-       Secondary -> Primary           [ label = "ioctl_set_state()" ]
-       Primary   -> Secondary         [ label = "ioctl_set_state()" ]
-}
-
 digraph peer_states {
        Secondary -> Primary           [ label = "recv state packet" ]
        Primary   -> Secondary         [ label = "recv state packet" ]
index 17f7cee..76e5eb5 100644 (file)
@@ -249,11 +249,16 @@ except ImportError:
 
 html_static_path = ['sphinx-static']
 
-html_context = {
-    'css_files': [
-        '_static/theme_overrides.css',
-    ],
-}
+html_css_files = [
+    'theme_overrides.css',
+]
+
+if major <= 1 and minor < 8:
+    html_context = {
+        'css_files': [
+            '_static/theme_overrides.css',
+        ],
+    }
 
 # Add any extra paths that contain custom files (such as robots.txt or
 # .htaccess) here, relative to this directory. These files are copied
index 22fc848..82b9531 100644 (file)
@@ -20,9 +20,9 @@ allOf:
 
 properties:
   compatible:
-    enum:
-      - apple,t8103-i2c
-      - apple,i2c
+    items:
+      - const: apple,t8103-i2c
+      - const: apple,i2c
 
   reg:
     maxItems: 1
@@ -51,7 +51,7 @@ unevaluatedProperties: false
 examples:
   - |
     i2c@35010000 {
-      compatible = "apple,t8103-i2c";
+      compatible = "apple,t8103-i2c", "apple,i2c";
       reg = <0x35010000 0x4000>;
       interrupt-parent = <&aic>;
       interrupts = <0 627 4>;
index c65921e..81c8729 100644 (file)
@@ -136,7 +136,7 @@ examples:
         samsung,syscon-phandle = <&pmu_system_controller>;
 
         /* NTC thermistor is a hwmon device */
-        ncp15wb473 {
+        thermistor {
             compatible = "murata,ncp15wb473";
             pullup-uv = <1800000>;
             pullup-ohm = <47000>;
index 060a309..dbe7ecc 100644 (file)
@@ -142,7 +142,7 @@ examples:
         down {
             label = "GPIO Key DOWN";
             linux,code = <108>;
-            interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+            interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
         };
     };
 
index 877183c..1ef849d 100644 (file)
@@ -79,6 +79,8 @@ properties:
 
             properties:
               data-lanes:
+                description:
+                  Note that 'fsl,imx7-mipi-csi2' only supports up to 2 data lines.
                 items:
                   minItems: 1
                   maxItems: 4
@@ -91,18 +93,6 @@ properties:
             required:
               - data-lanes
 
-            allOf:
-              - if:
-                  properties:
-                    compatible:
-                      contains:
-                        const: fsl,imx7-mipi-csi2
-                then:
-                  properties:
-                    data-lanes:
-                      items:
-                        maxItems: 2
-
       port@1:
         $ref: /schemas/graph.yaml#/properties/port
         description:
index 2766fe4..ee42328 100644 (file)
@@ -91,6 +91,14 @@ properties:
       compensate for the board being designed with the lanes
       swapped.
 
+  enet-phy-lane-no-swap:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      If set, indicates that PHY will disable swap of the
+      TX/RX lanes. This property allows the PHY to work correcly after
+      e.g. wrong bootstrap configuration caused by issues in PCB
+      layout design.
+
   eee-broken-100tx:
     $ref: /schemas/types.yaml#/definitions/flag
     description:
index 04d5654..7990651 100644 (file)
@@ -29,7 +29,7 @@ properties:
           - PHY_TYPE_PCIE
           - PHY_TYPE_SATA
           - PHY_TYPE_SGMII
-          - PHY_TYPE_USB
+          - PHY_TYPE_USB3
       - description: The PHY instance
         minimum: 0
         maximum: 1 # for DP, SATA or USB
index 06eca66..8367a1f 100644 (file)
@@ -105,7 +105,7 @@ examples:
           reg = <0x65>;
           interrupt-parent = <&gpio1>;
           interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
-          ti,watchdog-timer = <0>;
+          ti,watchdog-timeout-ms = <0>;
           ti,sc-ocp-limit-microamp = <2000000>;
           ti,sc-ovp-limit-microvolt = <17800000>;
           monitored-battery = <&bat>;
index 0e6249d..5e172e9 100644 (file)
@@ -19,6 +19,9 @@ properties:
   clocks:
     maxItems: 1
 
+  interrupts:
+    maxItems: 1
+
   "#sound-dai-cells":
     const: 0
 
index 7f987e7..52a78a2 100644 (file)
@@ -33,6 +33,7 @@ properties:
               - rockchip,rk3328-spi
               - rockchip,rk3368-spi
               - rockchip,rk3399-spi
+              - rockchip,rk3568-spi
               - rockchip,rv1126-spi
           - const: rockchip,rk3066-spi
 
index ddada4a..4fd7b70 100644 (file)
@@ -439,11 +439,9 @@ preemption. The following substitution works on both kernels::
   spin_lock(&p->lock);
   p->count += this_cpu_read(var2);
 
-On a non-PREEMPT_RT kernel migrate_disable() maps to preempt_disable()
-which makes the above code fully equivalent. On a PREEMPT_RT kernel
 migrate_disable() ensures that the task is pinned on the current CPU which
 in turn guarantees that the per-CPU access to var1 and var2 are staying on
-the same CPU.
+the same CPU while the task remains preemptible.
 
 The migrate_disable() substitution is not valid for the following
 scenario::
@@ -456,9 +454,8 @@ scenario::
     p = this_cpu_ptr(&var1);
     p->val = func2();
 
-While correct on a non-PREEMPT_RT kernel, this breaks on PREEMPT_RT because
-here migrate_disable() does not protect against reentrancy from a
-preempting task. A correct substitution for this case is::
+This breaks because migrate_disable() does not protect against reentrancy from
+a preempting task. A correct substitution for this case is::
 
   func()
   {
index f1d5233..0a233b1 100644 (file)
@@ -440,6 +440,22 @@ NOTE: For 82599-based network connections, if you are enabling jumbo frames in
 a virtual function (VF), jumbo frames must first be enabled in the physical
 function (PF). The VF MTU setting cannot be larger than the PF MTU.
 
+NBASE-T Support
+---------------
+The ixgbe driver supports NBASE-T on some devices. However, the advertisement
+of NBASE-T speeds is suppressed by default, to accommodate broken network
+switches which cannot cope with advertised NBASE-T speeds. Use the ethtool
+command to enable advertising NBASE-T speeds on devices which support it::
+
+  ethtool -s eth? advertise 0x1800000001028
+
+On Linux systems with INTERFACES(5), this can be specified as a pre-up command
+in /etc/network/interfaces so that the interface is always brought up with
+NBASE-T support, e.g.::
+
+  iface eth? inet dhcp
+       pre-up ethtool -s eth? advertise 0x1800000001028 || true
+
 Generic Receive Offload, aka GRO
 --------------------------------
 The driver supports the in-kernel software implementation of GRO. GRO has
index b398b85..cf908d7 100644 (file)
@@ -35,6 +35,7 @@ GNU make               3.81             make --version
 binutils               2.23             ld -v
 flex                   2.5.35           flex --version
 bison                  2.0              bison --version
+pahole                 1.16             pahole --version
 util-linux             2.10o            fdformat --version
 kmod                   13               depmod -V
 e2fsprogs              1.41.4           e2fsck -V
@@ -108,6 +109,16 @@ Bison
 Since Linux 4.16, the build system generates parsers
 during build.  This requires bison 2.0 or later.
 
+pahole:
+-------
+
+Since Linux 5.2, if CONFIG_DEBUG_INFO_BTF is selected, the build system
+generates BTF (BPF Type Format) from DWARF in vmlinux, a bit later from kernel
+modules as well.  This requires pahole v1.16 or later.
+
+It is found in the 'dwarves' or 'pahole' distro packages or from
+https://fedorapeople.org/~acme/dwarves/.
+
 Perl
 ----
 
index da085d6..6b3aaed 100644 (file)
@@ -14,7 +14,8 @@ works, see Documentation/process/development-process.rst. Also, read
 Documentation/process/submit-checklist.rst
 for a list of items to check before submitting code.  If you are submitting
 a driver, also read Documentation/process/submitting-drivers.rst; for device
-tree binding patches, read Documentation/process/submitting-patches.rst.
+tree binding patches, read
+Documentation/devicetree/bindings/submitting-patches.rst.
 
 This documentation assumes that you're using ``git`` to prepare your patches.
 If you're unfamiliar with ``git``, you would be well-advised to learn how to
index 43007f2..8912b2c 100644 (file)
@@ -3066,7 +3066,7 @@ F:        Documentation/devicetree/bindings/phy/phy-ath79-usb.txt
 F:     drivers/phy/qualcomm/phy-ath79-usb.c
 
 ATHEROS ATH GENERIC UTILITIES
-M:     Kalle Valo <kvalo@codeaurora.org>
+M:     Kalle Valo <kvalo@kernel.org>
 L:     linux-wireless@vger.kernel.org
 S:     Supported
 F:     drivers/net/wireless/ath/*
@@ -3081,7 +3081,7 @@ W:        https://wireless.wiki.kernel.org/en/users/Drivers/ath5k
 F:     drivers/net/wireless/ath/ath5k/
 
 ATHEROS ATH6KL WIRELESS DRIVER
-M:     Kalle Valo <kvalo@codeaurora.org>
+M:     Kalle Valo <kvalo@kernel.org>
 L:     linux-wireless@vger.kernel.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath6kl
@@ -9329,7 +9329,6 @@ S:        Maintained
 F:     drivers/iio/pressure/dps310.c
 
 INFINIBAND SUBSYSTEM
-M:     Doug Ledford <dledford@redhat.com>
 M:     Jason Gunthorpe <jgg@nvidia.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
@@ -10280,9 +10279,9 @@ F:      lib/Kconfig.kcsan
 F:     scripts/Makefile.kcsan
 
 KDUMP
-M:     Dave Young <dyoung@redhat.com>
 M:     Baoquan He <bhe@redhat.com>
 R:     Vivek Goyal <vgoyal@redhat.com>
+R:     Dave Young <dyoung@redhat.com>
 L:     kexec@lists.infradead.org
 S:     Maintained
 W:     http://lse.sourceforge.net/kdump/
@@ -12180,8 +12179,8 @@ F:      drivers/net/ethernet/mellanox/mlx5/core/fpga/*
 F:     include/linux/mlx5/mlx5_ifc_fpga.h
 
 MELLANOX ETHERNET SWITCH DRIVERS
-M:     Jiri Pirko <jiri@nvidia.com>
 M:     Ido Schimmel <idosch@nvidia.com>
+M:     Petr Machata <petrm@nvidia.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
@@ -13249,7 +13248,7 @@ F:      include/uapi/linux/if_*
 F:     include/uapi/linux/netdevice.h
 
 NETWORKING DRIVERS (WIRELESS)
-M:     Kalle Valo <kvalo@codeaurora.org>
+M:     Kalle Valo <kvalo@kernel.org>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
 Q:     http://patchwork.kernel.org/project/linux-wireless/list/
@@ -15705,7 +15704,7 @@ T:      git git://linuxtv.org/anttip/media_tree.git
 F:     drivers/media/tuners/qt1010*
 
 QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
-M:     Kalle Valo <kvalo@codeaurora.org>
+M:     Kalle Valo <kvalo@kernel.org>
 L:     ath10k@lists.infradead.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
@@ -15713,7 +15712,7 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath10k/
 
 QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
-M:     Kalle Valo <kvalo@codeaurora.org>
+M:     Kalle Valo <kvalo@kernel.org>
 L:     ath11k@lists.infradead.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
@@ -15771,6 +15770,15 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/net/qcom,ethqos.txt
 F:     drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
 
+QUALCOMM FASTRPC DRIVER
+M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+M:     Amol Maheshwari <amahesh@qti.qualcomm.com>
+L:     linux-arm-msm@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/misc/qcom,fastrpc.txt
+F:     drivers/misc/fastrpc.c
+F:     include/uapi/misc/fastrpc.h
+
 QUALCOMM GENERIC INTERFACE I2C DRIVER
 M:     Akash Asthana <akashast@codeaurora.org>
 M:     Mukesh Savaliya <msavaliy@codeaurora.org>
@@ -15877,7 +15885,7 @@ F:      Documentation/devicetree/bindings/media/*venus*
 F:     drivers/media/platform/qcom/venus/
 
 QUALCOMM WCN36XX WIRELESS DRIVER
-M:     Kalle Valo <kvalo@codeaurora.org>
+M:     Kalle Valo <kvalo@kernel.org>
 L:     wcn36xx@lists.infradead.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/wcn36xx
@@ -16629,7 +16637,6 @@ W:      http://www.ibm.com/developerworks/linux/linux390/
 F:     drivers/iommu/s390-iommu.c
 
 S390 IUCV NETWORK LAYER
-M:     Julian Wiedmann <jwi@linux.ibm.com>
 M:     Alexandra Winter <wintera@linux.ibm.com>
 M:     Wenjia Zhang <wenjia@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
@@ -16641,7 +16648,6 @@ F:      include/net/iucv/
 F:     net/iucv/
 
 S390 NETWORK DRIVERS
-M:     Julian Wiedmann <jwi@linux.ibm.com>
 M:     Alexandra Winter <wintera@linux.ibm.com>
 M:     Wenjia Zhang <wenjia@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
@@ -21053,7 +21059,7 @@ S:      Maintained
 F:     arch/x86/kernel/cpu/zhaoxin.c
 
 ZONEFS FILESYSTEM
-M:     Damien Le Moal <damien.lemoal@wdc.com>
+M:     Damien Le Moal <damien.lemoal@opensource.wdc.com>
 M:     Naohiro Aota <naohiro.aota@wdc.com>
 R:     Johannes Thumshirn <jth@kernel.org>
 L:     linux-fsdevel@vger.kernel.org
index 8e35d78..d85f1ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 16
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc6
 NAME = Gobble Gobble
 
 # *DOCUMENTATION*
@@ -789,7 +789,7 @@ stackp-flags-$(CONFIG_STACKPROTECTOR_STRONG)      := -fstack-protector-strong
 KBUILD_CFLAGS += $(stackp-flags-y)
 
 KBUILD_CFLAGS-$(CONFIG_WERROR) += -Werror
-KBUILD_CFLAGS += $(KBUILD_CFLAGS-y) $(CONFIG_CC_IMPLICIT_FALLTHROUGH)
+KBUILD_CFLAGS += $(KBUILD_CFLAGS-y) $(CONFIG_CC_IMPLICIT_FALLTHROUGH:"%"=%)
 
 ifdef CONFIG_CC_IS_CLANG
 KBUILD_CPPFLAGS += -Qunused-arguments
@@ -1374,17 +1374,17 @@ endif
 
 ifneq ($(dtstree),)
 
-%.dtb: dt_binding_check include/config/kernel.release scripts_dtc
-       $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ $(dtstree)/$*.dt.yaml
+%.dtb: include/config/kernel.release scripts_dtc
+       $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
-%.dtbo: dt_binding_check include/config/kernel.release scripts_dtc
-       $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ $(dtstree)/$*.dt.yaml
+%.dtbo: include/config/kernel.release scripts_dtc
+       $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
 PHONY += dtbs dtbs_install dtbs_check
 dtbs: include/config/kernel.release scripts_dtc
        $(Q)$(MAKE) $(build)=$(dtstree)
 
-ifneq ($(filter dtbs_check %.dtb %.dtbo, $(MAKECMDGOALS)),)
+ifneq ($(filter dtbs_check, $(MAKECMDGOALS)),)
 export CHECK_DTBS=y
 dtbs: dt_binding_check
 endif
index 7648e8a..cf6571c 100644 (file)
                                label = "cpu";
                                ethernet = <&fec>;
                                phy-mode = "rgmii-id";
+                               rx-internal-delay-ps = <2000>;
+                               tx-internal-delay-ps = <2000>;
 
                                fixed-link {
                                        speed = <100>;
index eb025a9..7328d4e 100644 (file)
@@ -82,6 +82,6 @@
 #define MX6ULL_PAD_CSI_DATA04__ESAI_TX_FS                         0x01F4 0x0480 0x0000 0x9 0x0
 #define MX6ULL_PAD_CSI_DATA05__ESAI_TX_CLK                        0x01F8 0x0484 0x0000 0x9 0x0
 #define MX6ULL_PAD_CSI_DATA06__ESAI_TX5_RX0                       0x01FC 0x0488 0x0000 0x9 0x0
-#define MX6ULL_PAD_CSI_DATA07__ESAI_T                           0x0200 0x048C 0x0000 0x9 0x0
+#define MX6ULL_PAD_CSI_DATA07__ESAI_TX0                           0x0200 0x048C 0x0000 0x9 0x0
 
 #endif /* __DTS_IMX6ULL_PINFUNC_H */
index ff0ffb2..1ea32ff 100644 (file)
@@ -91,6 +91,8 @@
                                /* Internal port connected to eth2 */
                                ethernet = <&enet2>;
                                phy-mode = "rgmii";
+                               rx-internal-delay-ps = <0>;
+                               tx-internal-delay-ps = <0>;
                                reg = <4>;
 
                                fixed-link {
index 2b64564..2a74552 100644 (file)
@@ -12,7 +12,7 @@
        flash0: n25q00@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q00aa";
+               compatible = "micron,mt25qu02g", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <100000000>;
 
index 90e676e..1b02d46 100644 (file)
        flash: flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q256a";
+               compatible = "micron,n25q256a", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <100000000>;
 
index 6f138b2..51bb436 100644 (file)
        flash0: n25q00@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q00";
+               compatible = "micron,mt25qu02g", "jedec,spi-nor";
                reg = <0>;      /* chip select */
                spi-max-frequency = <100000000>;
 
index c155ff0..cae9ddd 100644 (file)
        flash: flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q00";
+               compatible = "micron,mt25qu02g", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <100000000>;
 
index 8d5d399..ca18b95 100644 (file)
@@ -80,7 +80,7 @@
        flash: flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q256a";
+               compatible = "micron,n25q256a", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <100000000>;
                m25p,fast-read;
index 99a7175..3f7aa7b 100644 (file)
        flash0: n25q512a@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q512a";
+               compatible = "micron,n25q512a", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <100000000>;
 
index a060718..25874e1 100644 (file)
        n25q128@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q128";
+               compatible = "micron,n25q128", "jedec,spi-nor";
                reg = <0>;              /* chip select */
                spi-max-frequency = <100000000>;
                m25p,fast-read;
        n25q00@1 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "n25q00";
+               compatible = "micron,mt25qu02g", "jedec,spi-nor";
                reg = <1>;              /* chip select */
                spi-max-frequency = <100000000>;
                m25p,fast-read;
index d608568..5ec58d0 100644 (file)
@@ -189,7 +189,7 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
        rockchip_boot_fn = __pa_symbol(secondary_startup);
 
        /* copy the trampoline to sram, that runs during startup of the core */
-       memcpy(sram_base_addr, &rockchip_secondary_trampoline, trampoline_sz);
+       memcpy_toio(sram_base_addr, &rockchip_secondary_trampoline, trampoline_sz);
        flush_cache_all();
        outer_clean_range(0, trampoline_sz);
 
index 1aa8b70..54e3910 100644 (file)
@@ -161,7 +161,6 @@ config ARCH_MEDIATEK
 
 config ARCH_MESON
        bool "Amlogic Platforms"
-       select COMMON_CLK
        help
          This enables support for the arm64 based Amlogic SoCs
          such as the s905, S905X/D, S912, A113X/D or S905X/D2
index 52ebe37..561eec2 100644 (file)
                                        type = "critical";
                                };
                        };
-               };
 
-               cpu_cooling_maps: cooling-maps {
-                       map0 {
-                               trip = <&cpu_passive>;
-                               cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                       };
+                       cpu_cooling_maps: cooling-maps {
+                               map0 {
+                                       trip = <&cpu_passive>;
+                                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
 
-                       map1 {
-                               trip = <&cpu_hot>;
-                               cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
-                                               <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               map1 {
+                                       trip = <&cpu_hot>;
+                                       cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                       <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                       <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+                                                       <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+                               };
                        };
                };
        };
index 33a80f9..02c3630 100644 (file)
@@ -60,7 +60,7 @@
 
 &port02 {
        bus-range = <3 3>;
-       ethernet0: pci@0,0 {
+       ethernet0: ethernet@0,0 {
                reg = <0x30000 0x0 0x0 0x0 0x0>;
                /* To be filled by the loader */
                local-mac-address = [00 10 18 00 00 00];
index fc8b2bb..8b61e7f 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright The Asahi Linux Contributors
  */
 
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/apple-aic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pinctrl/apple.h>
                        apple,npins = <212>;
 
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupt-parent = <&aic>;
                        interrupts = <AIC_IRQ 190 IRQ_TYPE_LEVEL_HIGH>,
                                     <AIC_IRQ 191 IRQ_TYPE_LEVEL_HIGH>,
                        apple,npins = <42>;
 
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupt-parent = <&aic>;
                        interrupts = <AIC_IRQ 268 IRQ_TYPE_LEVEL_HIGH>,
                                     <AIC_IRQ 269 IRQ_TYPE_LEVEL_HIGH>,
                        apple,npins = <23>;
 
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupt-parent = <&aic>;
                        interrupts = <AIC_IRQ 330 IRQ_TYPE_LEVEL_HIGH>,
                                     <AIC_IRQ 331 IRQ_TYPE_LEVEL_HIGH>,
                        apple,npins = <16>;
 
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupt-parent = <&aic>;
                        interrupts = <AIC_IRQ 391 IRQ_TYPE_LEVEL_HIGH>,
                                     <AIC_IRQ 392 IRQ_TYPE_LEVEL_HIGH>,
                        port00: pci@0,0 {
                                device_type = "pci";
                                reg = <0x0 0x0 0x0 0x0 0x0>;
-                               reset-gpios = <&pinctrl_ap 152 0>;
+                               reset-gpios = <&pinctrl_ap 152 GPIO_ACTIVE_LOW>;
                                max-link-speed = <2>;
 
                                #address-cells = <3>;
                        port01: pci@1,0 {
                                device_type = "pci";
                                reg = <0x800 0x0 0x0 0x0 0x0>;
-                               reset-gpios = <&pinctrl_ap 153 0>;
+                               reset-gpios = <&pinctrl_ap 153 GPIO_ACTIVE_LOW>;
                                max-link-speed = <2>;
 
                                #address-cells = <3>;
                        port02: pci@2,0 {
                                device_type = "pci";
                                reg = <0x1000 0x0 0x0 0x0 0x0>;
-                               reset-gpios = <&pinctrl_ap 33 0>;
+                               reset-gpios = <&pinctrl_ap 33 GPIO_ACTIVE_LOW>;
                                max-link-speed = <1>;
 
                                #address-cells = <3>;
index 3063851..d3f03dc 100644 (file)
@@ -38,7 +38,6 @@
                powerdn {
                        label = "External Power Down";
                        gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
-                       interrupts = <&gpio1 17 IRQ_TYPE_EDGE_FALLING>;
                        linux,code = <KEY_POWER>;
                };
 
@@ -46,7 +45,6 @@
                admin {
                        label = "ADMIN button";
                        gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
-                       interrupts = <&gpio3 8 IRQ_TYPE_EDGE_RISING>;
                        linux,code = <KEY_WPS_BUTTON>;
                };
        };
index b21be03..042c486 100644 (file)
                                reg = <2>;
                                ethernet = <&dpmac17>;
                                phy-mode = "rgmii-id";
+                               rx-internal-delay-ps = <2000>;
+                               tx-internal-delay-ps = <2000>;
 
                                fixed-link {
                                        speed = <1000>;
                                reg = <2>;
                                ethernet = <&dpmac18>;
                                phy-mode = "rgmii-id";
+                               rx-internal-delay-ps = <2000>;
+                               tx-internal-delay-ps = <2000>;
 
                                fixed-link {
                                        speed = <1000>;
index 972766b..71bf497 100644 (file)
                                                  <&clk IMX8MQ_VIDEO_PLL1>,
                                                  <&clk IMX8MQ_VIDEO_PLL1_OUT>;
                                assigned-clock-rates = <0>, <0>, <0>, <594000000>;
-                               interconnects = <&noc IMX8MQ_ICM_LCDIF &noc IMX8MQ_ICS_DRAM>;
-                               interconnect-names = "dram";
                                status = "disabled";
 
                                port@0 {
index 665b2e6..ea68209 100644 (file)
@@ -97,7 +97,7 @@
                regulator-max-microvolt = <3300000>;
                regulator-always-on;
                regulator-boot-on;
-               vim-supply = <&vcc_io>;
+               vin-supply = <&vcc_io>;
        };
 
        vdd_core: vdd-core {
index d5c7648..f1fcc6b 100644 (file)
 &sdhci {
        bus-width = <8>;
        mmc-hs400-1_8v;
-       mmc-hs400-enhanced-strobe;
        non-removable;
        status = "okay";
 };
index 63c7681..b6ac00f 100644 (file)
                clock-output-names = "xin32k", "rk808-clkout2";
                pinctrl-names = "default";
                pinctrl-0 = <&pmic_int_l>;
+               rockchip,system-power-controller;
                vcc1-supply = <&vcc5v0_sys>;
                vcc2-supply = <&vcc5v0_sys>;
                vcc3-supply = <&vcc5v0_sys>;
index 7c93f84..e890166 100644 (file)
@@ -55,7 +55,7 @@
                regulator-boot-on;
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
-               vim-supply = <&vcc3v3_sys>;
+               vin-supply = <&vcc3v3_sys>;
        };
 
        vcc3v3_sys: vcc3v3-sys {
index 98136c8..6a434be 100644 (file)
        status = "okay";
 
        bt656-supply = <&vcc_3v0>;
-       audio-supply = <&vcc_3v0>;
+       audio-supply = <&vcc1v8_codec>;
        sdmmc-supply = <&vcc_sdio>;
        gpio1830-supply = <&vcc_3v0>;
 };
index 63634b4..59c648d 100644 (file)
@@ -149,6 +149,7 @@ int load_other_segments(struct kimage *image,
                                           initrd_len, cmdline, 0);
        if (!dtb) {
                pr_err("Preparing for new dtb failed\n");
+               ret = -EINVAL;
                goto out_err;
        }
 
index e5fbf86..2020af8 100644 (file)
@@ -209,7 +209,7 @@ asmlinkage void do_trap_illinsn(struct pt_regs *regs)
 
 asmlinkage void do_trap_fpe(struct pt_regs *regs)
 {
-#ifdef CONFIG_CPU_HAS_FP
+#ifdef CONFIG_CPU_HAS_FPU
        return fpu_fpe(regs);
 #else
        do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc,
@@ -219,7 +219,7 @@ asmlinkage void do_trap_fpe(struct pt_regs *regs)
 
 asmlinkage void do_trap_priv(struct pt_regs *regs)
 {
-#ifdef CONFIG_CPU_HAS_FP
+#ifdef CONFIG_CPU_HAS_FPU
        if (user_mode(regs) && fpu_libc_helper(regs))
                return;
 #endif
index 05d14c2..f7af11e 100644 (file)
@@ -6,5 +6,7 @@
 #define PCI_IOSIZE     SZ_64K
 #define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
 
+#define pci_remap_iospace pci_remap_iospace
+
 #include <asm/mach-generic/spaces.h>
 #endif
index 421231f..9ffc819 100644 (file)
 #include <linux/list.h>
 #include <linux/of.h>
 
-#ifdef CONFIG_PCI_DRIVERS_GENERIC
-#define pci_remap_iospace pci_remap_iospace
-#endif
-
 #ifdef CONFIG_PCI_DRIVERS_LEGACY
 
 /*
index 6f3a7b0..a37fe20 100644 (file)
@@ -98,7 +98,7 @@ do {                                                          \
 #define emit(...) __emit(__VA_ARGS__)
 
 /* Workaround for R10000 ll/sc errata */
-#ifdef CONFIG_WAR_R10000
+#ifdef CONFIG_WAR_R10000_LLSC
 #define LLSC_beqz      beqzl
 #else
 #define LLSC_beqz      beqz
index 18eb8a4..d2d68ba 100644 (file)
@@ -47,6 +47,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
        pci_read_bridge_bases(bus);
 }
 
+#ifdef pci_remap_iospace
 int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
 {
        unsigned long vaddr;
@@ -60,3 +61,4 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
        set_io_port_base(vaddr);
        return 0;
 }
+#endif
index 6baa676..5d77d3f 100644 (file)
@@ -422,11 +422,17 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,
                              const char *name)
 {
        long reladdr;
+       func_desc_t desc;
+       int i;
 
        if (is_mprofile_ftrace_call(name))
                return create_ftrace_stub(entry, addr, me);
 
-       memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
+       for (i = 0; i < sizeof(ppc64_stub_insns) / sizeof(u32); i++) {
+               if (patch_instruction(&entry->jump[i],
+                                     ppc_inst(ppc64_stub_insns[i])))
+                       return 0;
+       }
 
        /* Stub uses address relative to r2. */
        reladdr = (unsigned long)entry - my_r2(sechdrs, me);
@@ -437,10 +443,24 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,
        }
        pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr);
 
-       entry->jump[0] |= PPC_HA(reladdr);
-       entry->jump[1] |= PPC_LO(reladdr);
-       entry->funcdata = func_desc(addr);
-       entry->magic = STUB_MAGIC;
+       if (patch_instruction(&entry->jump[0],
+                             ppc_inst(entry->jump[0] | PPC_HA(reladdr))))
+               return 0;
+
+       if (patch_instruction(&entry->jump[1],
+                         ppc_inst(entry->jump[1] | PPC_LO(reladdr))))
+               return 0;
+
+       // func_desc_t is 8 bytes if ABIv2, else 16 bytes
+       desc = func_desc(addr);
+       for (i = 0; i < sizeof(func_desc_t) / sizeof(u32); i++) {
+               if (patch_instruction(((u32 *)&entry->funcdata) + i,
+                                     ppc_inst(((u32 *)(&desc))[i])))
+                       return 0;
+       }
+
+       if (patch_instruction(&entry->magic, ppc_inst(STUB_MAGIC)))
+               return 0;
 
        return 1;
 }
@@ -495,8 +515,11 @@ static int restore_r2(const char *name, u32 *instruction, struct module *me)
                        me->name, *instruction, instruction);
                return 0;
        }
+
        /* ld r2,R2_STACK_OFFSET(r1) */
-       *instruction = PPC_INST_LD_TOC;
+       if (patch_instruction(instruction, ppc_inst(PPC_INST_LD_TOC)))
+               return 0;
+
        return 1;
 }
 
@@ -636,9 +659,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        }
 
                        /* Only replace bits 2 through 26 */
-                       *(uint32_t *)location
-                               = (*(uint32_t *)location & ~0x03fffffc)
+                       value = (*(uint32_t *)location & ~0x03fffffc)
                                | (value & 0x03fffffc);
+
+                       if (patch_instruction((u32 *)location, ppc_inst(value)))
+                               return -EFAULT;
+
                        break;
 
                case R_PPC64_REL64:
index 83f4a63..d7081e9 100644 (file)
@@ -220,7 +220,7 @@ static int smp_85xx_start_cpu(int cpu)
        local_irq_save(flags);
        hard_irq_disable();
 
-       if (qoriq_pm_ops)
+       if (qoriq_pm_ops && qoriq_pm_ops->cpu_up_prepare)
                qoriq_pm_ops->cpu_up_prepare(cpu);
 
        /* if cpu is not spinning, reset it */
@@ -292,7 +292,7 @@ static int smp_85xx_kick_cpu(int nr)
                booting_thread_hwid = cpu_thread_in_core(nr);
                primary = cpu_first_thread_sibling(nr);
 
-               if (qoriq_pm_ops)
+               if (qoriq_pm_ops && qoriq_pm_ops->cpu_up_prepare)
                        qoriq_pm_ops->cpu_up_prepare(nr);
 
                /*
index ba304d4..ced0d4e 100644 (file)
@@ -76,6 +76,7 @@
                spi-max-frequency = <20000000>;
                voltage-ranges = <3300 3300>;
                disable-wp;
+               gpios = <&gpio 11 GPIO_ACTIVE_LOW>;
        };
 };
 
index 4f66919..6bfa1f2 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2020 SiFive, Inc */
 
 #include "fu740-c000.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
        temperature-sensor@4c {
                compatible = "ti,tmp451";
                reg = <0x4c>;
+               vcc-supply = <&vdd_bpro>;
                interrupt-parent = <&gpio>;
                interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
        };
 
+       eeprom@54 {
+               compatible = "microchip,24c02", "atmel,24c02";
+               reg = <0x54>;
+               vcc-supply = <&vdd_bpro>;
+               label = "board-id";
+               pagesize = <16>;
+               read-only;
+               size = <256>;
+       };
+
        pmic@58 {
                compatible = "dlg,da9063";
                reg = <0x58>;
                interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
                interrupt-controller;
 
-               regulators {
-                       vdd_bcore1: bcore1 {
-                               regulator-min-microvolt = <900000>;
-                               regulator-max-microvolt = <900000>;
-                               regulator-min-microamp = <5000000>;
-                               regulator-max-microamp = <5000000>;
-                               regulator-always-on;
-                       };
+               onkey {
+                       compatible = "dlg,da9063-onkey";
+               };
 
-                       vdd_bcore2: bcore2 {
-                               regulator-min-microvolt = <900000>;
-                               regulator-max-microvolt = <900000>;
-                               regulator-min-microamp = <5000000>;
-                               regulator-max-microamp = <5000000>;
+               rtc {
+                       compatible = "dlg,da9063-rtc";
+               };
+
+               wdt {
+                       compatible = "dlg,da9063-watchdog";
+               };
+
+               regulators {
+                       vdd_bcore: bcores-merged {
+                               regulator-min-microvolt = <1050000>;
+                               regulator-max-microvolt = <1050000>;
+                               regulator-min-microamp = <4800000>;
+                               regulator-max-microamp = <4800000>;
                                regulator-always-on;
                        };
 
                        vdd_bpro: bpro {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <2500000>;
-                               regulator-max-microamp = <2500000>;
+                               regulator-min-microamp = <2400000>;
+                               regulator-max-microamp = <2400000>;
                                regulator-always-on;
                        };
 
                        vdd_bperi: bperi {
-                               regulator-min-microvolt = <1050000>;
-                               regulator-max-microvolt = <1050000>;
+                               regulator-min-microvolt = <1060000>;
+                               regulator-max-microvolt = <1060000>;
                                regulator-min-microamp = <1500000>;
                                regulator-max-microamp = <1500000>;
                                regulator-always-on;
                        };
 
-                       vdd_bmem: bmem {
-                               regulator-min-microvolt = <1200000>;
-                               regulator-max-microvolt = <1200000>;
-                               regulator-min-microamp = <3000000>;
-                               regulator-max-microamp = <3000000>;
-                               regulator-always-on;
-                       };
-
-                       vdd_bio: bio {
+                       vdd_bmem_bio: bmem-bio-merged {
                                regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1200000>;
                                regulator-min-microamp = <3000000>;
                        vdd_ldo1: ldo1 {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <100000>;
-                               regulator-max-microamp = <100000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo2: ldo2 {
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo3: ldo3 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo4: ldo4 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
+                               regulator-min-microvolt = <2500000>;
+                               regulator-max-microvolt = <2500000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo5: ldo5 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <100000>;
-                               regulator-max-microamp = <100000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo6: ldo6 {
-                               regulator-min-microvolt = <3300000>;
-                               regulator-max-microvolt = <3300000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo7: ldo7 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
                        vdd_ldo8: ldo8 {
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
 
                        vdd_ld09: ldo9 {
                                regulator-min-microvolt = <1050000>;
                                regulator-max-microvolt = <1050000>;
-                               regulator-min-microamp = <200000>;
-                               regulator-max-microamp = <200000>;
+                               regulator-always-on;
                        };
 
                        vdd_ldo10: ldo10 {
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <1000000>;
-                               regulator-min-microamp = <300000>;
-                               regulator-max-microamp = <300000>;
+                               regulator-always-on;
                        };
 
                        vdd_ldo11: ldo11 {
                                regulator-min-microvolt = <2500000>;
                                regulator-max-microvolt = <2500000>;
-                               regulator-min-microamp = <300000>;
-                               regulator-max-microamp = <300000>;
                                regulator-always-on;
                        };
                };
                spi-max-frequency = <20000000>;
                voltage-ranges = <3300 3300>;
                disable-wp;
+               gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
        };
 };
 
 
 &gpio {
        status = "okay";
+       gpio-line-names = "J29.1", "PMICNTB", "PMICSHDN", "J8.1", "J8.3",
+               "PCIe_PWREN", "THERM", "UBRDG_RSTN", "PCIe_PERSTN",
+               "ULPI_RSTN", "J8.2", "UHUB_RSTN", "GEMGXL_RST", "J8.4",
+               "EN_VDD_SD", "SD_CD";
 };
index b626bc6..e45cc27 100644 (file)
@@ -117,6 +117,7 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
+CONFIG_NET_SWITCHDEV=y
 CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
@@ -511,6 +512,7 @@ CONFIG_NLMON=m
 CONFIG_MLX4_EN=m
 CONFIG_MLX5_CORE=m
 CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
index 0056cab..1c750bf 100644 (file)
@@ -109,6 +109,7 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
+CONFIG_NET_SWITCHDEV=y
 CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
@@ -502,6 +503,7 @@ CONFIG_NLMON=m
 CONFIG_MLX4_EN=m
 CONFIG_MLX5_CORE=m
 CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
index 5510c7d..21d62d8 100644 (file)
@@ -290,7 +290,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                return;
 
        regs = ftrace_get_regs(fregs);
-       preempt_disable_notrace();
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (unlikely(!p) || kprobe_disabled(p))
                goto out;
@@ -318,7 +317,6 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
        }
        __this_cpu_write(current_kprobe, NULL);
 out:
-       preempt_enable_notrace();
        ftrace_test_recursion_unlock(bit);
 }
 NOKPROBE_SYMBOL(kprobe_ftrace_handler);
index 0df83ec..cb70996 100644 (file)
@@ -138,7 +138,7 @@ void noinstr do_io_irq(struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
        int from_idle;
 
-       irq_enter();
+       irq_enter_rcu();
 
        if (user_mode(regs)) {
                update_timer_sys();
@@ -158,7 +158,8 @@ void noinstr do_io_irq(struct pt_regs *regs)
                        do_irq_async(regs, IO_INTERRUPT);
        } while (MACHINE_IS_LPAR && irq_pending(regs));
 
-       irq_exit();
+       irq_exit_rcu();
+
        set_irq_regs(old_regs);
        irqentry_exit(regs, state);
 
@@ -172,7 +173,7 @@ void noinstr do_ext_irq(struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
        int from_idle;
 
-       irq_enter();
+       irq_enter_rcu();
 
        if (user_mode(regs)) {
                update_timer_sys();
@@ -190,7 +191,7 @@ void noinstr do_ext_irq(struct pt_regs *regs)
 
        do_irq_async(regs, EXT_INTERRUPT);
 
-       irq_exit();
+       irq_exit_rcu();
        set_irq_regs(old_regs);
        irqentry_exit(regs, state);
 
index 9975ad2..8f43575 100644 (file)
@@ -7,6 +7,8 @@
  * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
  */
 
+#define pr_fmt(fmt)    "kexec: " fmt
+
 #include <linux/elf.h>
 #include <linux/errno.h>
 #include <linux/kexec.h>
@@ -290,8 +292,16 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                                     const Elf_Shdr *relsec,
                                     const Elf_Shdr *symtab)
 {
+       const char *strtab, *name, *shstrtab;
+       const Elf_Shdr *sechdrs;
        Elf_Rela *relas;
        int i, r_type;
+       int ret;
+
+       /* String & section header string table */
+       sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
+       strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset;
+       shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset;
 
        relas = (void *)pi->ehdr + relsec->sh_offset;
 
@@ -304,15 +314,27 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                sym = (void *)pi->ehdr + symtab->sh_offset;
                sym += ELF64_R_SYM(relas[i].r_info);
 
-               if (sym->st_shndx == SHN_UNDEF)
+               if (sym->st_name)
+                       name = strtab + sym->st_name;
+               else
+                       name = shstrtab + sechdrs[sym->st_shndx].sh_name;
+
+               if (sym->st_shndx == SHN_UNDEF) {
+                       pr_err("Undefined symbol: %s\n", name);
                        return -ENOEXEC;
+               }
 
-               if (sym->st_shndx == SHN_COMMON)
+               if (sym->st_shndx == SHN_COMMON) {
+                       pr_err("symbol '%s' in common section\n", name);
                        return -ENOEXEC;
+               }
 
                if (sym->st_shndx >= pi->ehdr->e_shnum &&
-                   sym->st_shndx != SHN_ABS)
+                   sym->st_shndx != SHN_ABS) {
+                       pr_err("Invalid section %d for symbol %s\n",
+                              sym->st_shndx, name);
                        return -ENOEXEC;
+               }
 
                loc = pi->purgatory_buf;
                loc += section->sh_offset;
@@ -326,7 +348,15 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                addr = section->sh_addr + relas[i].r_offset;
 
                r_type = ELF64_R_TYPE(relas[i].r_info);
-               arch_kexec_do_relocs(r_type, loc, val, addr);
+
+               if (r_type == R_390_PLT32DBL)
+                       r_type = R_390_PC32DBL;
+
+               ret = arch_kexec_do_relocs(r_type, loc, val, addr);
+               if (ret) {
+                       pr_err("Unknown rela relocation: %d\n", r_type);
+                       return -ENOEXEC;
+               }
        }
        return 0;
 }
index 7399327..5c2ccb8 100644 (file)
@@ -1932,6 +1932,7 @@ config EFI
        depends on ACPI
        select UCS2_STRING
        select EFI_RUNTIME_WRAPPERS
+       select ARCH_USE_MEMREMAP_PROT
        help
          This enables the kernel to use EFI runtime services that are
          available (such as the EFI variable services).
index 860ed50..2164b9f 100644 (file)
@@ -97,7 +97,7 @@
        KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_TLB_FLUSH_CURRENT      KVM_ARCH_REQ(26)
 #define KVM_REQ_TLB_FLUSH_GUEST \
-       KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_NO_WAKEUP)
+       KVM_ARCH_REQ_FLAGS(27, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_APF_READY              KVM_ARCH_REQ(28)
 #define KVM_REQ_MSR_FILTER_CHANGED     KVM_ARCH_REQ(29)
 #define KVM_REQ_UPDATE_CPU_DIRTY_LOGGING \
index ac2909f..617012f 100644 (file)
@@ -579,6 +579,17 @@ static struct sched_domain_topology_level x86_numa_in_package_topology[] = {
        { NULL, },
 };
 
+static struct sched_domain_topology_level x86_hybrid_topology[] = {
+#ifdef CONFIG_SCHED_SMT
+       { cpu_smt_mask, x86_smt_flags, SD_INIT_NAME(SMT) },
+#endif
+#ifdef CONFIG_SCHED_MC
+       { cpu_coregroup_mask, x86_core_flags, SD_INIT_NAME(MC) },
+#endif
+       { cpu_cpu_mask, SD_INIT_NAME(DIE) },
+       { NULL, },
+};
+
 static struct sched_domain_topology_level x86_topology[] = {
 #ifdef CONFIG_SCHED_SMT
        { cpu_smt_mask, x86_smt_flags, SD_INIT_NAME(SMT) },
@@ -1469,8 +1480,11 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
 
        calculate_max_logical_packages();
 
+       /* XXX for now assume numa-in-package and hybrid don't overlap */
        if (x86_has_numa_in_package)
                set_sched_topology(x86_numa_in_package_topology);
+       if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU))
+               set_sched_topology(x86_hybrid_topology);
 
        nmi_selftest();
        impress_friends();
index 5e19e6e..8d8c1cc 100644 (file)
@@ -1922,11 +1922,13 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
 
                all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL;
 
+               if (all_cpus)
+                       goto check_and_send_ipi;
+
                if (!sparse_banks_len)
                        goto ret_success;
 
-               if (!all_cpus &&
-                   kvm_read_guest(kvm,
+               if (kvm_read_guest(kvm,
                                   hc->ingpa + offsetof(struct hv_send_ipi_ex,
                                                        vp_set.bank_contents),
                                   sparse_banks,
@@ -1934,6 +1936,7 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
                        return HV_STATUS_INVALID_HYPERCALL_INPUT;
        }
 
+check_and_send_ipi:
        if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
                return HV_STATUS_INVALID_HYPERCALL_INPUT;
 
index e2e1d01..fcdf3f8 100644 (file)
@@ -3987,7 +3987,21 @@ out_retry:
 static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
                                struct kvm_page_fault *fault, int mmu_seq)
 {
-       if (is_obsolete_sp(vcpu->kvm, to_shadow_page(vcpu->arch.mmu->root_hpa)))
+       struct kvm_mmu_page *sp = to_shadow_page(vcpu->arch.mmu->root_hpa);
+
+       /* Special roots, e.g. pae_root, are not backed by shadow pages. */
+       if (sp && is_obsolete_sp(vcpu->kvm, sp))
+               return true;
+
+       /*
+        * Roots without an associated shadow page are considered invalid if
+        * there is a pending request to free obsolete roots.  The request is
+        * only a hint that the current root _may_ be obsolete and needs to be
+        * reloaded, e.g. if the guest frees a PGD that KVM is tracking as a
+        * previous root, then __kvm_mmu_prepare_zap_page() signals all vCPUs
+        * to reload even if no vCPU is actively using the root.
+        */
+       if (!sp && kvm_test_request(KVM_REQ_MMU_RELOAD, vcpu))
                return true;
 
        return fault->slot &&
index 9453743..5aadad3 100644 (file)
@@ -2646,15 +2646,6 @@ int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
                if (!loaded_vmcs->msr_bitmap)
                        goto out_vmcs;
                memset(loaded_vmcs->msr_bitmap, 0xff, PAGE_SIZE);
-
-               if (IS_ENABLED(CONFIG_HYPERV) &&
-                   static_branch_unlikely(&enable_evmcs) &&
-                   (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)) {
-                       struct hv_enlightened_vmcs *evmcs =
-                               (struct hv_enlightened_vmcs *)loaded_vmcs->vmcs;
-
-                       evmcs->hv_enlightenments_control.msr_bitmap = 1;
-               }
        }
 
        memset(&loaded_vmcs->host_state, 0, sizeof(struct vmcs_host_state));
@@ -6842,6 +6833,19 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
        if (err < 0)
                goto free_pml;
 
+       /*
+        * Use Hyper-V 'Enlightened MSR Bitmap' feature when KVM runs as a
+        * nested (L1) hypervisor and Hyper-V in L0 supports it. Enable the
+        * feature only for vmcs01, KVM currently isn't equipped to realize any
+        * performance benefits from enabling it for vmcs02.
+        */
+       if (IS_ENABLED(CONFIG_HYPERV) && static_branch_unlikely(&enable_evmcs) &&
+           (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)) {
+               struct hv_enlightened_vmcs *evmcs = (void *)vmx->vmcs01.vmcs;
+
+               evmcs->hv_enlightenments_control.msr_bitmap = 1;
+       }
+
        /* The MSR bitmap starts with all ones */
        bitmap_fill(vmx->shadow_msr_intercept.read, MAX_POSSIBLE_PASSTHROUGH_MSRS);
        bitmap_fill(vmx->shadow_msr_intercept.write, MAX_POSSIBLE_PASSTHROUGH_MSRS);
index e0aa4dd..9a2972f 100644 (file)
@@ -890,7 +890,8 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
            !load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu)))
                return 1;
 
-       if (!(cr0 & X86_CR0_PG) && kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE))
+       if (!(cr0 & X86_CR0_PG) &&
+           (is_64_bit_mode(vcpu) || kvm_read_cr4_bits(vcpu, X86_CR4_PCIDE)))
                return 1;
 
        static_call(kvm_x86_set_cr0)(vcpu, cr0);
@@ -3412,7 +3413,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
                if (!msr_info->host_initiated)
                        return 1;
-               if (guest_cpuid_has(vcpu, X86_FEATURE_PDCM) && kvm_get_msr_feature(&msr_ent))
+               if (kvm_get_msr_feature(&msr_ent))
                        return 1;
                if (data & ~msr_ent.data)
                        return 1;
@@ -7121,7 +7122,13 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size,
                           unsigned short port, void *val, unsigned int count)
 {
        if (vcpu->arch.pio.count) {
-               /* Complete previous iteration.  */
+               /*
+                * Complete a previous iteration that required userspace I/O.
+                * Note, @count isn't guaranteed to match pio.count as userspace
+                * can modify ECX before rerunning the vCPU.  Ignore any such
+                * shenanigans as KVM doesn't support modifying the rep count,
+                * and the emulator ensures @count doesn't overflow the buffer.
+                */
        } else {
                int r = __emulator_pio_in(vcpu, size, port, count);
                if (!r)
@@ -7130,7 +7137,6 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size,
                /* Results already available, fall through.  */
        }
 
-       WARN_ON(count != vcpu->arch.pio.count);
        complete_emulator_pio_in(vcpu, val);
        return 1;
 }
index 3609822..96d34eb 100644 (file)
@@ -981,7 +981,7 @@ static void __meminit free_pagetable(struct page *page, int order)
        if (PageReserved(page)) {
                __ClearPageReserved(page);
 
-               magic = (unsigned long)page->freelist;
+               magic = page->index;
                if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
                        while (nr_pages--)
                                put_page_bootmem(page++);
index 726700f..bafe36e 100644 (file)
@@ -1252,19 +1252,54 @@ st:                     if (is_imm8(insn->off))
                case BPF_LDX | BPF_MEM | BPF_DW:
                case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
                        if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
-                               /* test src_reg, src_reg */
-                               maybe_emit_mod(&prog, src_reg, src_reg, true); /* always 1 byte */
-                               EMIT2(0x85, add_2reg(0xC0, src_reg, src_reg));
-                               /* jne start_of_ldx */
-                               EMIT2(X86_JNE, 0);
+                               /* Though the verifier prevents negative insn->off in BPF_PROBE_MEM
+                                * add abs(insn->off) to the limit to make sure that negative
+                                * offset won't be an issue.
+                                * insn->off is s16, so it won't affect valid pointers.
+                                */
+                               u64 limit = TASK_SIZE_MAX + PAGE_SIZE + abs(insn->off);
+                               u8 *end_of_jmp1, *end_of_jmp2;
+
+                               /* Conservatively check that src_reg + insn->off is a kernel address:
+                                * 1. src_reg + insn->off >= limit
+                                * 2. src_reg + insn->off doesn't become small positive.
+                                * Cannot do src_reg + insn->off >= limit in one branch,
+                                * since it needs two spare registers, but JIT has only one.
+                                */
+
+                               /* movabsq r11, limit */
+                               EMIT2(add_1mod(0x48, AUX_REG), add_1reg(0xB8, AUX_REG));
+                               EMIT((u32)limit, 4);
+                               EMIT(limit >> 32, 4);
+                               /* cmp src_reg, r11 */
+                               maybe_emit_mod(&prog, src_reg, AUX_REG, true);
+                               EMIT2(0x39, add_2reg(0xC0, src_reg, AUX_REG));
+                               /* if unsigned '<' goto end_of_jmp2 */
+                               EMIT2(X86_JB, 0);
+                               end_of_jmp1 = prog;
+
+                               /* mov r11, src_reg */
+                               emit_mov_reg(&prog, true, AUX_REG, src_reg);
+                               /* add r11, insn->off */
+                               maybe_emit_1mod(&prog, AUX_REG, true);
+                               EMIT2_off32(0x81, add_1reg(0xC0, AUX_REG), insn->off);
+                               /* jmp if not carry to start_of_ldx
+                                * Otherwise ERR_PTR(-EINVAL) + 128 will be the user addr
+                                * that has to be rejected.
+                                */
+                               EMIT2(0x73 /* JNC */, 0);
+                               end_of_jmp2 = prog;
+
                                /* xor dst_reg, dst_reg */
                                emit_mov_imm32(&prog, false, dst_reg, 0);
                                /* jmp byte_after_ldx */
                                EMIT2(0xEB, 0);
 
-                               /* populate jmp_offset for JNE above */
-                               temp[4] = prog - temp - 5 /* sizeof(test + jne) */;
+                               /* populate jmp_offset for JB above to jump to xor dst_reg */
+                               end_of_jmp1[-1] = end_of_jmp2 - end_of_jmp1;
+                               /* populate jmp_offset for JNC above to jump to start_of_ldx */
                                start_of_ldx = prog;
+                               end_of_jmp2[-1] = start_of_ldx - end_of_jmp2;
                        }
                        emit_ldx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
                        if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
@@ -1305,7 +1340,7 @@ st:                       if (is_imm8(insn->off))
                                 * End result: x86 insn "mov rbx, qword ptr [rax+0x14]"
                                 * of 4 bytes will be ignored and rbx will be zero inited.
                                 */
-                               ex->fixup = (prog - temp) | (reg2pt_regs[dst_reg] << 8);
+                               ex->fixup = (prog - start_of_ldx) | (reg2pt_regs[dst_reg] << 8);
                        }
                        break;
 
index b15ebfe..b0b848d 100644 (file)
@@ -277,7 +277,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
                return;
        }
 
-       new = early_memremap(data.phys_map, data.size);
+       new = early_memremap_prot(data.phys_map, data.size,
+                                 pgprot_val(pgprot_encrypted(FIXMAP_PAGE_NORMAL)));
        if (!new) {
                pr_err("Failed to map new boot services memmap\n");
                return;
index a5b37cc..769b643 100644 (file)
@@ -2311,7 +2311,14 @@ static void ioc_timer_fn(struct timer_list *timer)
                        hwm = current_hweight_max(iocg);
                        new_hwi = hweight_after_donation(iocg, old_hwi, hwm,
                                                         usage, &now);
-                       if (new_hwi < hwm) {
+                       /*
+                        * Donation calculation assumes hweight_after_donation
+                        * to be positive, a condition that a donor w/ hwa < 2
+                        * can't meet. Don't bother with donation if hwa is
+                        * below 2. It's not gonna make a meaningful difference
+                        * anyway.
+                        */
+                       if (new_hwi < hwm && hwa >= 2) {
                                iocg->hweight_donating = hwa;
                                iocg->hweight_after_donation = new_hwi;
                                list_add(&iocg->surplus_list, &surpluses);
index ad732a3..0da147e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/falloc.h>
 #include <linux/suspend.h>
 #include <linux/fs.h>
+#include <linux/module.h>
 #include "blk.h"
 
 static inline struct inode *bdev_file_inode(struct file *file)
@@ -340,8 +341,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
        } else {
                ret = bio_iov_iter_get_pages(bio, iter);
                if (unlikely(ret)) {
-                       bio->bi_status = BLK_STS_IOERR;
-                       bio_endio(bio);
+                       bio_put(bio);
                        return ret;
                }
        }
index 313c14a..6f01d35 100644 (file)
@@ -220,6 +220,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
                                pgrp = task_pgrp(current);
                        else
                                pgrp = find_vpid(who);
+                       read_lock(&tasklist_lock);
                        do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
                                tmpio = get_task_ioprio(p);
                                if (tmpio < 0)
@@ -229,6 +230,8 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
                                else
                                        ret = ioprio_best(ret, tmpio);
                        } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
+                       read_unlock(&tasklist_lock);
+
                        break;
                case IOPRIO_WHO_USER:
                        uid = make_kuid(current_user_ns(), who);
index be5d40a..a110338 100644 (file)
@@ -41,8 +41,7 @@ obj-$(CONFIG_DMADEVICES)      += dma/
 # SOC specific infrastructure drivers.
 obj-y                          += soc/
 
-obj-$(CONFIG_VIRTIO)           += virtio/
-obj-$(CONFIG_VIRTIO_PCI_LIB)   += virtio/
+obj-y                          += virtio/
 obj-$(CONFIG_VDPA)             += vdpa/
 obj-$(CONFIG_XEN)              += xen/
 
index cffbe57..c75fb60 100644 (file)
@@ -4422,23 +4422,20 @@ static int binder_thread_release(struct binder_proc *proc,
        __release(&t->lock);
 
        /*
-        * If this thread used poll, make sure we remove the waitqueue
-        * from any epoll data structures holding it with POLLFREE.
-        * waitqueue_active() is safe to use here because we're holding
-        * the inner lock.
+        * If this thread used poll, make sure we remove the waitqueue from any
+        * poll data structures holding it.
         */
-       if ((thread->looper & BINDER_LOOPER_STATE_POLL) &&
-           waitqueue_active(&thread->wait)) {
-               wake_up_poll(&thread->wait, EPOLLHUP | POLLFREE);
-       }
+       if (thread->looper & BINDER_LOOPER_STATE_POLL)
+               wake_up_pollfree(&thread->wait);
 
        binder_inner_proc_unlock(thread->proc);
 
        /*
-        * This is needed to avoid races between wake_up_poll() above and
-        * and ep_remove_waitqueue() called for other reasons (eg the epoll file
-        * descriptor being closed); ep_remove_waitqueue() holds an RCU read
-        * lock, so we can be sure it's done after calling synchronize_rcu().
+        * This is needed to avoid races between wake_up_pollfree() above and
+        * someone else removing the last entry from the queue for other reasons
+        * (e.g. ep_remove_wait_queue() being called due to an epoll file
+        * descriptor being closed).  Such other users hold an RCU read lock, so
+        * we can be sure they're done after we call synchronize_rcu().
         */
        if (thread->looper & BINDER_LOOPER_STATE_POLL)
                synchronize_rcu();
index 50b56cd..e9c7c07 100644 (file)
@@ -94,6 +94,7 @@ struct ceva_ahci_priv {
 static unsigned int ceva_ahci_read_id(struct ata_device *dev,
                                        struct ata_taskfile *tf, u16 *id)
 {
+       __le16 *__id = (__le16 *)id;
        u32 err_mask;
 
        err_mask = ata_do_dev_read_id(dev, tf, id);
@@ -103,7 +104,7 @@ static unsigned int ceva_ahci_read_id(struct ata_device *dev,
         * Since CEVA controller does not support device sleep feature, we
         * need to clear DEVSLP (bit 8) in word78 of the IDENTIFY DEVICE data.
         */
-       id[ATA_ID_FEATURE_SUPP] &= cpu_to_le16(~(1 << 8));
+       __id[ATA_ID_FEATURE_SUPP] &= cpu_to_le16(~(1 << 8));
 
        return 0;
 }
index 59ad8c9..aba0c67 100644 (file)
@@ -3920,6 +3920,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "VRFDFC22048UCHC-TE*", NULL,          ATA_HORKAGE_NODMA },
        /* Odd clown on sil3726/4726 PMPs */
        { "Config  Disk",       NULL,           ATA_HORKAGE_DISABLE },
+       /* Similar story with ASMedia 1092 */
+       { "ASMT109x- Config",   NULL,           ATA_HORKAGE_DISABLE },
 
        /* Weird ATAPI devices */
        { "TORiSAN DVD-ROM DRD-N216", NULL,     ATA_HORKAGE_MAX_SEC_128 },
index 1b84d55..313e947 100644 (file)
@@ -2859,8 +2859,19 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
                goto invalid_fld;
        }
 
-       if (ata_is_ncq(tf->protocol) && (cdb[2 + cdb_offset] & 0x3) == 0)
-               tf->protocol = ATA_PROT_NCQ_NODATA;
+       if ((cdb[2 + cdb_offset] & 0x3) == 0) {
+               /*
+                * When T_LENGTH is zero (No data is transferred), dir should
+                * be DMA_NONE.
+                */
+               if (scmd->sc_data_direction != DMA_NONE) {
+                       fp = 2 + cdb_offset;
+                       goto invalid_fld;
+               }
+
+               if (ata_is_ncq(tf->protocol))
+                       tf->protocol = ATA_PROT_NCQ_NODATA;
+       }
 
        /* enable LBA */
        tf->flags |= ATA_TFLAG_LBA;
index fb99e37..547e6e7 100644 (file)
@@ -881,7 +881,7 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl)
 }
 EXPORT_SYMBOL_GPL(mhi_pm_suspend);
 
-int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
+static int __mhi_pm_resume(struct mhi_controller *mhi_cntrl, bool force)
 {
        struct mhi_chan *itr, *tmp;
        struct device *dev = &mhi_cntrl->mhi_dev->dev;
@@ -898,8 +898,12 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
        if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
                return -EIO;
 
-       if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3)
-               return -EINVAL;
+       if (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_M3) {
+               dev_warn(dev, "Resuming from non M3 state (%s)\n",
+                        TO_MHI_STATE_STR(mhi_get_mhi_state(mhi_cntrl)));
+               if (!force)
+                       return -EINVAL;
+       }
 
        /* Notify clients about exiting LPM */
        list_for_each_entry_safe(itr, tmp, &mhi_cntrl->lpm_chans, node) {
@@ -940,8 +944,19 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
 
        return 0;
 }
+
+int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
+{
+       return __mhi_pm_resume(mhi_cntrl, false);
+}
 EXPORT_SYMBOL_GPL(mhi_pm_resume);
 
+int mhi_pm_resume_force(struct mhi_controller *mhi_cntrl)
+{
+       return __mhi_pm_resume(mhi_cntrl, true);
+}
+EXPORT_SYMBOL_GPL(mhi_pm_resume_force);
+
 int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl)
 {
        int ret;
index 59a4896..4c577a7 100644 (file)
@@ -20,7 +20,7 @@
 
 #define MHI_PCI_DEFAULT_BAR_NUM 0
 
-#define MHI_POST_RESET_DELAY_MS 500
+#define MHI_POST_RESET_DELAY_MS 2000
 
 #define HEALTH_CHECK_PERIOD (HZ * 2)
 
index f467d63..566ee2c 100644 (file)
@@ -3418,6 +3418,14 @@ static int __clk_core_init(struct clk_core *core)
 
        clk_prepare_lock();
 
+       /*
+        * Set hw->core after grabbing the prepare_lock to synchronize with
+        * callers of clk_core_fill_parent_index() where we treat hw->core
+        * being NULL as the clk not being registered yet. This is crucial so
+        * that clks aren't parented until their parent is fully registered.
+        */
+       core->hw->core = core;
+
        ret = clk_pm_runtime_get(core);
        if (ret)
                goto unlock;
@@ -3582,8 +3590,10 @@ static int __clk_core_init(struct clk_core *core)
 out:
        clk_pm_runtime_put(core);
 unlock:
-       if (ret)
+       if (ret) {
                hlist_del_init(&core->child_node);
+               core->hw->core = NULL;
+       }
 
        clk_prepare_unlock();
 
@@ -3847,7 +3857,6 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
        core->num_parents = init->num_parents;
        core->min_rate = 0;
        core->max_rate = ULONG_MAX;
-       hw->core = core;
 
        ret = clk_core_populate_parent_map(core, init);
        if (ret)
@@ -3865,7 +3874,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
                goto fail_create_clk;
        }
 
-       clk_core_link_consumer(hw->core, hw->clk);
+       clk_core_link_consumer(core, hw->clk);
 
        ret = __clk_core_init(core);
        if (!ret)
index d3e905c..b237580 100644 (file)
@@ -370,7 +370,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = {
        .probe = imx8qxp_lpcg_clk_probe,
 };
 
-builtin_platform_driver(imx8qxp_lpcg_clk_driver);
+module_platform_driver(imx8qxp_lpcg_clk_driver);
 
 MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
 MODULE_DESCRIPTION("NXP i.MX8QXP LPCG clock driver");
index c53a688..40a2efb 100644 (file)
@@ -308,7 +308,7 @@ static struct platform_driver imx8qxp_clk_driver = {
        },
        .probe = imx8qxp_clk_probe,
 };
-builtin_platform_driver(imx8qxp_clk_driver);
+module_platform_driver(imx8qxp_clk_driver);
 
 MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
 MODULE_DESCRIPTION("NXP i.MX8QXP clock driver");
index eaedcce..8f65b9b 100644 (file)
@@ -1429,6 +1429,15 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_fabia_ops);
 void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
                             const struct alpha_pll_config *config)
 {
+       /*
+        * If the bootloader left the PLL enabled it's likely that there are
+        * RCGs that will lock up if we disable the PLL below.
+        */
+       if (trion_pll_is_enabled(pll, regmap)) {
+               pr_debug("Trion PLL is already enabled, skipping configuration\n");
+               return;
+       }
+
        clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l);
        regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL);
        clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
index b2d00b4..45d9cca 100644 (file)
@@ -28,7 +28,7 @@ static u8 mux_get_parent(struct clk_hw *hw)
        val &= mask;
 
        if (mux->parent_map)
-               return qcom_find_src_index(hw, mux->parent_map, val);
+               return qcom_find_cfg_index(hw, mux->parent_map, val);
 
        return val;
 }
index 0932e01..75f09e6 100644 (file)
@@ -69,6 +69,18 @@ int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
 }
 EXPORT_SYMBOL_GPL(qcom_find_src_index);
 
+int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map, u8 cfg)
+{
+       int i, num_parents = clk_hw_get_num_parents(hw);
+
+       for (i = 0; i < num_parents; i++)
+               if (cfg == map[i].cfg)
+                       return i;
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(qcom_find_cfg_index);
+
 struct regmap *
 qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc)
 {
index bb39a7e..9c8f7b7 100644 (file)
@@ -49,6 +49,8 @@ extern void
 qcom_pll_set_fsm_mode(struct regmap *m, u32 reg, u8 bias_count, u8 lock_count);
 extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
                               u8 src);
+extern int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map,
+                              u8 cfg);
 
 extern int qcom_cc_register_board_clk(struct device *dev, const char *path,
                                      const char *name, unsigned long rate);
index 543cfab..431b55b 100644 (file)
@@ -1121,7 +1121,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
                .name = "gcc_sdcc1_apps_clk_src",
                .parent_data = gcc_parent_data_1,
                .num_parents = ARRAY_SIZE(gcc_parent_data_1),
-               .ops = &clk_rcg2_ops,
+               .ops = &clk_rcg2_floor_ops,
        },
 };
 
@@ -1143,7 +1143,7 @@ static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
                .name = "gcc_sdcc1_ice_core_clk_src",
                .parent_data = gcc_parent_data_0,
                .num_parents = ARRAY_SIZE(gcc_parent_data_0),
-               .ops = &clk_rcg2_floor_ops,
+               .ops = &clk_rcg2_ops,
        },
 };
 
index d52f976..d5cb372 100644 (file)
@@ -543,8 +543,8 @@ static void __init of_syscon_icst_setup(struct device_node *np)
 
        regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map, ctype);
        if (IS_ERR(regclk)) {
-               kfree(name);
                pr_err("error setting up syscon ICST clock %s\n", name);
+               kfree(name);
                return;
        }
        of_clk_add_provider(np, of_clk_src_simple_get, regclk);
index 9a04eac..1ecd52f 100644 (file)
@@ -394,8 +394,13 @@ EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround);
 
 static atomic_t timer_unstable_counter_workaround_in_use = ATOMIC_INIT(0);
 
-static void erratum_set_next_event_generic(const int access, unsigned long evt,
-                                               struct clock_event_device *clk)
+/*
+ * Force the inlining of this function so that the register accesses
+ * can be themselves correctly inlined.
+ */
+static __always_inline
+void erratum_set_next_event_generic(const int access, unsigned long evt,
+                                   struct clock_event_device *clk)
 {
        unsigned long ctrl;
        u64 cval;
index 3819ef5..3245eb0 100644 (file)
@@ -47,7 +47,7 @@ static int __init timer_get_base_and_rate(struct device_node *np,
                        pr_warn("pclk for %pOFn is present, but could not be activated\n",
                                np);
 
-       if (!of_property_read_u32(np, "clock-freq", rate) &&
+       if (!of_property_read_u32(np, "clock-freq", rate) ||
            !of_property_read_u32(np, "clock-frequency", rate))
                return 0;
 
index cd0d745..33baf15 100644 (file)
@@ -373,7 +373,7 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
                                      struct axi_dma_desc *first)
 {
        u32 priority = chan->chip->dw->hdata->priority[chan->id];
-       struct axi_dma_chan_config config;
+       struct axi_dma_chan_config config = {};
        u32 irq_mask;
        u8 lms = 0; /* Select AXI0 master for LLI fetching */
 
@@ -391,7 +391,7 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
        config.tt_fc = DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC;
        config.prior = priority;
        config.hs_sel_dst = DWAXIDMAC_HS_SEL_HW;
-       config.hs_sel_dst = DWAXIDMAC_HS_SEL_HW;
+       config.hs_sel_src = DWAXIDMAC_HS_SEL_HW;
        switch (chan->direction) {
        case DMA_MEM_TO_DEV:
                dw_axi_dma_set_byte_halfword(chan, true);
index 198f6cd..cee7aa2 100644 (file)
@@ -187,17 +187,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
        /* DMA configuration */
        err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (!err) {
+       if (err) {
                pci_err(pdev, "DMA mask 64 set failed\n");
                return err;
-       } else {
-               pci_err(pdev, "DMA mask 64 set failed\n");
-
-               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-               if (err) {
-                       pci_err(pdev, "DMA mask 32 set failed\n");
-                       return err;
-               }
        }
 
        /* Data structure allocation */
index 17f2f8a..cf2c8bc 100644 (file)
@@ -137,10 +137,10 @@ halt:
                        INIT_WORK(&idxd->work, idxd_device_reinit);
                        queue_work(idxd->wq, &idxd->work);
                } else {
-                       spin_lock(&idxd->dev_lock);
                        idxd->state = IDXD_DEV_HALTED;
                        idxd_wqs_quiesce(idxd);
                        idxd_wqs_unmap_portal(idxd);
+                       spin_lock(&idxd->dev_lock);
                        idxd_device_clear_state(idxd);
                        dev_err(&idxd->pdev->dev,
                                "idxd halted, need %s.\n",
index de76fb4..83452fb 100644 (file)
@@ -106,6 +106,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
 {
        struct idxd_desc *d, *t, *found = NULL;
        struct llist_node *head;
+       LIST_HEAD(flist);
 
        desc->completion->status = IDXD_COMP_DESC_ABORT;
        /*
@@ -120,7 +121,11 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
                                found = desc;
                                continue;
                        }
-                       list_add_tail(&desc->list, &ie->work_list);
+
+                       if (d->completion->status)
+                               list_add_tail(&d->list, &flist);
+                       else
+                               list_add_tail(&d->list, &ie->work_list);
                }
        }
 
@@ -130,6 +135,17 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
 
        if (found)
                complete_desc(found, IDXD_COMPLETE_ABORT);
+
+       /*
+        * complete_desc() will return desc to allocator and the desc can be
+        * acquired by a different process and the desc->list can be modified.
+        * Delete desc from list so the list trasversing does not get corrupted
+        * by the other process.
+        */
+       list_for_each_entry_safe(d, t, &flist, list) {
+               list_del_init(&d->list);
+               complete_desc(d, IDXD_COMPLETE_NORMAL);
+       }
 }
 
 int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
index 962b6e0..d95c421 100644 (file)
@@ -874,4 +874,4 @@ MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver");
 MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>");
 MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
-MODULE_ALIAS("platform: " DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
index 041d8e3..6e56d1c 100644 (file)
@@ -4534,45 +4534,60 @@ static int udma_setup_resources(struct udma_dev *ud)
        rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
        if (IS_ERR(rm_res)) {
                bitmap_zero(ud->tchan_map, ud->tchan_cnt);
+               irq_res.sets = 1;
        } else {
                bitmap_fill(ud->tchan_map, ud->tchan_cnt);
                for (i = 0; i < rm_res->sets; i++)
                        udma_mark_resource_ranges(ud, ud->tchan_map,
                                                  &rm_res->desc[i], "tchan");
+               irq_res.sets = rm_res->sets;
        }
-       irq_res.sets = rm_res->sets;
 
        /* rchan and matching default flow ranges */
        rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
        if (IS_ERR(rm_res)) {
                bitmap_zero(ud->rchan_map, ud->rchan_cnt);
+               irq_res.sets++;
        } else {
                bitmap_fill(ud->rchan_map, ud->rchan_cnt);
                for (i = 0; i < rm_res->sets; i++)
                        udma_mark_resource_ranges(ud, ud->rchan_map,
                                                  &rm_res->desc[i], "rchan");
+               irq_res.sets += rm_res->sets;
        }
 
-       irq_res.sets += rm_res->sets;
        irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
+       if (!irq_res.desc)
+               return -ENOMEM;
        rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
-       for (i = 0; i < rm_res->sets; i++) {
-               irq_res.desc[i].start = rm_res->desc[i].start;
-               irq_res.desc[i].num = rm_res->desc[i].num;
-               irq_res.desc[i].start_sec = rm_res->desc[i].start_sec;
-               irq_res.desc[i].num_sec = rm_res->desc[i].num_sec;
+       if (IS_ERR(rm_res)) {
+               irq_res.desc[0].start = 0;
+               irq_res.desc[0].num = ud->tchan_cnt;
+               i = 1;
+       } else {
+               for (i = 0; i < rm_res->sets; i++) {
+                       irq_res.desc[i].start = rm_res->desc[i].start;
+                       irq_res.desc[i].num = rm_res->desc[i].num;
+                       irq_res.desc[i].start_sec = rm_res->desc[i].start_sec;
+                       irq_res.desc[i].num_sec = rm_res->desc[i].num_sec;
+               }
        }
        rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
-       for (j = 0; j < rm_res->sets; j++, i++) {
-               if (rm_res->desc[j].num) {
-                       irq_res.desc[i].start = rm_res->desc[j].start +
-                                       ud->soc_data->oes.udma_rchan;
-                       irq_res.desc[i].num = rm_res->desc[j].num;
-               }
-               if (rm_res->desc[j].num_sec) {
-                       irq_res.desc[i].start_sec = rm_res->desc[j].start_sec +
-                                       ud->soc_data->oes.udma_rchan;
-                       irq_res.desc[i].num_sec = rm_res->desc[j].num_sec;
+       if (IS_ERR(rm_res)) {
+               irq_res.desc[i].start = 0;
+               irq_res.desc[i].num = ud->rchan_cnt;
+       } else {
+               for (j = 0; j < rm_res->sets; j++, i++) {
+                       if (rm_res->desc[j].num) {
+                               irq_res.desc[i].start = rm_res->desc[j].start +
+                                               ud->soc_data->oes.udma_rchan;
+                               irq_res.desc[i].num = rm_res->desc[j].num;
+                       }
+                       if (rm_res->desc[j].num_sec) {
+                               irq_res.desc[i].start_sec = rm_res->desc[j].start_sec +
+                                               ud->soc_data->oes.udma_rchan;
+                               irq_res.desc[i].num_sec = rm_res->desc[j].num_sec;
+                       }
                }
        }
        ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res);
@@ -4690,14 +4705,15 @@ static int bcdma_setup_resources(struct udma_dev *ud)
                rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN];
                if (IS_ERR(rm_res)) {
                        bitmap_zero(ud->bchan_map, ud->bchan_cnt);
+                       irq_res.sets++;
                } else {
                        bitmap_fill(ud->bchan_map, ud->bchan_cnt);
                        for (i = 0; i < rm_res->sets; i++)
                                udma_mark_resource_ranges(ud, ud->bchan_map,
                                                          &rm_res->desc[i],
                                                          "bchan");
+                       irq_res.sets += rm_res->sets;
                }
-               irq_res.sets += rm_res->sets;
        }
 
        /* tchan ranges */
@@ -4705,14 +4721,15 @@ static int bcdma_setup_resources(struct udma_dev *ud)
                rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
                if (IS_ERR(rm_res)) {
                        bitmap_zero(ud->tchan_map, ud->tchan_cnt);
+                       irq_res.sets += 2;
                } else {
                        bitmap_fill(ud->tchan_map, ud->tchan_cnt);
                        for (i = 0; i < rm_res->sets; i++)
                                udma_mark_resource_ranges(ud, ud->tchan_map,
                                                          &rm_res->desc[i],
                                                          "tchan");
+                       irq_res.sets += rm_res->sets * 2;
                }
-               irq_res.sets += rm_res->sets * 2;
        }
 
        /* rchan ranges */
@@ -4720,47 +4737,72 @@ static int bcdma_setup_resources(struct udma_dev *ud)
                rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
                if (IS_ERR(rm_res)) {
                        bitmap_zero(ud->rchan_map, ud->rchan_cnt);
+                       irq_res.sets += 2;
                } else {
                        bitmap_fill(ud->rchan_map, ud->rchan_cnt);
                        for (i = 0; i < rm_res->sets; i++)
                                udma_mark_resource_ranges(ud, ud->rchan_map,
                                                          &rm_res->desc[i],
                                                          "rchan");
+                       irq_res.sets += rm_res->sets * 2;
                }
-               irq_res.sets += rm_res->sets * 2;
        }
 
        irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
+       if (!irq_res.desc)
+               return -ENOMEM;
        if (ud->bchan_cnt) {
                rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN];
-               for (i = 0; i < rm_res->sets; i++) {
-                       irq_res.desc[i].start = rm_res->desc[i].start +
-                                               oes->bcdma_bchan_ring;
-                       irq_res.desc[i].num = rm_res->desc[i].num;
+               if (IS_ERR(rm_res)) {
+                       irq_res.desc[0].start = oes->bcdma_bchan_ring;
+                       irq_res.desc[0].num = ud->bchan_cnt;
+                       i = 1;
+               } else {
+                       for (i = 0; i < rm_res->sets; i++) {
+                               irq_res.desc[i].start = rm_res->desc[i].start +
+                                                       oes->bcdma_bchan_ring;
+                               irq_res.desc[i].num = rm_res->desc[i].num;
+                       }
                }
        }
        if (ud->tchan_cnt) {
                rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
-               for (j = 0; j < rm_res->sets; j++, i += 2) {
-                       irq_res.desc[i].start = rm_res->desc[j].start +
-                                               oes->bcdma_tchan_data;
-                       irq_res.desc[i].num = rm_res->desc[j].num;
-
-                       irq_res.desc[i + 1].start = rm_res->desc[j].start +
-                                               oes->bcdma_tchan_ring;
-                       irq_res.desc[i + 1].num = rm_res->desc[j].num;
+               if (IS_ERR(rm_res)) {
+                       irq_res.desc[i].start = oes->bcdma_tchan_data;
+                       irq_res.desc[i].num = ud->tchan_cnt;
+                       irq_res.desc[i + 1].start = oes->bcdma_tchan_ring;
+                       irq_res.desc[i + 1].num = ud->tchan_cnt;
+                       i += 2;
+               } else {
+                       for (j = 0; j < rm_res->sets; j++, i += 2) {
+                               irq_res.desc[i].start = rm_res->desc[j].start +
+                                                       oes->bcdma_tchan_data;
+                               irq_res.desc[i].num = rm_res->desc[j].num;
+
+                               irq_res.desc[i + 1].start = rm_res->desc[j].start +
+                                                       oes->bcdma_tchan_ring;
+                               irq_res.desc[i + 1].num = rm_res->desc[j].num;
+                       }
                }
        }
        if (ud->rchan_cnt) {
                rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
-               for (j = 0; j < rm_res->sets; j++, i += 2) {
-                       irq_res.desc[i].start = rm_res->desc[j].start +
-                                               oes->bcdma_rchan_data;
-                       irq_res.desc[i].num = rm_res->desc[j].num;
-
-                       irq_res.desc[i + 1].start = rm_res->desc[j].start +
-                                               oes->bcdma_rchan_ring;
-                       irq_res.desc[i + 1].num = rm_res->desc[j].num;
+               if (IS_ERR(rm_res)) {
+                       irq_res.desc[i].start = oes->bcdma_rchan_data;
+                       irq_res.desc[i].num = ud->rchan_cnt;
+                       irq_res.desc[i + 1].start = oes->bcdma_rchan_ring;
+                       irq_res.desc[i + 1].num = ud->rchan_cnt;
+                       i += 2;
+               } else {
+                       for (j = 0; j < rm_res->sets; j++, i += 2) {
+                               irq_res.desc[i].start = rm_res->desc[j].start +
+                                                       oes->bcdma_rchan_data;
+                               irq_res.desc[i].num = rm_res->desc[j].num;
+
+                               irq_res.desc[i + 1].start = rm_res->desc[j].start +
+                                                       oes->bcdma_rchan_ring;
+                               irq_res.desc[i + 1].num = rm_res->desc[j].num;
+                       }
                }
        }
 
@@ -4858,39 +4900,54 @@ static int pktdma_setup_resources(struct udma_dev *ud)
        if (IS_ERR(rm_res)) {
                /* all rflows are assigned exclusively to Linux */
                bitmap_zero(ud->rflow_in_use, ud->rflow_cnt);
+               irq_res.sets = 1;
        } else {
                bitmap_fill(ud->rflow_in_use, ud->rflow_cnt);
                for (i = 0; i < rm_res->sets; i++)
                        udma_mark_resource_ranges(ud, ud->rflow_in_use,
                                                  &rm_res->desc[i], "rflow");
+               irq_res.sets = rm_res->sets;
        }
-       irq_res.sets = rm_res->sets;
 
        /* tflow ranges */
        rm_res = tisci_rm->rm_ranges[RM_RANGE_TFLOW];
        if (IS_ERR(rm_res)) {
                /* all tflows are assigned exclusively to Linux */
                bitmap_zero(ud->tflow_map, ud->tflow_cnt);
+               irq_res.sets++;
        } else {
                bitmap_fill(ud->tflow_map, ud->tflow_cnt);
                for (i = 0; i < rm_res->sets; i++)
                        udma_mark_resource_ranges(ud, ud->tflow_map,
                                                  &rm_res->desc[i], "tflow");
+               irq_res.sets += rm_res->sets;
        }
-       irq_res.sets += rm_res->sets;
 
        irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
+       if (!irq_res.desc)
+               return -ENOMEM;
        rm_res = tisci_rm->rm_ranges[RM_RANGE_TFLOW];
-       for (i = 0; i < rm_res->sets; i++) {
-               irq_res.desc[i].start = rm_res->desc[i].start +
-                                       oes->pktdma_tchan_flow;
-               irq_res.desc[i].num = rm_res->desc[i].num;
+       if (IS_ERR(rm_res)) {
+               irq_res.desc[0].start = oes->pktdma_tchan_flow;
+               irq_res.desc[0].num = ud->tflow_cnt;
+               i = 1;
+       } else {
+               for (i = 0; i < rm_res->sets; i++) {
+                       irq_res.desc[i].start = rm_res->desc[i].start +
+                                               oes->pktdma_tchan_flow;
+                       irq_res.desc[i].num = rm_res->desc[i].num;
+               }
        }
        rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW];
-       for (j = 0; j < rm_res->sets; j++, i++) {
-               irq_res.desc[i].start = rm_res->desc[j].start +
-                                       oes->pktdma_rchan_flow;
-               irq_res.desc[i].num = rm_res->desc[j].num;
+       if (IS_ERR(rm_res)) {
+               irq_res.desc[i].start = oes->pktdma_rchan_flow;
+               irq_res.desc[i].num = ud->rflow_cnt;
+       } else {
+               for (j = 0; j < rm_res->sets; j++, i++) {
+                       irq_res.desc[i].start = rm_res->desc[j].start +
+                                               oes->pktdma_rchan_flow;
+                       irq_res.desc[i].num = rm_res->desc[j].num;
+               }
        }
        ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res);
        kfree(irq_res.desc);
index 5120160..8006739 100644 (file)
@@ -16,7 +16,6 @@ struct scpi_pm_domain {
        struct generic_pm_domain genpd;
        struct scpi_ops *ops;
        u32 domain;
-       char name[30];
 };
 
 /*
@@ -110,8 +109,13 @@ static int scpi_pm_domain_probe(struct platform_device *pdev)
 
                scpi_pd->domain = i;
                scpi_pd->ops = scpi_ops;
-               sprintf(scpi_pd->name, "%pOFn.%d", np, i);
-               scpi_pd->genpd.name = scpi_pd->name;
+               scpi_pd->genpd.name = devm_kasprintf(dev, GFP_KERNEL,
+                                                    "%pOFn.%d", np, i);
+               if (!scpi_pd->genpd.name) {
+                       dev_err(dev, "Failed to allocate genpd name:%pOFn.%d\n",
+                               np, i);
+                       continue;
+               }
                scpi_pd->genpd.power_off = scpi_pd_power_off;
                scpi_pd->genpd.power_on = scpi_pd_power_on;
 
index 6d66fe0..fd89899 100644 (file)
@@ -77,13 +77,14 @@ static const char *get_filename(struct tegra_bpmp *bpmp,
        const char *root_path, *filename = NULL;
        char *root_path_buf;
        size_t root_len;
+       size_t root_path_buf_len = 512;
 
-       root_path_buf = kzalloc(512, GFP_KERNEL);
+       root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL);
        if (!root_path_buf)
                goto out;
 
        root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
-                               sizeof(root_path_buf));
+                               root_path_buf_len);
        if (IS_ERR(root_path))
                goto out;
 
index b305fd3..edb3e3b 100644 (file)
@@ -3070,8 +3070,8 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev)
                              AMD_PG_SUPPORT_CP |
                              AMD_PG_SUPPORT_GDS |
                              AMD_PG_SUPPORT_RLC_SMU_HS)) {
-               WREG32(mmRLC_JUMP_TABLE_RESTORE,
-                      adev->gfx.rlc.cp_table_gpu_addr >> 8);
+               WREG32_SOC15(GC, 0, mmRLC_JUMP_TABLE_RESTORE,
+                            adev->gfx.rlc.cp_table_gpu_addr >> 8);
                gfx_v9_0_init_gfx_power_gating(adev);
        }
 }
index 480e418..ec4d5e1 100644 (file)
@@ -162,7 +162,6 @@ static void gfxhub_v1_0_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC);/* XXX for emulation. */
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
index 14c1c1a..6e0ace2 100644 (file)
@@ -196,7 +196,6 @@ static void gfxhub_v2_0_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC); /* UC, uncached */
 
index e80d1dc..b4eddf6 100644 (file)
@@ -197,7 +197,6 @@ static void gfxhub_v2_1_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC); /* UC, uncached */
 
index cb82404..d84523c 100644 (file)
@@ -1808,6 +1808,14 @@ static int gmc_v9_0_hw_fini(void *handle)
                return 0;
        }
 
+       /*
+        * Pair the operations did in gmc_v9_0_hw_init and thus maintain
+        * a correct cached state for GMC. Otherwise, the "gate" again
+        * operation on S3 resuming will fail due to wrong cached state.
+        */
+       if (adev->mmhub.funcs->update_power_gating)
+               adev->mmhub.funcs->update_power_gating(adev, false);
+
        amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0);
        amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0);
 
index a999538..1da2ec6 100644 (file)
@@ -145,7 +145,6 @@ static void mmhub_v1_0_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC);/* XXX for emulation. */
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
@@ -302,10 +301,10 @@ static void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev,
        if (amdgpu_sriov_vf(adev))
                return;
 
-       if (enable && adev->pg_flags & AMD_PG_SUPPORT_MMHUB) {
-               amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GMC, true);
-
-       }
+       if (adev->pg_flags & AMD_PG_SUPPORT_MMHUB)
+               amdgpu_dpm_set_powergating_by_smu(adev,
+                                                 AMD_IP_BLOCK_TYPE_GMC,
+                                                 enable);
 }
 
 static int mmhub_v1_0_gart_enable(struct amdgpu_device *adev)
index f80a14a..f5f7181 100644 (file)
@@ -165,7 +165,6 @@ static void mmhub_v1_7_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC);/* XXX for emulation. */
        tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
index 25f8e93..3718ff6 100644 (file)
@@ -267,7 +267,6 @@ static void mmhub_v2_0_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC); /* UC, uncached */
 
index a11d60e..9e16da2 100644 (file)
@@ -194,7 +194,6 @@ static void mmhub_v2_3_init_tlb_regs(struct amdgpu_device *adev)
                            ENABLE_ADVANCED_DRIVER_MODEL, 1);
        tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
-       tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
        tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC); /* UC, uncached */
 
index c4ef822..ff49eea 100644 (file)
@@ -190,8 +190,6 @@ static void mmhub_v9_4_init_tlb_regs(struct amdgpu_device *adev, int hubid)
        tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
                            SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
        tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
-                           ECO_BITS, 0);
-       tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
                            MTYPE, MTYPE_UC);/* XXX for emulation. */
        tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
                            ATC_EN, 1);
index 1cd6b9f..e727f1d 100644 (file)
@@ -1051,6 +1051,11 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
                return 0;
        }
 
+       /* Reset DMCUB if it was previously running - before we overwrite its memory. */
+       status = dmub_srv_hw_reset(dmub_srv);
+       if (status != DMUB_STATUS_OK)
+               DRM_WARN("Error resetting DMUB HW: %d\n", status);
+
        hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data;
 
        fw_inst_const = dmub_fw->data +
@@ -2576,7 +2581,8 @@ static int dm_resume(void *handle)
                 */
                link_enc_cfg_init(dm->dc, dc_state);
 
-               amdgpu_dm_outbox_init(adev);
+               if (dc_enable_dmub_notifications(adev->dm.dc))
+                       amdgpu_dm_outbox_init(adev);
 
                r = dm_dmub_hw_init(adev);
                if (r)
@@ -2625,6 +2631,10 @@ static int dm_resume(void *handle)
        /* TODO: Remove dc_state->dccg, use dc->dccg directly. */
        dc_resource_state_construct(dm->dc, dm_state->context);
 
+       /* Re-enable outbox interrupts for DPIA. */
+       if (dc_enable_dmub_notifications(adev->dm.dc))
+               amdgpu_dm_outbox_init(adev);
+
        /* Before powering on DC we need to re-initialize DMUB. */
        r = dm_dmub_hw_init(adev);
        if (r)
index b01077a..fad3d88 100644 (file)
@@ -226,6 +226,8 @@ static inline void get_edp_links(const struct dc *dc,
        *edp_num = 0;
        for (i = 0; i < dc->link_count; i++) {
                // report any eDP links, even unconnected DDI's
+               if (!dc->links[i])
+                       continue;
                if (dc->links[i]->connector_signal == SIGNAL_TYPE_EDP) {
                        edp_links[*edp_num] = dc->links[i];
                        if (++(*edp_num) == MAX_NUM_EDP)
index 05335a8..4f6e639 100644 (file)
@@ -101,6 +101,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
        .z10_restore = dcn31_z10_restore,
        .z10_save_init = dcn31_z10_save_init,
        .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
+       .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
        .update_visual_confirm_color = dcn20_update_visual_confirm_color,
 };
 
index 8d796ed..619f8d3 100644 (file)
@@ -1328,7 +1328,12 @@ static int pp_set_powergating_by_smu(void *handle,
                pp_dpm_powergate_vce(handle, gate);
                break;
        case AMD_IP_BLOCK_TYPE_GMC:
-               pp_dpm_powergate_mmhub(handle);
+               /*
+                * For now, this is only used on PICASSO.
+                * And only "gate" operation is supported.
+                */
+               if (gate)
+                       pp_dpm_powergate_mmhub(handle);
                break;
        case AMD_IP_BLOCK_TYPE_GFX:
                ret = pp_dpm_powergate_gfx(handle, gate);
index d60b8c5..43028f2 100644 (file)
@@ -191,6 +191,9 @@ int smu_v12_0_fini_smc_tables(struct smu_context *smu)
        kfree(smu_table->watermarks_table);
        smu_table->watermarks_table = NULL;
 
+       kfree(smu_table->gpu_metrics_table);
+       smu_table->gpu_metrics_table = NULL;
+
        return 0;
 }
 
index 35145db..19a5d2c 100644 (file)
@@ -198,6 +198,7 @@ int smu_v13_0_check_fw_status(struct smu_context *smu)
 
 int smu_v13_0_check_fw_version(struct smu_context *smu)
 {
+       struct amdgpu_device *adev = smu->adev;
        uint32_t if_version = 0xff, smu_version = 0xff;
        uint16_t smu_major;
        uint8_t smu_minor, smu_debug;
@@ -210,6 +211,8 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)
        smu_major = (smu_version >> 16) & 0xffff;
        smu_minor = (smu_version >> 8) & 0xff;
        smu_debug = (smu_version >> 0) & 0xff;
+       if (smu->is_apu)
+               adev->pm.fw_version = smu_version;
 
        switch (smu->adev->ip_versions[MP1_HWIP][0]) {
        case IP_VERSION(13, 0, 2):
index 1e30eae..d5c98f7 100644 (file)
@@ -1121,7 +1121,10 @@ static void ast_crtc_reset(struct drm_crtc *crtc)
        if (crtc->state)
                crtc->funcs->atomic_destroy_state(crtc, crtc->state);
 
-       __drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
+       if (ast_state)
+               __drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
+       else
+               __drm_atomic_helper_crtc_reset(crtc, NULL);
 }
 
 static struct drm_crtc_state *
index 8e7a124..22bf690 100644 (file)
@@ -1743,7 +1743,13 @@ void drm_fb_helper_fill_info(struct fb_info *info,
                               sizes->fb_width, sizes->fb_height);
 
        info->par = fb_helper;
-       snprintf(info->fix.id, sizeof(info->fix.id), "%s",
+       /*
+        * The DRM drivers fbdev emulation device name can be confusing if the
+        * driver name also has a "drm" suffix on it. Leading to names such as
+        * "simpledrmdrmfb" in /proc/fb. Unfortunately, it's an uAPI and can't
+        * be changed due user-space tools (e.g: pm-utils) matching against it.
+        */
+       snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb",
                 fb_helper->dev->driver->name);
 
 }
index 7b9f69f..bca0de9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/module.h>
 
 #ifdef CONFIG_X86
 #include <asm/set_memory.h>
index c9a9d74..c313a5b 100644 (file)
@@ -404,8 +404,17 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
 
        if (*fence) {
                ret = dma_fence_chain_find_seqno(fence, point);
-               if (!ret)
+               if (!ret) {
+                       /* If the requested seqno is already signaled
+                        * drm_syncobj_find_fence may return a NULL
+                        * fence. To make sure the recipient gets
+                        * signalled, use a new fence instead.
+                        */
+                       if (!*fence)
+                               *fence = dma_fence_get_stub();
+
                        goto out;
+               }
                dma_fence_put(*fence);
        } else {
                ret = -EINVAL;
index 2dc9d63..aef6952 100644 (file)
@@ -596,7 +596,7 @@ static void parse_dmc_fw(struct drm_i915_private *dev_priv,
                        continue;
 
                offset = readcount + dmc->dmc_info[id].dmc_offset * 4;
-               if (fw->size - offset < 0) {
+               if (offset > fw->size) {
                        drm_err(&dev_priv->drm, "Reading beyond the fw_size\n");
                        continue;
                }
index 4d7da07..9b24d9b 100644 (file)
@@ -3277,6 +3277,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
        out_fence = eb_requests_create(&eb, in_fence, out_fence_fd);
        if (IS_ERR(out_fence)) {
                err = PTR_ERR(out_fence);
+               out_fence = NULL;
                if (eb.requests[0])
                        goto err_request;
                else
index 67d14af..b67f620 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/slab.h> /* fault-inject.h is not standalone! */
 
 #include <linux/fault-inject.h>
+#include <linux/sched/mm.h>
 
 #include "gem/i915_gem_lmem.h"
 #include "i915_trace.h"
index ed73d9b..2400d64 100644 (file)
@@ -1127,6 +1127,15 @@ icl_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
                    GAMT_CHKN_BIT_REG,
                    GAMT_CHKN_DISABLE_L3_COH_PIPE);
 
+       /* Wa_1407352427:icl,ehl */
+       wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE2,
+                   PSDUNIT_CLKGATE_DIS);
+
+       /* Wa_1406680159:icl,ehl */
+       wa_write_or(wal,
+                   SUBSLICE_UNIT_LEVEL_CLKGATE,
+                   GWUNIT_CLKGATE_DIS);
+
        /* Wa_1607087056:icl,ehl,jsl */
        if (IS_ICELAKE(i915) ||
            IS_JSL_EHL_GT_STEP(i915, STEP_A0, STEP_B0))
@@ -1852,15 +1861,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
                wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE,
                            VSUNIT_CLKGATE_DIS | HSUNIT_CLKGATE_DIS);
 
-               /* Wa_1407352427:icl,ehl */
-               wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE2,
-                           PSDUNIT_CLKGATE_DIS);
-
-               /* Wa_1406680159:icl,ehl */
-               wa_write_or(wal,
-                           SUBSLICE_UNIT_LEVEL_CLKGATE,
-                           GWUNIT_CLKGATE_DIS);
-
                /*
                 * Wa_1408767742:icl[a2..forever],ehl[all]
                 * Wa_1605460711:icl[a0..c0]
index 820a1f3..89cccef 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/sched/clock.h>
 #include <linux/sched/signal.h>
+#include <linux/sched/mm.h>
 
 #include "gem/i915_gem_context.h"
 #include "gt/intel_breadcrumbs.h"
index 65fdca3..f74f804 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/clk.h>
+#include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 
index 4a1420b..086dacf 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/vmalloc.h>
+#include <linux/sched/mm.h>
 
 #include "msm_drv.h"
 #include "msm_gem.h"
index 481b48b..5a6e898 100644 (file)
@@ -458,7 +458,7 @@ static struct drm_display_mode simpledrm_mode(unsigned int width,
 {
        struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) };
 
-       mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay;
+       mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */;
        drm_mode_set_name(&mode);
 
        return mode;
index 739f11c..047adc4 100644 (file)
@@ -1103,7 +1103,7 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
         * as an indication that we're about to swap out.
         */
        memset(&place, 0, sizeof(place));
-       place.mem_type = TTM_PL_SYSTEM;
+       place.mem_type = bo->resource->mem_type;
        if (!ttm_bo_evict_swapout_allowable(bo, ctx, &place, &locked, NULL))
                return -EBUSY;
 
@@ -1135,6 +1135,7 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
                struct ttm_place hop;
 
                memset(&hop, 0, sizeof(hop));
+               place.mem_type = TTM_PL_SYSTEM;
                ret = ttm_resource_alloc(bo, &place, &evict_mem);
                if (unlikely(ret))
                        goto out;
index 7e83c00..79c870a 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/sched.h>
 #include <linux/shmem_fs.h>
 #include <linux/file.h>
+#include <linux/module.h>
 #include <drm/drm_cache.h>
 #include <drm/ttm/ttm_bo_driver.h>
 
index 9f5435b..a7c78ac 100644 (file)
@@ -207,14 +207,14 @@ config HID_CHERRY
 
 config HID_CHICONY
        tristate "Chicony devices"
-       depends on HID
+       depends on USB_HID
        default !EXPERT
        help
        Support for Chicony Tactical pad and special keys on Chicony keyboards.
 
 config HID_CORSAIR
        tristate "Corsair devices"
-       depends on HID && USB && LEDS_CLASS
+       depends on USB_HID && LEDS_CLASS
        help
        Support for Corsair devices that are not fully compliant with the
        HID standard.
@@ -245,7 +245,7 @@ config HID_MACALLY
 
 config HID_PRODIKEYS
        tristate "Prodikeys PC-MIDI Keyboard support"
-       depends on HID && SND
+       depends on USB_HID && SND
        select SND_RAWMIDI
        help
        Support for Prodikeys PC-MIDI Keyboard device support.
@@ -560,7 +560,7 @@ config HID_LENOVO
 
 config HID_LOGITECH
        tristate "Logitech devices"
-       depends on HID
+       depends on USB_HID
        depends on LEDS_CLASS
        default !EXPERT
        help
@@ -951,7 +951,7 @@ config HID_SAITEK
 
 config HID_SAMSUNG
        tristate "Samsung InfraRed remote control or keyboards"
-       depends on HID
+       depends on USB_HID
        help
        Support for Samsung InfraRed remote control or keyboards.
 
index f3ecddc..08c9a9a 100644 (file)
@@ -1028,8 +1028,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
                drvdata->tp = &asus_i2c_tp;
 
-       if ((drvdata->quirks & QUIRK_T100_KEYBOARD) &&
-           hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+       if ((drvdata->quirks & QUIRK_T100_KEYBOARD) && hid_is_usb(hdev)) {
                struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
                if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
@@ -1057,8 +1056,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
                drvdata->tp = &asus_t100chi_tp;
        }
 
-       if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
-           hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+       if ((drvdata->quirks & QUIRK_MEDION_E1239T) && hid_is_usb(hdev)) {
                struct usb_host_interface *alt =
                        to_usb_interface(hdev->dev.parent)->altsetting;
 
index db6da21..74ad8bf 100644 (file)
@@ -191,7 +191,7 @@ static void bigben_worker(struct work_struct *work)
                struct bigben_device, worker);
        struct hid_field *report_field = bigben->report->field[0];
 
-       if (bigben->removed)
+       if (bigben->removed || !report_field)
                return;
 
        if (bigben->work_led) {
index ca556d3..f04d2aa 100644 (file)
@@ -114,6 +114,9 @@ static int ch_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
        ret = hid_parse(hdev);
        if (ret) {
index 902a60e..8c895c8 100644 (file)
@@ -553,7 +553,12 @@ static int corsair_probe(struct hid_device *dev, const struct hid_device_id *id)
        int ret;
        unsigned long quirks = id->driver_data;
        struct corsair_drvdata *drvdata;
-       struct usb_interface *usbif = to_usb_interface(dev->dev.parent);
+       struct usb_interface *usbif;
+
+       if (!hid_is_usb(dev))
+               return -EINVAL;
+
+       usbif = to_usb_interface(dev->dev.parent);
 
        drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata),
                               GFP_KERNEL);
index 0210498..3091355 100644 (file)
@@ -50,7 +50,7 @@ struct elan_drvdata {
 
 static int is_not_elan_touchpad(struct hid_device *hdev)
 {
-       if (hdev->bus == BUS_USB) {
+       if (hid_is_usb(hdev)) {
                struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
                return (intf->altsetting->desc.bInterfaceNumber !=
index 383dfda..8e960d7 100644 (file)
@@ -230,6 +230,9 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
        int ret;
        struct usb_device *udev;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
index 8ee77f4..79505c6 100644 (file)
@@ -915,6 +915,9 @@ static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct ft260_get_chip_version_report version;
        int ret;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
index 8123b87..0403beb 100644 (file)
@@ -586,6 +586,8 @@ static const struct hid_device_id hammer_devices[] = {
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) },
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+                    USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_EEL) },
+       { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) },
index 0a38e8e..403506b 100644 (file)
@@ -140,12 +140,17 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type,
 static int holtek_kbd_probe(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
-       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-       int ret = hid_parse(hdev);
+       struct usb_interface *intf;
+       int ret;
+
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
 
+       ret = hid_parse(hdev);
        if (!ret)
                ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 
+       intf = to_usb_interface(hdev->dev.parent);
        if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) {
                struct hid_input *hidinput;
                list_for_each_entry(hidinput, &hdev->inputs, list) {
index 195b735..b7172c4 100644 (file)
@@ -62,6 +62,14 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        return rdesc;
 }
 
+static int holtek_mouse_probe(struct hid_device *hdev,
+                             const struct hid_device_id *id)
+{
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+       return 0;
+}
+
 static const struct hid_device_id holtek_mouse_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
                        USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
@@ -83,6 +91,7 @@ static struct hid_driver holtek_mouse_driver = {
        .name = "holtek_mouse",
        .id_table = holtek_mouse_devices,
        .report_fixup = holtek_mouse_report_fixup,
+       .probe = holtek_mouse_probe,
 };
 
 module_hid_driver(holtek_mouse_driver);
index 96a4559..19da077 100644 (file)
 #define USB_DEVICE_ID_HP_X2_10_COVER   0x0755
 #define I2C_DEVICE_ID_HP_ENVY_X360_15  0x2d05
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_15       0x2817
+#define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544
 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN   0x2706
 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN   0x261A
 
 #define USB_DEVICE_ID_GOOGLE_MAGNEMITE 0x503d
 #define USB_DEVICE_ID_GOOGLE_MOONBALL  0x5044
 #define USB_DEVICE_ID_GOOGLE_DON       0x5050
+#define USB_DEVICE_ID_GOOGLE_EEL       0x5057
 
 #define USB_VENDOR_ID_GOTOP            0x08f2
 #define USB_DEVICE_ID_SUPER_Q2         0x007f
 #define USB_DEVICE_ID_MS_TOUCH_COVER_2   0x07a7
 #define USB_DEVICE_ID_MS_TYPE_COVER_2    0x07a9
 #define USB_DEVICE_ID_MS_POWER_COVER     0x07da
+#define USB_DEVICE_ID_MS_SURFACE3_COVER                0x07de
 #define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
 #define USB_DEVICE_ID_MS_PIXART_MOUSE    0x00cb
 #define USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS      0x02e0
index 217f2d1..03f9945 100644 (file)
@@ -325,6 +325,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
          HID_BATTERY_QUIRK_IGNORE },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
          HID_BATTERY_QUIRK_IGNORE },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
+         HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
          HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
index d40af91..fb3f725 100644 (file)
@@ -749,12 +749,18 @@ static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
 
 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
-       struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
-       __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+       struct usb_interface *iface;
+       __u8 iface_num;
        unsigned int connect_mask = HID_CONNECT_DEFAULT;
        struct lg_drv_data *drv_data;
        int ret;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
+       iface = to_usb_interface(hdev->dev.parent);
+       iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
        /* G29 only work with the 1st interface */
        if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
            (iface_num != 0)) {
index a0017b0..7106b92 100644 (file)
@@ -1777,7 +1777,7 @@ static int logi_dj_probe(struct hid_device *hdev,
        case recvr_type_bluetooth:      no_dj_interfaces = 2; break;
        case recvr_type_dinovo:         no_dj_interfaces = 2; break;
        }
-       if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+       if (hid_is_usb(hdev)) {
                intf = to_usb_interface(hdev->dev.parent);
                if (intf && intf->altsetting->desc.bInterfaceNumber >=
                                                        no_dj_interfaces) {
index 2666af0..e4e9471 100644 (file)
@@ -798,12 +798,18 @@ static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,
 static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
-       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-       unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+       struct usb_interface *intf;
+       unsigned short ifnum;
        unsigned long quirks = id->driver_data;
        struct pk_device *pk;
        struct pcmidi_snd *pm = NULL;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
+       intf = to_usb_interface(hdev->dev.parent);
+       ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
        pk = kzalloc(sizeof(*pk), GFP_KERNEL);
        if (pk == NULL) {
                hid_err(hdev, "can't alloc descriptor\n");
index 06b7908..ee7e504 100644 (file)
@@ -124,6 +124,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE3_COVER), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
index 4556d2a..d94ee05 100644 (file)
@@ -344,6 +344,9 @@ static int arvo_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index ce5f225..e95d59c 100644 (file)
@@ -324,6 +324,9 @@ static int isku_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index ea17abc..76da048 100644 (file)
@@ -749,6 +749,9 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 0316edf..1896c69 100644 (file)
@@ -431,6 +431,9 @@ static int koneplus_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 5248b3c..cf8eeb3 100644 (file)
@@ -133,6 +133,9 @@ static int konepure_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 9600128..6fb9b95 100644 (file)
@@ -501,6 +501,9 @@ static int kovaplus_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 4a88a76..d5ddf0d 100644 (file)
@@ -160,6 +160,9 @@ static int lua_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 989927d..4fcc8e7 100644 (file)
@@ -449,6 +449,9 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 3956a6c..5bf1971 100644 (file)
@@ -141,6 +141,9 @@ static int ryos_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 818701f..a784bb4 100644 (file)
@@ -113,6 +113,9 @@ static int savu_probe(struct hid_device *hdev,
 {
        int retval;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        retval = hid_parse(hdev);
        if (retval) {
                hid_err(hdev, "parse failed\n");
index 2e1c311..cf5992e 100644 (file)
@@ -152,6 +152,9 @@ static int samsung_probe(struct hid_device *hdev,
        int ret;
        unsigned int cmask = HID_CONNECT_DEFAULT;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed\n");
index d1b107d..60ec2b2 100644 (file)
@@ -3000,7 +3000,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        sc->quirks = quirks;
        hid_set_drvdata(hdev, sc);
        sc->hdev = hdev;
-       usbdev = to_usb_device(sc->hdev->dev.parent->parent);
 
        ret = hid_parse(hdev);
        if (ret) {
@@ -3038,14 +3037,23 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
         */
        if (!(hdev->claimed & HID_CLAIMED_INPUT)) {
                hid_err(hdev, "failed to claim input\n");
-               hid_hw_stop(hdev);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err;
        }
 
        if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) {
+               if (!hid_is_usb(hdev)) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               usbdev = to_usb_device(sc->hdev->dev.parent->parent);
+
                sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
-               if (!sc->ghl_urb)
-                       return -ENOMEM;
+               if (!sc->ghl_urb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
                if (sc->quirks & GHL_GUITAR_PS3WIIU)
                        ret = ghl_init_urb(sc, usbdev, ghl_ps3wiiu_magic_data,
@@ -3055,7 +3063,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                                                           ARRAY_SIZE(ghl_ps4_magic_data));
                if (ret) {
                        hid_err(hdev, "error preparing URB\n");
-                       return ret;
+                       goto err;
                }
 
                timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0);
@@ -3064,6 +3072,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        }
 
        return ret;
+
+err:
+       hid_hw_stop(hdev);
+       return ret;
 }
 
 static void sony_remove(struct hid_device *hdev)
index 3a53334..03b935f 100644 (file)
@@ -274,6 +274,9 @@ static int thrustmaster_probe(struct hid_device *hdev, const struct hid_device_i
        int ret = 0;
        struct tm_wheel *tm_wheel = NULL;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "parse failed with error %d\n", ret);
index 31ea7fc..ad489ca 100644 (file)
@@ -311,7 +311,7 @@ static int u2fzero_probe(struct hid_device *hdev,
        unsigned int minor;
        int ret;
 
-       if (!hid_is_using_ll_driver(hdev, &usb_hid_driver))
+       if (!hid_is_usb(hdev))
                return -EINVAL;
 
        dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
index 6a9865d..d8ab013 100644 (file)
@@ -164,6 +164,9 @@ static int uclogic_probe(struct hid_device *hdev,
        struct uclogic_drvdata *drvdata = NULL;
        bool params_initialized = false;
 
+       if (!hid_is_usb(hdev))
+               return -EINVAL;
+
        /*
         * libinput requires the pad interface to be on a different node
         * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
index 3d67b74..adff1bd 100644 (file)
@@ -843,8 +843,7 @@ int uclogic_params_init(struct uclogic_params *params,
        struct uclogic_params p = {0, };
 
        /* Check arguments */
-       if (params == NULL || hdev == NULL ||
-           !hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
+       if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
                rc = -EINVAL;
                goto cleanup;
        }
index 1c50390..8e9d945 100644 (file)
@@ -266,7 +266,8 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
 
        if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
                        && IPC_IS_ISH_ILUP(fwsts)) {
-               disable_irq_wake(pdev->irq);
+               if (device_may_wakeup(&pdev->dev))
+                       disable_irq_wake(pdev->irq);
 
                ish_set_host_ready(dev);
 
@@ -337,7 +338,8 @@ static int __maybe_unused ish_suspend(struct device *device)
                         */
                        pci_save_state(pdev);
 
-                       enable_irq_wake(pdev->irq);
+                       if (device_may_wakeup(&pdev->dev))
+                               enable_irq_wake(pdev->irq);
                }
        } else {
                /*
index 2717d39..066c567 100644 (file)
@@ -726,7 +726,7 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
         * Skip the query for this type and modify defaults based on
         * interface number.
         */
-       if (features->type == WIRELESS) {
+       if (features->type == WIRELESS && intf) {
                if (intf->cur_altsetting->desc.bInterfaceNumber == 0)
                        features->device_type = WACOM_DEVICETYPE_WL_MONITOR;
                else
@@ -2214,7 +2214,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
        if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
                char *product_name = wacom->hdev->name;
 
-               if (hid_is_using_ll_driver(wacom->hdev, &usb_hid_driver)) {
+               if (hid_is_usb(wacom->hdev)) {
                        struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent);
                        struct usb_device *dev = interface_to_usbdev(intf);
                        product_name = dev->product;
@@ -2451,6 +2451,9 @@ static void wacom_wireless_work(struct work_struct *work)
 
        wacom_destroy_battery(wacom);
 
+       if (!usbdev)
+               return;
+
        /* Stylus interface */
        hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
        wacom1 = hid_get_drvdata(hdev1);
@@ -2730,8 +2733,6 @@ static void wacom_mode_change_work(struct work_struct *work)
 static int wacom_probe(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
-       struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-       struct usb_device *dev = interface_to_usbdev(intf);
        struct wacom *wacom;
        struct wacom_wac *wacom_wac;
        struct wacom_features *features;
@@ -2766,8 +2767,14 @@ static int wacom_probe(struct hid_device *hdev,
        wacom_wac->hid_data.inputmode = -1;
        wacom_wac->mode_report = -1;
 
-       wacom->usbdev = dev;
-       wacom->intf = intf;
+       if (hid_is_usb(hdev)) {
+               struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+               struct usb_device *dev = interface_to_usbdev(intf);
+
+               wacom->usbdev = dev;
+               wacom->intf = intf;
+       }
+
        mutex_init(&wacom->lock);
        INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
        INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
index dd12af2..0747a8f 100644 (file)
@@ -19,6 +19,7 @@ config HYPERV_TIMER
 config HYPERV_UTILS
        tristate "Microsoft Hyper-V Utilities driver"
        depends on HYPERV && CONNECTOR && NLS
+       depends on PTP_1588_CLOCK_OPTIONAL
        help
          Select this option to enable the Hyper-V Utilities.
 
index 731d511..14389fd 100644 (file)
@@ -729,7 +729,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
        corsairpsu_check_cmd_support(priv);
 
        priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv,
-                                                         &corsairpsu_chip_info, 0);
+                                                         &corsairpsu_chip_info, NULL);
 
        if (IS_ERR(priv->hwmon_dev)) {
                ret = PTR_ERR(priv->hwmon_dev);
index eaace47..5596c21 100644 (file)
@@ -627,10 +627,9 @@ static void __init i8k_init_procfs(struct device *dev)
 {
        struct dell_smm_data *data = dev_get_drvdata(dev);
 
-       /* Register the proc entry */
-       proc_create_data("i8k", 0, NULL, &i8k_proc_ops, data);
-
-       devm_add_action_or_reset(dev, i8k_exit_procfs, NULL);
+       /* Only register exit function if creation was successful */
+       if (proc_create_data("i8k", 0, NULL, &i8k_proc_ops, data))
+               devm_add_action_or_reset(dev, i8k_exit_procfs, NULL);
 }
 
 #else
index 93dca47..57ce863 100644 (file)
@@ -1527,7 +1527,7 @@ static u16 nct6775_wmi_read_value(struct nct6775_data *data, u16 reg)
 
        nct6775_wmi_set_bank(data, reg);
 
-       err = nct6775_asuswmi_read(data->bank, reg, &tmp);
+       err = nct6775_asuswmi_read(data->bank, reg & 0xff, &tmp);
        if (err)
                return 0;
 
index 17518b4..f12b9a2 100644 (file)
@@ -336,8 +336,6 @@ static int pwm_fan_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       ctx->pwm_value = MAX_PWM;
-
        pwm_init_state(ctx->pwm, &ctx->pwm_state);
 
        /*
index 09c2a0b..3415d7a 100644 (file)
@@ -23,7 +23,7 @@
 /*
  * I2C command delays (in microseconds)
  */
-#define SHT4X_MEAS_DELAY       1000
+#define SHT4X_MEAS_DELAY_HPM   8200    /* see t_MEAS,h in datasheet */
 #define SHT4X_DELAY_EXTRA      10000
 
 /*
@@ -90,7 +90,7 @@ static int sht4x_read_values(struct sht4x_data *data)
        if (ret < 0)
                goto unlock;
 
-       usleep_range(SHT4X_MEAS_DELAY, SHT4X_MEAS_DELAY + SHT4X_DELAY_EXTRA);
+       usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA);
 
        ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH);
        if (ret != SHT4X_RESPONSE_LENGTH) {
index a6ea1eb..53b8da6 100644 (file)
@@ -636,7 +636,7 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
        status = readb(i2c->base + MPC_I2C_SR);
        if (status & CSR_MIF) {
                /* Wait up to 100us for transfer to properly complete */
-               readb_poll_timeout(i2c->base + MPC_I2C_SR, status, !(status & CSR_MCF), 0, 100);
+               readb_poll_timeout_atomic(i2c->base + MPC_I2C_SR, status, status & CSR_MCF, 0, 100);
                writeb(0, i2c->base + MPC_I2C_SR);
                mpc_i2c_do_intr(i2c, status);
                return IRQ_HANDLED;
index 9537878..41eb0dc 100644 (file)
 /**
  * struct virtio_i2c - virtio I2C data
  * @vdev: virtio device for this controller
- * @completion: completion of virtio I2C message
  * @adap: I2C adapter for this controller
  * @vq: the virtio virtqueue for communication
  */
 struct virtio_i2c {
        struct virtio_device *vdev;
-       struct completion completion;
        struct i2c_adapter adap;
        struct virtqueue *vq;
 };
 
 /**
  * struct virtio_i2c_req - the virtio I2C request structure
+ * @completion: completion of virtio I2C message
  * @out_hdr: the OUT header of the virtio I2C message
  * @buf: the buffer into which data is read, or from which it's written
  * @in_hdr: the IN header of the virtio I2C message
  */
 struct virtio_i2c_req {
+       struct completion completion;
        struct virtio_i2c_out_hdr out_hdr       ____cacheline_aligned;
        uint8_t *buf                            ____cacheline_aligned;
        struct virtio_i2c_in_hdr in_hdr         ____cacheline_aligned;
@@ -47,9 +47,11 @@ struct virtio_i2c_req {
 
 static void virtio_i2c_msg_done(struct virtqueue *vq)
 {
-       struct virtio_i2c *vi = vq->vdev->priv;
+       struct virtio_i2c_req *req;
+       unsigned int len;
 
-       complete(&vi->completion);
+       while ((req = virtqueue_get_buf(vq, &len)))
+               complete(&req->completion);
 }
 
 static int virtio_i2c_prepare_reqs(struct virtqueue *vq,
@@ -62,6 +64,8 @@ static int virtio_i2c_prepare_reqs(struct virtqueue *vq,
        for (i = 0; i < num; i++) {
                int outcnt = 0, incnt = 0;
 
+               init_completion(&reqs[i].completion);
+
                /*
                 * Only 7-bit mode supported for this moment. For the address
                 * format, Please check the Virtio I2C Specification.
@@ -106,21 +110,15 @@ static int virtio_i2c_complete_reqs(struct virtqueue *vq,
                                    struct virtio_i2c_req *reqs,
                                    struct i2c_msg *msgs, int num)
 {
-       struct virtio_i2c_req *req;
        bool failed = false;
-       unsigned int len;
        int i, j = 0;
 
        for (i = 0; i < num; i++) {
-               /* Detach the ith request from the vq */
-               req = virtqueue_get_buf(vq, &len);
+               struct virtio_i2c_req *req = &reqs[i];
 
-               /*
-                * Condition req == &reqs[i] should always meet since we have
-                * total num requests in the vq. reqs[i] can never be NULL here.
-                */
-               if (!failed && (WARN_ON(req != &reqs[i]) ||
-                               req->in_hdr.status != VIRTIO_I2C_MSG_OK))
+               wait_for_completion(&req->completion);
+
+               if (!failed && req->in_hdr.status != VIRTIO_I2C_MSG_OK)
                        failed = true;
 
                i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], !failed);
@@ -156,12 +154,8 @@ static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
         * remote here to clear the virtqueue, so we can try another set of
         * messages later on.
         */
-
-       reinit_completion(&vi->completion);
        virtqueue_kick(vq);
 
-       wait_for_completion(&vi->completion);
-
        count = virtio_i2c_complete_reqs(vq, reqs, msgs, count);
 
 err_free:
@@ -210,8 +204,6 @@ static int virtio_i2c_probe(struct virtio_device *vdev)
        vdev->priv = vi;
        vi->vdev = vdev;
 
-       init_completion(&vi->completion);
-
        ret = virtio_i2c_setup_vqs(vi);
        if (ret)
                return ret;
index a51fdd3..24c9387 100644 (file)
@@ -1595,8 +1595,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
        return 0;
 
 err_buffer_cleanup:
-       if (data->dready_trig)
-               iio_triggered_buffer_cleanup(indio_dev);
+       iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
        if (data->dready_trig)
                iio_trigger_unregister(data->dready_trig);
@@ -1618,8 +1617,8 @@ static int kxcjk1013_remove(struct i2c_client *client)
        pm_runtime_disable(&client->dev);
        pm_runtime_set_suspended(&client->dev);
 
+       iio_triggered_buffer_cleanup(indio_dev);
        if (data->dready_trig) {
-               iio_triggered_buffer_cleanup(indio_dev);
                iio_trigger_unregister(data->dready_trig);
                iio_trigger_unregister(data->motion_trig);
        }
index 2faf85c..552eba5 100644 (file)
@@ -224,14 +224,14 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
                               hw_values.chan,
                               sizeof(hw_values.chan));
        if (ret) {
-               dev_err(st->dev,
-                       "error reading data\n");
-               return ret;
+               dev_err(st->dev, "error reading data: %d\n", ret);
+               goto out;
        }
 
        iio_push_to_buffers_with_timestamp(indio_dev,
                                           &hw_values,
                                           iio_get_time_ns(indio_dev));
+out:
        iio_trigger_notify_done(indio_dev->trig);
 
        return IRQ_HANDLED;
index 715b813..09c7f10 100644 (file)
@@ -1470,7 +1470,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
        if (ret)
                return ret;
 
-       indio_dev->trig = trig;
+       indio_dev->trig = iio_trigger_get(trig);
 
        return 0;
 }
index 8bf5b62..3363af1 100644 (file)
@@ -532,7 +532,7 @@ config IMX7D_ADC
 
 config IMX8QXP_ADC
        tristate "NXP IMX8QXP ADC driver"
-       depends on ARCH_MXC_ARM64 || COMPILE_TEST
+       depends on ARCH_MXC || COMPILE_TEST
        depends on HAS_IOMEM
        help
          Say yes here to build support for IMX8QXP ADC.
index 2c5c8a3..aa42ba7 100644 (file)
@@ -480,8 +480,8 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p)
        iio_push_to_buffers_with_timestamp(indio_dev, &st->data.scan,
                                           iio_get_time_ns(indio_dev));
 
-       iio_trigger_notify_done(indio_dev->trig);
 err_unlock:
+       iio_trigger_notify_done(indio_dev->trig);
        mutex_unlock(&st->lock);
 
        return IRQ_HANDLED;
index 4c922ef..92a57cf 100644 (file)
@@ -1586,7 +1586,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
                *val = st->conversion_value;
                ret = at91_adc_adjust_val_osr(st, val);
                if (chan->scan_type.sign == 's')
-                       *val = sign_extend32(*val, 11);
+                       *val = sign_extend32(*val,
+                                            chan->scan_type.realbits - 1);
                st->conversion_done = false;
        }
 
index 3e0c023..df99f13 100644 (file)
@@ -251,19 +251,8 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev,
                          struct iio_chan_spec const *chan, int *val)
 {
        struct axp20x_adc_iio *info = iio_priv(indio_dev);
-       int size;
 
-       /*
-        * N.B.: Unlike the Chinese datasheets tell, the charging current is
-        * stored on 12 bits, not 13 bits. Only discharging current is on 13
-        * bits.
-        */
-       if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
-               size = 13;
-       else
-               size = 12;
-
-       *val = axp20x_read_variable_width(info->regmap, chan->address, size);
+       *val = axp20x_read_variable_width(info->regmap, chan->address, 12);
        if (*val < 0)
                return *val;
 
@@ -386,9 +375,8 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
                return IIO_VAL_INT_PLUS_MICRO;
 
        case IIO_CURRENT:
-               *val = 0;
-               *val2 = 500000;
-               return IIO_VAL_INT_PLUS_MICRO;
+               *val = 1;
+               return IIO_VAL_INT;
 
        case IIO_TEMP:
                *val = 100;
index 1640766..97d162a 100644 (file)
@@ -248,7 +248,6 @@ static int dln2_adc_set_chan_period(struct dln2_adc *dln2,
 static int dln2_adc_read(struct dln2_adc *dln2, unsigned int channel)
 {
        int ret, i;
-       struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);
        u16 conflict;
        __le16 value;
        int olen = sizeof(value);
@@ -257,13 +256,9 @@ static int dln2_adc_read(struct dln2_adc *dln2, unsigned int channel)
                .chan = channel,
        };
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret < 0)
-               return ret;
-
        ret = dln2_adc_set_chan_enabled(dln2, channel, true);
        if (ret < 0)
-               goto release_direct;
+               return ret;
 
        ret = dln2_adc_set_port_enabled(dln2, true, &conflict);
        if (ret < 0) {
@@ -300,8 +295,6 @@ disable_port:
        dln2_adc_set_port_enabled(dln2, false, NULL);
 disable_chan:
        dln2_adc_set_chan_enabled(dln2, channel, false);
-release_direct:
-       iio_device_release_direct_mode(indio_dev);
 
        return ret;
 }
@@ -337,10 +330,16 @@ static int dln2_adc_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret < 0)
+                       return ret;
+
                mutex_lock(&dln2->mutex);
                ret = dln2_adc_read(dln2, chan->channel);
                mutex_unlock(&dln2->mutex);
 
+               iio_device_release_direct_mode(indio_dev);
+
                if (ret < 0)
                        return ret;
 
@@ -656,7 +655,11 @@ static int dln2_adc_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        iio_trigger_set_drvdata(dln2->trig, dln2);
-       devm_iio_trigger_register(dev, dln2->trig);
+       ret = devm_iio_trigger_register(dev, dln2->trig);
+       if (ret) {
+               dev_err(dev, "failed to register trigger: %d\n", ret);
+               return ret;
+       }
        iio_trigger_set_immutable(indio_dev, dln2->trig);
 
        ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
index 6245434..8cd258c 100644 (file)
@@ -1117,6 +1117,7 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
 {
        struct stm32_adc *adc = iio_priv(indio_dev);
 
+       stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
        stm32h7_adc_disable(indio_dev);
        stm32_adc_int_ch_disable(adc);
        stm32h7_adc_enter_pwr_down(adc);
@@ -1986,7 +1987,7 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n
                        /* Get calibration data for vrefint channel */
                        ret = nvmem_cell_read_u16(&indio_dev->dev, "vrefint", &vrefint);
                        if (ret && ret != -ENOENT) {
-                               return dev_err_probe(&indio_dev->dev, ret,
+                               return dev_err_probe(indio_dev->dev.parent, ret,
                                                     "nvmem access error\n");
                        }
                        if (ret == -ENOENT)
index 3e0734d..600e972 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -124,7 +125,7 @@ static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *
                goto err_unlock;
        }
 
-       *val = temp;
+       *val = sign_extend32(temp, 15);
 
 err_unlock:
        mutex_unlock(&st->lock);
@@ -146,7 +147,7 @@ static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val)
        }
 
        /* extract lower 12 bits temperature reading */
-       *val = temp & 0x0FFF;
+       *val = sign_extend32(temp, 11);
 
 err_unlock:
        mutex_unlock(&st->lock);
index 04dd6a7..4cfa0d4 100644 (file)
@@ -61,9 +61,9 @@ static irqreturn_t itg3200_trigger_handler(int irq, void *p)
 
        iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp);
 
+error_ret:
        iio_trigger_notify_done(indio_dev->trig);
 
-error_ret:
        return IRQ_HANDLED;
 }
 
index b23caa2..93990ff 100644 (file)
@@ -556,7 +556,6 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
                irq_modify_status(trig->subirq_base + i,
                                  IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
        }
-       get_device(&trig->dev);
 
        return trig;
 
index 7e51aaa..b2983b1 100644 (file)
@@ -1275,7 +1275,7 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
                ret = regmap_bulk_read(data->regmap, LTR501_ALS_DATA1,
                                       als_buf, sizeof(als_buf));
                if (ret < 0)
-                       return ret;
+                       goto done;
                if (test_bit(0, indio_dev->active_scan_mask))
                        scan.channels[j++] = le16_to_cpu(als_buf[1]);
                if (test_bit(1, indio_dev->active_scan_mask))
index 07e9184..fc63856 100644 (file)
@@ -546,9 +546,8 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
        mutex_lock(&data->lock);
        ret = regmap_field_read(data->reg_flag_nf, &dir);
        if (ret < 0) {
-               dev_err(&data->client->dev, "register read failed\n");
-               mutex_unlock(&data->lock);
-               return ret;
+               dev_err(&data->client->dev, "register read failed: %d\n", ret);
+               goto out;
        }
        event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
                                     IIO_EV_TYPE_THRESH,
@@ -560,6 +559,7 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
        ret = regmap_field_write(data->reg_flag_psint, 0);
        if (ret < 0)
                dev_err(&data->client->dev, "failed to reset interrupts\n");
+out:
        mutex_unlock(&data->lock);
 
        return IRQ_HANDLED;
index 3308387..4353b74 100644 (file)
@@ -912,6 +912,6 @@ static struct platform_driver stm32_timer_trigger_driver = {
 };
 module_platform_driver(stm32_timer_trigger_driver);
 
-MODULE_ALIAS("platform: stm32-timer-trigger");
+MODULE_ALIAS("platform:stm32-timer-trigger");
 MODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver");
 MODULE_LICENSE("GPL v2");
index ec37f4f..f1245c9 100644 (file)
@@ -8415,6 +8415,8 @@ static void receive_interrupt_common(struct hfi1_ctxtdata *rcd)
  */
 static void __hfi1_rcd_eoi_intr(struct hfi1_ctxtdata *rcd)
 {
+       if (!rcd->rcvhdrq)
+               return;
        clear_recv_intr(rcd);
        if (check_packet_present(rcd))
                force_recv_intr(rcd);
index 61f341c..e2c634a 100644 (file)
@@ -1012,6 +1012,8 @@ int handle_receive_interrupt(struct hfi1_ctxtdata *rcd, int thread)
        struct hfi1_packet packet;
        int skip_pkt = 0;
 
+       if (!rcd->rcvhdrq)
+               return RCV_PKT_OK;
        /* Control context will always use the slow path interrupt handler */
        needset = (rcd->ctxt == HFI1_CTRL_CTXT) ? 0 : 1;
 
index dbd1c31..4436ed4 100644 (file)
@@ -113,7 +113,6 @@ static int hfi1_create_kctxt(struct hfi1_devdata *dd,
        rcd->fast_handler = get_dma_rtail_setting(rcd) ?
                                handle_receive_interrupt_dma_rtail :
                                handle_receive_interrupt_nodma_rtail;
-       rcd->slow_handler = handle_receive_interrupt;
 
        hfi1_set_seq_cnt(rcd, 1);
 
@@ -334,6 +333,8 @@ int hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, int numa,
                rcd->numa_id = numa;
                rcd->rcv_array_groups = dd->rcv_entries.ngroups;
                rcd->rhf_rcv_function_map = normal_rhf_rcv_functions;
+               rcd->slow_handler = handle_receive_interrupt;
+               rcd->do_interrupt = rcd->slow_handler;
                rcd->msix_intr = CCE_NUM_MSIX_VECTORS;
 
                mutex_init(&rcd->exp_mutex);
@@ -874,18 +875,6 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
        if (ret)
                goto done;
 
-       /* allocate dummy tail memory for all receive contexts */
-       dd->rcvhdrtail_dummy_kvaddr = dma_alloc_coherent(&dd->pcidev->dev,
-                                                        sizeof(u64),
-                                                        &dd->rcvhdrtail_dummy_dma,
-                                                        GFP_KERNEL);
-
-       if (!dd->rcvhdrtail_dummy_kvaddr) {
-               dd_dev_err(dd, "cannot allocate dummy tail memory\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-
        /* dd->rcd can be NULL if early initialization failed */
        for (i = 0; dd->rcd && i < dd->first_dyn_alloc_ctxt; ++i) {
                /*
@@ -898,8 +887,6 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit)
                if (!rcd)
                        continue;
 
-               rcd->do_interrupt = &handle_receive_interrupt;
-
                lastfail = hfi1_create_rcvhdrq(dd, rcd);
                if (!lastfail)
                        lastfail = hfi1_setup_eagerbufs(rcd);
@@ -1120,7 +1107,7 @@ void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd)
        rcd->egrbufs.rcvtids = NULL;
 
        for (e = 0; e < rcd->egrbufs.alloced; e++) {
-               if (rcd->egrbufs.buffers[e].dma)
+               if (rcd->egrbufs.buffers[e].addr)
                        dma_free_coherent(&dd->pcidev->dev,
                                          rcd->egrbufs.buffers[e].len,
                                          rcd->egrbufs.buffers[e].addr,
@@ -1201,6 +1188,11 @@ void hfi1_free_devdata(struct hfi1_devdata *dd)
        dd->tx_opstats    = NULL;
        kfree(dd->comp_vect);
        dd->comp_vect = NULL;
+       if (dd->rcvhdrtail_dummy_kvaddr)
+               dma_free_coherent(&dd->pcidev->dev, sizeof(u64),
+                                 (void *)dd->rcvhdrtail_dummy_kvaddr,
+                                 dd->rcvhdrtail_dummy_dma);
+       dd->rcvhdrtail_dummy_kvaddr = NULL;
        sdma_clean(dd, dd->num_sdma);
        rvt_dealloc_device(&dd->verbs_dev.rdi);
 }
@@ -1298,6 +1290,15 @@ static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
                goto bail;
        }
 
+       /* allocate dummy tail memory for all receive contexts */
+       dd->rcvhdrtail_dummy_kvaddr =
+               dma_alloc_coherent(&dd->pcidev->dev, sizeof(u64),
+                                  &dd->rcvhdrtail_dummy_dma, GFP_KERNEL);
+       if (!dd->rcvhdrtail_dummy_kvaddr) {
+               ret = -ENOMEM;
+               goto bail;
+       }
+
        atomic_set(&dd->ipoib_rsm_usr_num, 0);
        return dd;
 
@@ -1505,13 +1506,6 @@ static void cleanup_device_data(struct hfi1_devdata *dd)
 
        free_credit_return(dd);
 
-       if (dd->rcvhdrtail_dummy_kvaddr) {
-               dma_free_coherent(&dd->pcidev->dev, sizeof(u64),
-                                 (void *)dd->rcvhdrtail_dummy_kvaddr,
-                                 dd->rcvhdrtail_dummy_dma);
-               dd->rcvhdrtail_dummy_kvaddr = NULL;
-       }
-
        /*
         * Free any resources still in use (usually just kernel contexts)
         * at unload; we do for ctxtcnt, because that's what we allocate.
index 2b6c24b..f07d328 100644 (file)
@@ -838,8 +838,8 @@ struct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd,
        if (current->nr_cpus_allowed != 1)
                goto out;
 
-       cpu_id = smp_processor_id();
        rcu_read_lock();
+       cpu_id = smp_processor_id();
        rht_node = rhashtable_lookup(dd->sdma_rht, &cpu_id,
                                     sdma_rht_params);
 
index 9bfbadd..bbfa133 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/acpi.h>
 #include <linux/etherdevice.h>
 #include <linux/interrupt.h>
+#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <net/addrconf.h>
@@ -1050,9 +1051,14 @@ static u32 hns_roce_v2_cmd_hw_resetting(struct hns_roce_dev *hr_dev,
                                        unsigned long instance_stage,
                                        unsigned long reset_stage)
 {
+#define HW_RESET_TIMEOUT_US 1000000
+#define HW_RESET_SLEEP_US 1000
+
        struct hns_roce_v2_priv *priv = hr_dev->priv;
        struct hnae3_handle *handle = priv->handle;
        const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
+       unsigned long val;
+       int ret;
 
        /* When hardware reset is detected, we should stop sending mailbox&cmq&
         * doorbell to hardware. If now in .init_instance() function, we should
@@ -1064,7 +1070,11 @@ static u32 hns_roce_v2_cmd_hw_resetting(struct hns_roce_dev *hr_dev,
         * again.
         */
        hr_dev->dis_db = true;
-       if (!ops->get_hw_reset_stat(handle))
+
+       ret = read_poll_timeout(ops->ae_dev_reset_cnt, val,
+                               val > hr_dev->reset_cnt, HW_RESET_SLEEP_US,
+                               HW_RESET_TIMEOUT_US, false, handle);
+       if (!ret)
                hr_dev->is_reset = true;
 
        if (!hr_dev->is_reset || reset_stage == HNS_ROCE_STATE_RST_INIT ||
@@ -6387,10 +6397,8 @@ static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle)
        if (!hr_dev)
                return 0;
 
-       hr_dev->is_reset = true;
        hr_dev->active = false;
        hr_dev->dis_db = true;
-
        hr_dev->state = HNS_ROCE_DEVICE_STATE_RST_DOWN;
 
        return 0;
index 4108dca..b4c657f 100644 (file)
@@ -60,6 +60,8 @@ static void irdma_iwarp_ce_handler(struct irdma_sc_cq *iwcq)
 {
        struct irdma_cq *cq = iwcq->back_cq;
 
+       if (!cq->user_mode)
+               cq->armed = false;
        if (cq->ibcq.comp_handler)
                cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
 }
@@ -146,6 +148,7 @@ static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
                qp->flush_code = FLUSH_PROT_ERR;
                break;
        case IRDMA_AE_AMP_BAD_QP:
+       case IRDMA_AE_WQE_UNEXPECTED_OPCODE:
                qp->flush_code = FLUSH_LOC_QP_OP_ERR;
                break;
        case IRDMA_AE_AMP_BAD_STAG_KEY:
@@ -156,7 +159,6 @@ static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
        case IRDMA_AE_PRIV_OPERATION_DENIED:
        case IRDMA_AE_IB_INVALID_REQUEST:
        case IRDMA_AE_IB_REMOTE_ACCESS_ERROR:
-       case IRDMA_AE_IB_REMOTE_OP_ERROR:
                qp->flush_code = FLUSH_REM_ACCESS_ERR;
                qp->event_type = IRDMA_QP_EVENT_ACCESS_ERR;
                break;
@@ -184,6 +186,9 @@ static void irdma_set_flush_fields(struct irdma_sc_qp *qp,
        case IRDMA_AE_AMP_MWBIND_INVALID_BOUNDS:
                qp->flush_code = FLUSH_MW_BIND_ERR;
                break;
+       case IRDMA_AE_IB_REMOTE_OP_ERROR:
+               qp->flush_code = FLUSH_REM_OP_ERR;
+               break;
        default:
                qp->flush_code = FLUSH_FATAL_ERR;
                break;
index 91a4971..cb218ca 100644 (file)
@@ -542,6 +542,7 @@ int irdma_ah_cqp_op(struct irdma_pci_f *rf, struct irdma_sc_ah *sc_ah, u8 cmd,
                    void (*callback_fcn)(struct irdma_cqp_request *cqp_request),
                    void *cb_param);
 void irdma_gsi_ud_qp_ah_cb(struct irdma_cqp_request *cqp_request);
+bool irdma_cq_empty(struct irdma_cq *iwcq);
 int irdma_inetaddr_event(struct notifier_block *notifier, unsigned long event,
                         void *ptr);
 int irdma_inet6addr_event(struct notifier_block *notifier, unsigned long event,
index aeeb1c3..fed49da 100644 (file)
@@ -25,8 +25,7 @@ void irdma_destroy_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
                list_del(&chunk->list);
                if (chunk->type == PBLE_SD_PAGED)
                        irdma_pble_free_paged_mem(chunk);
-               if (chunk->bitmapbuf)
-                       kfree(chunk->bitmapmem.va);
+               bitmap_free(chunk->bitmapbuf);
                kfree(chunk->chunkmem.va);
        }
 }
@@ -283,7 +282,6 @@ add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
                  "PBLE: next_fpm_addr = %llx chunk_size[%llu] = 0x%llx\n",
                  pble_rsrc->next_fpm_addr, chunk->size, chunk->size);
        pble_rsrc->unallocated_pble -= (u32)(chunk->size >> 3);
-       list_add(&chunk->list, &pble_rsrc->pinfo.clist);
        sd_reg_val = (sd_entry_type == IRDMA_SD_TYPE_PAGED) ?
                             sd_entry->u.pd_table.pd_page_addr.pa :
                             sd_entry->u.bp.addr.pa;
@@ -295,12 +293,12 @@ add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
                        goto error;
        }
 
+       list_add(&chunk->list, &pble_rsrc->pinfo.clist);
        sd_entry->valid = true;
        return 0;
 
 error:
-       if (chunk->bitmapbuf)
-               kfree(chunk->bitmapmem.va);
+       bitmap_free(chunk->bitmapbuf);
        kfree(chunk->chunkmem.va);
 
        return ret_code;
index e1b3b81..aa20827 100644 (file)
@@ -78,7 +78,6 @@ struct irdma_chunk {
        u32 pg_cnt;
        enum irdma_alloc_type type;
        struct irdma_sc_dev *dev;
-       struct irdma_virt_mem bitmapmem;
        struct irdma_virt_mem chunkmem;
 };
 
index 8b42c43..398736d 100644 (file)
@@ -2239,15 +2239,10 @@ enum irdma_status_code irdma_prm_add_pble_mem(struct irdma_pble_prm *pprm,
 
        sizeofbitmap = (u64)pchunk->size >> pprm->pble_shift;
 
-       pchunk->bitmapmem.size = sizeofbitmap >> 3;
-       pchunk->bitmapmem.va = kzalloc(pchunk->bitmapmem.size, GFP_KERNEL);
-
-       if (!pchunk->bitmapmem.va)
+       pchunk->bitmapbuf = bitmap_zalloc(sizeofbitmap, GFP_KERNEL);
+       if (!pchunk->bitmapbuf)
                return IRDMA_ERR_NO_MEMORY;
 
-       pchunk->bitmapbuf = pchunk->bitmapmem.va;
-       bitmap_zero(pchunk->bitmapbuf, sizeofbitmap);
-
        pchunk->sizeofbitmap = sizeofbitmap;
        /* each pble is 8 bytes hence shift by 3 */
        pprm->total_pble_alloc += pchunk->size >> 3;
@@ -2491,3 +2486,18 @@ void irdma_ib_qp_event(struct irdma_qp *iwqp, enum irdma_qp_event_type event)
        ibevent.element.qp = &iwqp->ibqp;
        iwqp->ibqp.event_handler(&ibevent, iwqp->ibqp.qp_context);
 }
+
+bool irdma_cq_empty(struct irdma_cq *iwcq)
+{
+       struct irdma_cq_uk *ukcq;
+       u64 qword3;
+       __le64 *cqe;
+       u8 polarity;
+
+       ukcq  = &iwcq->sc_cq.cq_uk;
+       cqe = IRDMA_GET_CURRENT_CQ_ELEM(ukcq);
+       get_64bit_val(cqe, 24, &qword3);
+       polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3);
+
+       return polarity != ukcq->polarity;
+}
index 0f66e80..8cd5f92 100644 (file)
@@ -3584,18 +3584,31 @@ static int irdma_req_notify_cq(struct ib_cq *ibcq,
        struct irdma_cq *iwcq;
        struct irdma_cq_uk *ukcq;
        unsigned long flags;
-       enum irdma_cmpl_notify cq_notify = IRDMA_CQ_COMPL_EVENT;
+       enum irdma_cmpl_notify cq_notify;
+       bool promo_event = false;
+       int ret = 0;
 
+       cq_notify = notify_flags == IB_CQ_SOLICITED ?
+                   IRDMA_CQ_COMPL_SOLICITED : IRDMA_CQ_COMPL_EVENT;
        iwcq = to_iwcq(ibcq);
        ukcq = &iwcq->sc_cq.cq_uk;
-       if (notify_flags == IB_CQ_SOLICITED)
-               cq_notify = IRDMA_CQ_COMPL_SOLICITED;
 
        spin_lock_irqsave(&iwcq->lock, flags);
-       irdma_uk_cq_request_notification(ukcq, cq_notify);
+       /* Only promote to arm the CQ for any event if the last arm event was solicited. */
+       if (iwcq->last_notify == IRDMA_CQ_COMPL_SOLICITED && notify_flags != IB_CQ_SOLICITED)
+               promo_event = true;
+
+       if (!iwcq->armed || promo_event) {
+               iwcq->armed = true;
+               iwcq->last_notify = cq_notify;
+               irdma_uk_cq_request_notification(ukcq, cq_notify);
+       }
+
+       if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) && !irdma_cq_empty(iwcq))
+               ret = 1;
        spin_unlock_irqrestore(&iwcq->lock, flags);
 
-       return 0;
+       return ret;
 }
 
 static int irdma_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
index 5c244cd..d0fdef8 100644 (file)
@@ -110,6 +110,8 @@ struct irdma_cq {
        u16 cq_size;
        u16 cq_num;
        bool user_mode;
+       bool armed;
+       enum irdma_cmpl_notify last_notify;
        u32 polled_cmpls;
        u32 cq_mem_size;
        struct irdma_dma_mem kmem;
index e636e95..4a7a56e 100644 (file)
@@ -664,7 +664,6 @@ struct mlx5_ib_mr {
 
        /* User MR data */
        struct mlx5_cache_ent *cache_ent;
-       struct ib_umem *umem;
 
        /* This is zero'd when the MR is allocated */
        union {
@@ -676,7 +675,7 @@ struct mlx5_ib_mr {
                        struct list_head list;
                };
 
-               /* Used only by kernel MRs (umem == NULL) */
+               /* Used only by kernel MRs */
                struct {
                        void *descs;
                        void *descs_alloc;
@@ -697,8 +696,9 @@ struct mlx5_ib_mr {
                        int data_length;
                };
 
-               /* Used only by User MRs (umem != NULL) */
+               /* Used only by User MRs */
                struct {
+                       struct ib_umem *umem;
                        unsigned int page_shift;
                        /* Current access_flags */
                        int access_flags;
index 157d862..63e2129 100644 (file)
@@ -1904,19 +1904,18 @@ err:
        return ret;
 }
 
-static void
-mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
+static void mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
 {
-       if (!mr->umem && mr->descs) {
-               struct ib_device *device = mr->ibmr.device;
-               int size = mr->max_descs * mr->desc_size;
-               struct mlx5_ib_dev *dev = to_mdev(device);
+       struct mlx5_ib_dev *dev = to_mdev(mr->ibmr.device);
+       int size = mr->max_descs * mr->desc_size;
 
-               dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
-                                DMA_TO_DEVICE);
-               kfree(mr->descs_alloc);
-               mr->descs = NULL;
-       }
+       if (!mr->descs)
+               return;
+
+       dma_unmap_single(&dev->mdev->pdev->dev, mr->desc_map, size,
+                        DMA_TO_DEVICE);
+       kfree(mr->descs_alloc);
+       mr->descs = NULL;
 }
 
 int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
@@ -1992,7 +1991,8 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
        if (mr->cache_ent) {
                mlx5_mr_cache_free(dev, mr);
        } else {
-               mlx5_free_priv_descs(mr);
+               if (!udata)
+                       mlx5_free_priv_descs(mr);
                kfree(mr);
        }
        return 0;
@@ -2079,7 +2079,6 @@ static struct mlx5_ib_mr *mlx5_ib_alloc_pi_mr(struct ib_pd *pd,
        if (err)
                goto err_free_in;
 
-       mr->umem = NULL;
        kfree(in);
 
        return mr;
@@ -2206,7 +2205,6 @@ static struct ib_mr *__mlx5_ib_alloc_mr(struct ib_pd *pd,
        }
 
        mr->ibmr.device = pd->device;
-       mr->umem = NULL;
 
        switch (mr_type) {
        case IB_MR_TYPE_MEM_REG:
index 9753218..54b8711 100644 (file)
@@ -359,6 +359,7 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
 
 err2:
        rxe_queue_cleanup(qp->sq.queue);
+       qp->sq.queue = NULL;
 err1:
        qp->pd = NULL;
        qp->rcq = NULL;
index f7e459f..76e4352 100644 (file)
@@ -19,7 +19,7 @@ void rtrs_clt_update_wc_stats(struct rtrs_clt_con *con)
        int cpu;
 
        cpu = raw_smp_processor_id();
-       s = this_cpu_ptr(stats->pcpu_stats);
+       s = get_cpu_ptr(stats->pcpu_stats);
        if (con->cpu != cpu) {
                s->cpu_migr.to++;
 
@@ -27,14 +27,16 @@ void rtrs_clt_update_wc_stats(struct rtrs_clt_con *con)
                s = per_cpu_ptr(stats->pcpu_stats, con->cpu);
                atomic_inc(&s->cpu_migr.from);
        }
+       put_cpu_ptr(stats->pcpu_stats);
 }
 
 void rtrs_clt_inc_failover_cnt(struct rtrs_clt_stats *stats)
 {
        struct rtrs_clt_stats_pcpu *s;
 
-       s = this_cpu_ptr(stats->pcpu_stats);
+       s = get_cpu_ptr(stats->pcpu_stats);
        s->rdma.failover_cnt++;
+       put_cpu_ptr(stats->pcpu_stats);
 }
 
 int rtrs_clt_stats_migration_from_cnt_to_str(struct rtrs_clt_stats *stats, char *buf)
@@ -169,9 +171,10 @@ static inline void rtrs_clt_update_rdma_stats(struct rtrs_clt_stats *stats,
 {
        struct rtrs_clt_stats_pcpu *s;
 
-       s = this_cpu_ptr(stats->pcpu_stats);
+       s = get_cpu_ptr(stats->pcpu_stats);
        s->rdma.dir[d].cnt++;
        s->rdma.dir[d].size_total += size;
+       put_cpu_ptr(stats->pcpu_stats);
 }
 
 void rtrs_clt_update_all_stats(struct rtrs_clt_io_req *req, int dir)
index 3759dc3..2543ef6 100644 (file)
@@ -707,7 +707,7 @@ static const struct irq_domain_ops aic_ipi_domain_ops = {
        .free = aic_ipi_free,
 };
 
-static int aic_init_smp(struct aic_irq_chip *irqc, struct device_node *node)
+static int __init aic_init_smp(struct aic_irq_chip *irqc, struct device_node *node)
 {
        struct irq_domain *ipi_domain;
        int base_ipi;
index 80906bf..5b8d571 100644 (file)
@@ -232,16 +232,12 @@ static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
        int hwirq, i;
 
        mutex_lock(&msi_used_lock);
+       hwirq = bitmap_find_free_region(msi_used, PCI_MSI_DOORBELL_NR,
+                                       order_base_2(nr_irqs));
+       mutex_unlock(&msi_used_lock);
 
-       hwirq = bitmap_find_next_zero_area(msi_used, PCI_MSI_DOORBELL_NR,
-                                          0, nr_irqs, 0);
-       if (hwirq >= PCI_MSI_DOORBELL_NR) {
-               mutex_unlock(&msi_used_lock);
+       if (hwirq < 0)
                return -ENOSPC;
-       }
-
-       bitmap_set(msi_used, hwirq, nr_irqs);
-       mutex_unlock(&msi_used_lock);
 
        for (i = 0; i < nr_irqs; i++) {
                irq_domain_set_info(domain, virq + i, hwirq + i,
@@ -250,7 +246,7 @@ static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
                                    NULL, NULL);
        }
 
-       return hwirq;
+       return 0;
 }
 
 static void armada_370_xp_msi_free(struct irq_domain *domain,
@@ -259,7 +255,7 @@ static void armada_370_xp_msi_free(struct irq_domain *domain,
        struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 
        mutex_lock(&msi_used_lock);
-       bitmap_clear(msi_used, d->hwirq, nr_irqs);
+       bitmap_release_region(msi_used, d->hwirq, order_base_2(nr_irqs));
        mutex_unlock(&msi_used_lock);
 }
 
index f3c6855..18b77c3 100644 (file)
@@ -76,8 +76,8 @@ static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
                generic_handle_domain_irq(scu_ic->irq_domain,
                                          bit - scu_ic->irq_shift);
 
-               regmap_update_bits(scu_ic->scu, scu_ic->reg, mask,
-                                  BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
+               regmap_write_bits(scu_ic->scu, scu_ic->reg, mask,
+                                 BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
        }
 
        chained_irq_exit(chip, desc);
index d80e67a..bb6609c 100644 (file)
@@ -238,6 +238,7 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
        }
 
        data->num_parent_irqs = platform_irq_count(pdev);
+       put_device(&pdev->dev);
        if (data->num_parent_irqs <= 0) {
                pr_err("invalid number of parent interrupts\n");
                ret = -ENOMEM;
index eb0882d..0cb584d 100644 (file)
@@ -742,7 +742,7 @@ static struct its_collection *its_build_invall_cmd(struct its_node *its,
 
        its_fixup_cmd(cmd);
 
-       return NULL;
+       return desc->its_invall_cmd.col;
 }
 
 static struct its_vpe *its_build_vinvall_cmd(struct its_node *its,
index d02b05a..ff89b36 100644 (file)
@@ -9,6 +9,7 @@
 
 #define pr_fmt(fmt) "irq-mips-gic: " fmt
 
+#include <linux/bitfield.h>
 #include <linux/bitmap.h>
 #include <linux/clocksource.h>
 #include <linux/cpuhotplug.h>
@@ -735,8 +736,7 @@ static int __init gic_of_init(struct device_node *node,
        mips_gic_base = ioremap(gic_base, gic_len);
 
        gicconfig = read_gic_config();
-       gic_shared_intrs = gicconfig & GIC_CONFIG_NUMINTERRUPTS;
-       gic_shared_intrs >>= __ffs(GIC_CONFIG_NUMINTERRUPTS);
+       gic_shared_intrs = FIELD_GET(GIC_CONFIG_NUMINTERRUPTS, gicconfig);
        gic_shared_intrs = (gic_shared_intrs + 1) * 8;
 
        if (cpu_has_veic) {
index 63bac3f..ba4759b 100644 (file)
@@ -26,7 +26,7 @@
 
 #define NVIC_ISER              0x000
 #define NVIC_ICER              0x080
-#define NVIC_IPR               0x300
+#define NVIC_IPR               0x400
 
 #define NVIC_MAX_BANKS         16
 /*
index 86b9e35..140f35d 100644 (file)
@@ -1139,6 +1139,7 @@ static void cancel_writeback_rate_update_dwork(struct cached_dev *dc)
 static void cached_dev_detach_finish(struct work_struct *w)
 {
        struct cached_dev *dc = container_of(w, struct cached_dev, detach);
+       struct cache_set *c = dc->disk.c;
 
        BUG_ON(!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags));
        BUG_ON(refcount_read(&dc->count));
@@ -1156,7 +1157,7 @@ static void cached_dev_detach_finish(struct work_struct *w)
 
        bcache_device_detach(&dc->disk);
        list_move(&dc->list, &uncached_devices);
-       calc_cached_dev_sectors(dc->disk.c);
+       calc_cached_dev_sectors(c);
 
        clear_bit(BCACHE_DEV_DETACHING, &dc->disk.flags);
        clear_bit(BCACHE_DEV_UNLINK_DONE, &dc->disk.flags);
index 6319dec..7af242d 100644 (file)
@@ -1963,7 +1963,7 @@ static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
                n_sectors -= bv.bv_len >> SECTOR_SHIFT;
                bio_advance_iter(bio, &bio->bi_iter, bv.bv_len);
 retry_kmap:
-               mem = bvec_kmap_local(&bv);
+               mem = kmap_local_page(bv.bv_page);
                if (likely(dio->op == REQ_OP_WRITE))
                        flush_dcache_page(bv.bv_page);
 
index 5111ed9..41d6e23 100644 (file)
@@ -2189,6 +2189,7 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
 
                if (!num_sectors || num_sectors > max_sectors)
                        num_sectors = max_sectors;
+               rdev->sb_start = sb_start;
        }
        sb = page_address(rdev->sb_page);
        sb->data_size = cpu_to_le64(num_sectors);
@@ -6270,7 +6271,8 @@ static void __md_stop(struct mddev *mddev)
        spin_lock(&mddev->lock);
        mddev->pers = NULL;
        spin_unlock(&mddev->lock);
-       pers->free(mddev, mddev->private);
+       if (mddev->private)
+               pers->free(mddev, mddev->private);
        mddev->private = NULL;
        if (pers->sync_request && mddev->to_remove == NULL)
                mddev->to_remove = &md_redundancy_group;
index 7053233..cb670f1 100644 (file)
@@ -423,9 +423,9 @@ static int rebalance_children(struct shadow_spine *s,
 
                memcpy(n, dm_block_data(child),
                       dm_bm_block_size(dm_tm_get_bm(info->tm)));
-               dm_tm_unlock(info->tm, child);
 
                dm_tm_dec(info->tm, dm_block_location(child));
+               dm_tm_unlock(info->tm, child);
                return 0;
        }
 
index 8c72eb5..6ac509c 100644 (file)
@@ -1803,8 +1803,6 @@ static int rtsx_pci_runtime_suspend(struct device *device)
        mutex_lock(&pcr->pcr_mutex);
        rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
-       free_irq(pcr->irq, (void *)pcr);
-
        mutex_unlock(&pcr->pcr_mutex);
 
        pcr->is_runtime_suspended = true;
@@ -1825,8 +1823,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
        mutex_lock(&pcr->pcr_mutex);
 
        rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
-       rtsx_pci_acquire_irq(pcr);
-       synchronize_irq(pcr->irq);
 
        if (pcr->ops->fetch_vendor_settings)
                pcr->ops->fetch_vendor_settings(pcr);
index 6323254..b38978a 100644 (file)
@@ -376,7 +376,6 @@ MODULE_DEVICE_TABLE(spi, at25_spi_ids);
 static int at25_probe(struct spi_device *spi)
 {
        struct at25_data        *at25 = NULL;
-       struct spi_eeprom       chip;
        int                     err;
        int                     sr;
        u8 id[FM25_ID_LEN];
@@ -389,15 +388,18 @@ static int at25_probe(struct spi_device *spi)
        if (match && !strcmp(match->compatible, "cypress,fm25"))
                is_fram = 1;
 
+       at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
+       if (!at25)
+               return -ENOMEM;
+
        /* Chip description */
-       if (!spi->dev.platform_data) {
-               if (!is_fram) {
-                       err = at25_fw_to_chip(&spi->dev, &chip);
-                       if (err)
-                               return err;
-               }
-       } else
-               chip = *(struct spi_eeprom *)spi->dev.platform_data;
+       if (spi->dev.platform_data) {
+               memcpy(&at25->chip, spi->dev.platform_data, sizeof(at25->chip));
+       } else if (!is_fram) {
+               err = at25_fw_to_chip(&spi->dev, &at25->chip);
+               if (err)
+                       return err;
+       }
 
        /* Ping the chip ... the status register is pretty portable,
         * unlike probing manufacturer IDs.  We do expect that system
@@ -409,12 +411,7 @@ static int at25_probe(struct spi_device *spi)
                return -ENXIO;
        }
 
-       at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);
-       if (!at25)
-               return -ENOMEM;
-
        mutex_init(&at25->lock);
-       at25->chip = chip;
        at25->spi = spi;
        spi_set_drvdata(spi, at25);
 
@@ -431,7 +428,7 @@ static int at25_probe(struct spi_device *spi)
                        dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]);
                        return -ENODEV;
                }
-               chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
+               at25->chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024;
 
                if (at25->chip.byte_len > 64 * 1024)
                        at25->chip.flags |= EE_ADDR3;
@@ -464,7 +461,7 @@ static int at25_probe(struct spi_device *spi)
        at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM;
        at25->nvmem_config.name = dev_name(&spi->dev);
        at25->nvmem_config.dev = &spi->dev;
-       at25->nvmem_config.read_only = chip.flags & EE_READONLY;
+       at25->nvmem_config.read_only = at25->chip.flags & EE_READONLY;
        at25->nvmem_config.root_only = true;
        at25->nvmem_config.owner = THIS_MODULE;
        at25->nvmem_config.compat = true;
@@ -474,17 +471,18 @@ static int at25_probe(struct spi_device *spi)
        at25->nvmem_config.priv = at25;
        at25->nvmem_config.stride = 1;
        at25->nvmem_config.word_size = 1;
-       at25->nvmem_config.size = chip.byte_len;
+       at25->nvmem_config.size = at25->chip.byte_len;
 
        at25->nvmem = devm_nvmem_register(&spi->dev, &at25->nvmem_config);
        if (IS_ERR(at25->nvmem))
                return PTR_ERR(at25->nvmem);
 
        dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n",
-                (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024),
-                (chip.byte_len < 1024) ? "Byte" : "KByte",
+                (at25->chip.byte_len < 1024) ?
+                       at25->chip.byte_len : (at25->chip.byte_len / 1024),
+                (at25->chip.byte_len < 1024) ? "Byte" : "KByte",
                 at25->chip.name, is_fram ? "fram" : "eeprom",
-                (chip.flags & EE_READONLY) ? " (readonly)" : "",
+                (at25->chip.flags & EE_READONLY) ? " (readonly)" : "",
                 at25->chip.page_size);
        return 0;
 }
index 39aca77..4ccbf43 100644 (file)
@@ -719,16 +719,18 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
 static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen)
 {
        u64 size = 0;
-       int i;
+       int oix;
 
        size = ALIGN(metalen, FASTRPC_ALIGN);
-       for (i = 0; i < ctx->nscalars; i++) {
+       for (oix = 0; oix < ctx->nbufs; oix++) {
+               int i = ctx->olaps[oix].raix;
+
                if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) {
 
-                       if (ctx->olaps[i].offset == 0)
+                       if (ctx->olaps[oix].offset == 0)
                                size = ALIGN(size, FASTRPC_ALIGN);
 
-                       size += (ctx->olaps[i].mend - ctx->olaps[i].mstart);
+                       size += (ctx->olaps[oix].mend - ctx->olaps[oix].mstart);
                }
        }
 
index 943940b..6327752 100644 (file)
@@ -2291,8 +2291,10 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card
                        sdr_set_field(host->base + PAD_DS_TUNE,
                                      PAD_DS_TUNE_DLY1, i);
                ret = mmc_get_ext_csd(card, &ext_csd);
-               if (!ret)
+               if (!ret) {
                        result_dly1 |= (1 << i);
+                       kfree(ext_csd);
+               }
        }
        host->hs400_tuning = false;
 
index a4407f3..f5b2684 100644 (file)
@@ -673,7 +673,7 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
        /* Issue CMD19 twice for each tap */
        for (i = 0; i < 2 * priv->tap_num; i++) {
-               int cmd_error;
+               int cmd_error = 0;
 
                /* Set sampling clock position */
                sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, i % priv->tap_num);
index 9802e26..2b317ed 100644 (file)
@@ -96,6 +96,13 @@ struct dataflash {
        struct mtd_info         mtd;
 };
 
+static const struct spi_device_id dataflash_dev_ids[] = {
+       { "at45" },
+       { "dataflash" },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, dataflash_dev_ids);
+
 #ifdef CONFIG_OF
 static const struct of_device_id dataflash_dt_ids[] = {
        { .compatible = "atmel,at45", },
@@ -927,6 +934,7 @@ static struct spi_driver dataflash_driver = {
                .name           = "mtd_dataflash",
                .of_match_table = of_match_ptr(dataflash_dt_ids),
        },
+       .id_table = dataflash_dev_ids,
 
        .probe          = dataflash_probe,
        .remove         = dataflash_remove,
index 67b7cb6..0a45d3c 100644 (file)
@@ -26,7 +26,7 @@ config MTD_NAND_DENALI_PCI
 config MTD_NAND_DENALI_DT
        tristate "Denali NAND controller as a DT device"
        select MTD_NAND_DENALI
-       depends on HAS_DMA && HAVE_CLK && OF
+       depends on HAS_DMA && HAVE_CLK && OF && HAS_IOMEM
        help
          Enable the driver for NAND flash on platforms using a Denali NAND
          controller as a DT device.
index 658f0cb..6b2bda8 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/clk.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-direction.h>
 #include <linux/dma-mapping.h>
 
 #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
 
+/*
+ * According to SPEAr300 Reference Manual (RM0082)
+ *  TOUDEL = 7ns (Output delay from the flip-flops to the board)
+ *  TINDEL = 5ns (Input delay from the board to the flipflop)
+ */
+#define TOUTDEL        7000
+#define TINDEL 5000
+
 struct fsmc_nand_timings {
        u8 tclr;
        u8 tar;
@@ -277,7 +286,7 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
 {
        unsigned long hclk = clk_get_rate(host->clk);
        unsigned long hclkn = NSEC_PER_SEC / hclk;
-       u32 thiz, thold, twait, tset;
+       u32 thiz, thold, twait, tset, twait_min;
 
        if (sdrt->tRC_min < 30000)
                return -EOPNOTSUPP;
@@ -309,13 +318,6 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
        else if (tims->thold > FSMC_THOLD_MASK)
                tims->thold = FSMC_THOLD_MASK;
 
-       twait = max(sdrt->tRP_min, sdrt->tWP_min);
-       tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
-       if (tims->twait == 0)
-               tims->twait = 1;
-       else if (tims->twait > FSMC_TWAIT_MASK)
-               tims->twait = FSMC_TWAIT_MASK;
-
        tset = max(sdrt->tCS_min - sdrt->tWP_min,
                   sdrt->tCEA_max - sdrt->tREA_max);
        tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
@@ -324,6 +326,21 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
        else if (tims->tset > FSMC_TSET_MASK)
                tims->tset = FSMC_TSET_MASK;
 
+       /*
+        * According to SPEAr300 Reference Manual (RM0082) which gives more
+        * information related to FSMSC timings than the SPEAr600 one (RM0305),
+        *   twait >= tCEA - (tset * TCLK) + TOUTDEL + TINDEL
+        */
+       twait_min = sdrt->tCEA_max - ((tims->tset + 1) * hclkn * 1000)
+                   + TOUTDEL + TINDEL;
+       twait = max3(sdrt->tRP_min, sdrt->tWP_min, twait_min);
+
+       tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+       if (tims->twait == 0)
+               tims->twait = 1;
+       else if (tims->twait > FSMC_TWAIT_MASK)
+               tims->twait = FSMC_TWAIT_MASK;
+
        return 0;
 }
 
@@ -664,6 +681,9 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op,
                                                instr->ctx.waitrdy.timeout_ms);
                        break;
                }
+
+               if (instr->delay_ns)
+                       ndelay(instr->delay_ns);
        }
 
        return ret;
index 3d6c6e8..a130320 100644 (file)
@@ -926,7 +926,7 @@ int nand_choose_best_sdr_timings(struct nand_chip *chip,
                                 struct nand_sdr_timings *spec_timings)
 {
        const struct nand_controller_ops *ops = chip->controller->ops;
-       int best_mode = 0, mode, ret;
+       int best_mode = 0, mode, ret = -EOPNOTSUPP;
 
        iface->type = NAND_SDR_IFACE;
 
@@ -977,7 +977,7 @@ int nand_choose_best_nvddr_timings(struct nand_chip *chip,
                                   struct nand_nvddr_timings *spec_timings)
 {
        const struct nand_controller_ops *ops = chip->controller->ops;
-       int best_mode = 0, mode, ret;
+       int best_mode = 0, mode, ret = -EOPNOTSUPP;
 
        iface->type = NAND_NVDDR_IFACE;
 
@@ -1837,7 +1837,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock)
                        NAND_OP_CMD(NAND_CMD_ERASE1, 0),
                        NAND_OP_ADDR(2, addrs, 0),
                        NAND_OP_CMD(NAND_CMD_ERASE2,
-                                   NAND_COMMON_TIMING_MS(conf, tWB_max)),
+                                   NAND_COMMON_TIMING_NS(conf, tWB_max)),
                        NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tBERS_max),
                                         0),
                };
index 2ec8e01..533e476 100644 (file)
@@ -1501,14 +1501,14 @@ void bond_alb_monitor(struct work_struct *work)
        struct slave *slave;
 
        if (!bond_has_slaves(bond)) {
-               bond_info->tx_rebalance_counter = 0;
+               atomic_set(&bond_info->tx_rebalance_counter, 0);
                bond_info->lp_counter = 0;
                goto re_arm;
        }
 
        rcu_read_lock();
 
-       bond_info->tx_rebalance_counter++;
+       atomic_inc(&bond_info->tx_rebalance_counter);
        bond_info->lp_counter++;
 
        /* send learning packets */
@@ -1530,7 +1530,7 @@ void bond_alb_monitor(struct work_struct *work)
        }
 
        /* rebalance tx traffic */
-       if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) {
+       if (atomic_read(&bond_info->tx_rebalance_counter) >= BOND_TLB_REBALANCE_TICKS) {
                bond_for_each_slave_rcu(bond, slave, iter) {
                        tlb_clear_slave(bond, slave, 1);
                        if (slave == rcu_access_pointer(bond->curr_active_slave)) {
@@ -1540,7 +1540,7 @@ void bond_alb_monitor(struct work_struct *work)
                                bond_info->unbalanced_load = 0;
                        }
                }
-               bond_info->tx_rebalance_counter = 0;
+               atomic_set(&bond_info->tx_rebalance_counter, 0);
        }
 
        if (bond_info->rlb_enabled) {
@@ -1610,7 +1610,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
        tlb_init_slave(slave);
 
        /* order a rebalance ASAP */
-       bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
+       atomic_set(&bond->alb_info.tx_rebalance_counter,
+                  BOND_TLB_REBALANCE_TICKS);
 
        if (bond->alb_info.rlb_enabled)
                bond->alb_info.rlb_rebalance = 1;
@@ -1647,7 +1648,8 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
                        rlb_clear_slave(bond, slave);
        } else if (link == BOND_LINK_UP) {
                /* order a rebalance ASAP */
-               bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
+               atomic_set(&bond_info->tx_rebalance_counter,
+                          BOND_TLB_REBALANCE_TICKS);
                if (bond->alb_info.rlb_enabled) {
                        bond->alb_info.rlb_rebalance = 1;
                        /* If the updelay module parameter is smaller than the
index 74d9899..eb74cdf 100644 (file)
@@ -248,6 +248,9 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
 #define KVASER_PCIEFD_SPACK_EWLR BIT(23)
 #define KVASER_PCIEFD_SPACK_EPLR BIT(24)
 
+/* Kvaser KCAN_EPACK second word */
+#define KVASER_PCIEFD_EPACK_DIR_TX BIT(0)
+
 struct kvaser_pciefd;
 
 struct kvaser_pciefd_can {
@@ -1285,7 +1288,10 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can,
 
        can->err_rep_cnt++;
        can->can.can_stats.bus_error++;
-       stats->rx_errors++;
+       if (p->header[1] & KVASER_PCIEFD_EPACK_DIR_TX)
+               stats->tx_errors++;
+       else
+               stats->rx_errors++;
 
        can->bec.txerr = bec.txerr;
        can->bec.rxerr = bec.rxerr;
index 2470c47..c2a8421 100644 (file)
@@ -204,16 +204,16 @@ enum m_can_reg {
 
 /* Interrupts for version 3.0.x */
 #define IR_ERR_LEC_30X (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
-#define IR_ERR_BUS_30X (IR_ERR_LEC_30X | IR_WDI | IR_ELO | IR_BEU | \
-                        IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
-                        IR_RF1L | IR_RF0L)
+#define IR_ERR_BUS_30X (IR_ERR_LEC_30X | IR_WDI | IR_BEU | IR_BEC | \
+                        IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
+                        IR_RF0L)
 #define IR_ERR_ALL_30X (IR_ERR_STATE | IR_ERR_BUS_30X)
 
 /* Interrupts for version >= 3.1.x */
 #define IR_ERR_LEC_31X (IR_PED | IR_PEA)
-#define IR_ERR_BUS_31X      (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \
-                        IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
-                        IR_RF1L | IR_RF0L)
+#define IR_ERR_BUS_31X      (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \
+                        IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \
+                        IR_RF0L)
 #define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X)
 
 /* Interrupt Line Select (ILS) */
@@ -517,7 +517,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
                err = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DATA,
                                      cf->data, DIV_ROUND_UP(cf->len, 4));
                if (err)
-                       goto out_fail;
+                       goto out_free_skb;
        }
 
        /* acknowledge rx fifo 0 */
@@ -532,6 +532,8 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
 
        return 0;
 
+out_free_skb:
+       kfree_skb(skb);
 out_fail:
        netdev_err(dev, "FIFO read returned %d\n", err);
        return err;
@@ -810,8 +812,6 @@ static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
 {
        if (irqstatus & IR_WDI)
                netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
-       if (irqstatus & IR_ELO)
-               netdev_err(dev, "Error Logging Overflow\n");
        if (irqstatus & IR_BEU)
                netdev_err(dev, "Bit Error Uncorrected\n");
        if (irqstatus & IR_BEC)
@@ -1494,20 +1494,32 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
        case 30:
                /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
                can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
-               cdev->can.bittiming_const = &m_can_bittiming_const_30X;
-               cdev->can.data_bittiming_const = &m_can_data_bittiming_const_30X;
+               cdev->can.bittiming_const = cdev->bit_timing ?
+                       cdev->bit_timing : &m_can_bittiming_const_30X;
+
+               cdev->can.data_bittiming_const = cdev->data_timing ?
+                       cdev->data_timing :
+                       &m_can_data_bittiming_const_30X;
                break;
        case 31:
                /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
                can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
-               cdev->can.bittiming_const = &m_can_bittiming_const_31X;
-               cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
+               cdev->can.bittiming_const = cdev->bit_timing ?
+                       cdev->bit_timing : &m_can_bittiming_const_31X;
+
+               cdev->can.data_bittiming_const = cdev->data_timing ?
+                       cdev->data_timing :
+                       &m_can_data_bittiming_const_31X;
                break;
        case 32:
        case 33:
                /* Support both MCAN version v3.2.x and v3.3.0 */
-               cdev->can.bittiming_const = &m_can_bittiming_const_31X;
-               cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
+               cdev->can.bittiming_const = cdev->bit_timing ?
+                       cdev->bit_timing : &m_can_bittiming_const_31X;
+
+               cdev->can.data_bittiming_const = cdev->data_timing ?
+                       cdev->data_timing :
+                       &m_can_data_bittiming_const_31X;
 
                cdev->can.ctrlmode_supported |=
                        (m_can_niso_supported(cdev) ?
index d18b515..2c5d409 100644 (file)
@@ -85,6 +85,9 @@ struct m_can_classdev {
        struct sk_buff *tx_skb;
        struct phy *transceiver;
 
+       const struct can_bittiming_const *bit_timing;
+       const struct can_bittiming_const *data_timing;
+
        struct m_can_ops *ops;
 
        int version;
index 89cc3d4..b56a54d 100644 (file)
 
 #define M_CAN_PCI_MMIO_BAR             0
 
-#define M_CAN_CLOCK_FREQ_EHL           100000000
 #define CTL_CSR_INT_CTL_OFFSET         0x508
 
+struct m_can_pci_config {
+       const struct can_bittiming_const *bit_timing;
+       const struct can_bittiming_const *data_timing;
+       unsigned int clock_freq;
+};
+
 struct m_can_pci_priv {
        struct m_can_classdev cdev;
 
@@ -42,8 +47,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
 static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
 {
        struct m_can_pci_priv *priv = cdev_to_priv(cdev);
+       void __iomem *src = priv->base + offset;
 
-       ioread32_rep(priv->base + offset, val, val_count);
+       while (val_count--) {
+               *(unsigned int *)val = ioread32(src);
+               val += 4;
+               src += 4;
+       }
 
        return 0;
 }
@@ -61,8 +71,13 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
                            const void *val, size_t val_count)
 {
        struct m_can_pci_priv *priv = cdev_to_priv(cdev);
+       void __iomem *dst = priv->base + offset;
 
-       iowrite32_rep(priv->base + offset, val, val_count);
+       while (val_count--) {
+               iowrite32(*(unsigned int *)val, dst);
+               val += 4;
+               dst += 4;
+       }
 
        return 0;
 }
@@ -74,9 +89,40 @@ static struct m_can_ops m_can_pci_ops = {
        .read_fifo = iomap_read_fifo,
 };
 
+static const struct can_bittiming_const m_can_bittiming_const_ehl = {
+       .name = KBUILD_MODNAME,
+       .tseg1_min = 2,         /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max = 64,
+       .tseg2_min = 1,         /* Time segment 2 = phase_seg2 */
+       .tseg2_max = 128,
+       .sjw_max = 128,
+       .brp_min = 1,
+       .brp_max = 512,
+       .brp_inc = 1,
+};
+
+static const struct can_bittiming_const m_can_data_bittiming_const_ehl = {
+       .name = KBUILD_MODNAME,
+       .tseg1_min = 2,         /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max = 16,
+       .tseg2_min = 1,         /* Time segment 2 = phase_seg2 */
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 32,
+       .brp_inc = 1,
+};
+
+static const struct m_can_pci_config m_can_pci_ehl = {
+       .bit_timing = &m_can_bittiming_const_ehl,
+       .data_timing = &m_can_data_bittiming_const_ehl,
+       .clock_freq = 200000000,
+};
+
 static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
        struct device *dev = &pci->dev;
+       const struct m_can_pci_config *cfg;
        struct m_can_classdev *mcan_class;
        struct m_can_pci_priv *priv;
        void __iomem *base;
@@ -104,6 +150,8 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
        if (!mcan_class)
                return -ENOMEM;
 
+       cfg = (const struct m_can_pci_config *)id->driver_data;
+
        priv = cdev_to_priv(mcan_class);
 
        priv->base = base;
@@ -115,7 +163,9 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
        mcan_class->dev = &pci->dev;
        mcan_class->net->irq = pci_irq_vector(pci, 0);
        mcan_class->pm_clock_support = 1;
-       mcan_class->can.clock.freq = id->driver_data;
+       mcan_class->bit_timing = cfg->bit_timing;
+       mcan_class->data_timing = cfg->data_timing;
+       mcan_class->can.clock.freq = cfg->clock_freq;
        mcan_class->ops = &m_can_pci_ops;
 
        pci_set_drvdata(pci, mcan_class);
@@ -168,8 +218,8 @@ static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
                         m_can_pci_suspend, m_can_pci_resume);
 
 static const struct pci_device_id m_can_pci_id_table[] = {
-       { PCI_VDEVICE(INTEL, 0x4bc1), M_CAN_CLOCK_FREQ_EHL, },
-       { PCI_VDEVICE(INTEL, 0x4bc2), M_CAN_CLOCK_FREQ_EHL, },
+       { PCI_VDEVICE(INTEL, 0x4bc1), (kernel_ulong_t)&m_can_pci_ehl, },
+       { PCI_VDEVICE(INTEL, 0x4bc2), (kernel_ulong_t)&m_can_pci_ehl, },
        {  }    /* Terminating Entry */
 };
 MODULE_DEVICE_TABLE(pci, m_can_pci_id_table);
index 92a54a5..964c8a0 100644 (file)
@@ -692,11 +692,11 @@ static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
                        cf->data[i + 1] = data_reg >> 8;
                }
 
-               netif_receive_skb(skb);
                rcv_pkts++;
                stats->rx_packets++;
                quota--;
                stats->rx_bytes += cf->len;
+               netif_receive_skb(skb);
 
                pch_fifo_thresh(priv, obj_num);
                obj_num++;
index e21b169..4642b6d 100644 (file)
@@ -234,7 +234,12 @@ static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base)
                        free_sja1000dev(dev);
        }
 
-       err = request_irq(dev->irq, &ems_pcmcia_interrupt, IRQF_SHARED,
+       if (!card->channels) {
+               err = -ENODEV;
+               goto failure_cleanup;
+       }
+
+       err = request_irq(pdev->irq, &ems_pcmcia_interrupt, IRQF_SHARED,
                          DRV_NAME, card);
        if (!err)
                return 0;
index 59ba7c7..f7af1bf 100644 (file)
 
 #include "kvaser_usb.h"
 
-/* Forward declaration */
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg;
-
-#define CAN_USB_CLOCK                  8000000
 #define MAX_USBCAN_NET_DEVICES         2
 
 /* Command header size */
@@ -80,6 +76,12 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg;
 
 #define CMD_LEAF_LOG_MESSAGE           106
 
+/* Leaf frequency options */
+#define KVASER_USB_LEAF_SWOPTION_FREQ_MASK 0x60
+#define KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK 0
+#define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5)
+#define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6)
+
 /* error factors */
 #define M16C_EF_ACKE                   BIT(0)
 #define M16C_EF_CRCE                   BIT(1)
@@ -340,6 +342,50 @@ struct kvaser_usb_err_summary {
        };
 };
 
+static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
+       .name = "kvaser_usb",
+       .tseg1_min = KVASER_USB_TSEG1_MIN,
+       .tseg1_max = KVASER_USB_TSEG1_MAX,
+       .tseg2_min = KVASER_USB_TSEG2_MIN,
+       .tseg2_max = KVASER_USB_TSEG2_MAX,
+       .sjw_max = KVASER_USB_SJW_MAX,
+       .brp_min = KVASER_USB_BRP_MIN,
+       .brp_max = KVASER_USB_BRP_MAX,
+       .brp_inc = KVASER_USB_BRP_INC,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
+       .clock = {
+               .freq = 8000000,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
+       .clock = {
+               .freq = 16000000,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
+       .clock = {
+               .freq = 24000000,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
+       .clock = {
+               .freq = 32000000,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+};
+
 static void *
 kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
                             const struct sk_buff *skb, int *frame_len,
@@ -471,6 +517,27 @@ static int kvaser_usb_leaf_send_simple_cmd(const struct kvaser_usb *dev,
        return rc;
 }
 
+static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
+                                                  const struct leaf_cmd_softinfo *softinfo)
+{
+       u32 sw_options = le32_to_cpu(softinfo->sw_options);
+
+       dev->fw_version = le32_to_cpu(softinfo->fw_version);
+       dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
+
+       switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
+       case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
+               dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
+               break;
+       case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
+               dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
+               break;
+       case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
+               dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
+               break;
+       }
+}
+
 static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
 {
        struct kvaser_cmd cmd;
@@ -486,14 +553,13 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
 
        switch (dev->card_data.leaf.family) {
        case KVASER_LEAF:
-               dev->fw_version = le32_to_cpu(cmd.u.leaf.softinfo.fw_version);
-               dev->max_tx_urbs =
-                       le16_to_cpu(cmd.u.leaf.softinfo.max_outstanding_tx);
+               kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
                break;
        case KVASER_USBCAN:
                dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
                dev->max_tx_urbs =
                        le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
+               dev->cfg = &kvaser_usb_leaf_dev_cfg_8mhz;
                break;
        }
 
@@ -1225,24 +1291,11 @@ static int kvaser_usb_leaf_init_card(struct kvaser_usb *dev)
 {
        struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
 
-       dev->cfg = &kvaser_usb_leaf_dev_cfg;
        card_data->ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
 
        return 0;
 }
 
-static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
-       .name = "kvaser_usb",
-       .tseg1_min = KVASER_USB_TSEG1_MIN,
-       .tseg1_max = KVASER_USB_TSEG1_MAX,
-       .tseg2_min = KVASER_USB_TSEG2_MIN,
-       .tseg2_max = KVASER_USB_TSEG2_MAX,
-       .sjw_max = KVASER_USB_SJW_MAX,
-       .brp_min = KVASER_USB_BRP_MIN,
-       .brp_max = KVASER_USB_BRP_MAX,
-       .brp_inc = KVASER_USB_BRP_INC,
-};
-
 static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
@@ -1348,11 +1401,3 @@ const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
        .dev_read_bulk_callback = kvaser_usb_leaf_read_bulk_callback,
        .dev_frame_to_cmd = kvaser_usb_leaf_frame_to_cmd,
 };
-
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg = {
-       .clock = {
-               .freq = CAN_USB_CLOCK,
-       },
-       .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
-};
index f00cbf5..cd8462d 100644 (file)
@@ -471,6 +471,12 @@ static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
        u16 reg;
        int err;
 
+       /* The 88e6250 family does not have the PHY detect bit. Instead,
+        * report whether the port is internal.
+        */
+       if (chip->info->family == MV88E6XXX_FAMILY_6250)
+               return port < chip->info->num_internal_phys;
+
        err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
        if (err) {
                dev_err(chip->dev,
@@ -692,44 +698,48 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
 {
        struct mv88e6xxx_chip *chip = ds->priv;
        struct mv88e6xxx_port *p;
-       int err;
+       int err = 0;
 
        p = &chip->ports[port];
 
-       /* FIXME: is this the correct test? If we're in fixed mode on an
-        * internal port, why should we process this any different from
-        * PHY mode? On the other hand, the port may be automedia between
-        * an internal PHY and the serdes...
-        */
-       if ((mode == MLO_AN_PHY) && mv88e6xxx_phy_is_internal(ds, port))
-               return;
-
        mv88e6xxx_reg_lock(chip);
-       /* In inband mode, the link may come up at any time while the link
-        * is not forced down. Force the link down while we reconfigure the
-        * interface mode.
-        */
-       if (mode == MLO_AN_INBAND && p->interface != state->interface &&
-           chip->info->ops->port_set_link)
-               chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
 
-       err = mv88e6xxx_port_config_interface(chip, port, state->interface);
-       if (err && err != -EOPNOTSUPP)
-               goto err_unlock;
-
-       err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface,
-                                         state->advertising);
-       /* FIXME: we should restart negotiation if something changed - which
-        * is something we get if we convert to using phylinks PCS operations.
-        */
-       if (err > 0)
-               err = 0;
+       if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) {
+               /* In inband mode, the link may come up at any time while the
+                * link is not forced down. Force the link down while we
+                * reconfigure the interface mode.
+                */
+               if (mode == MLO_AN_INBAND &&
+                   p->interface != state->interface &&
+                   chip->info->ops->port_set_link)
+                       chip->info->ops->port_set_link(chip, port,
+                                                      LINK_FORCED_DOWN);
+
+               err = mv88e6xxx_port_config_interface(chip, port,
+                                                     state->interface);
+               if (err && err != -EOPNOTSUPP)
+                       goto err_unlock;
+
+               err = mv88e6xxx_serdes_pcs_config(chip, port, mode,
+                                                 state->interface,
+                                                 state->advertising);
+               /* FIXME: we should restart negotiation if something changed -
+                * which is something we get if we convert to using phylinks
+                * PCS operations.
+                */
+               if (err > 0)
+                       err = 0;
+       }
 
        /* Undo the forced down state above after completing configuration
-        * irrespective of its state on entry, which allows the link to come up.
+        * irrespective of its state on entry, which allows the link to come
+        * up in the in-band case where there is no separate SERDES. Also
+        * ensure that the link can come up if the PPU is in use and we are
+        * in PHY mode (we treat the PPU as an effective in-band mechanism.)
         */
-       if (mode == MLO_AN_INBAND && p->interface != state->interface &&
-           chip->info->ops->port_set_link)
+       if (chip->info->ops->port_set_link &&
+           ((mode == MLO_AN_INBAND && p->interface != state->interface) ||
+            (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port))))
                chip->info->ops->port_set_link(chip, port, LINK_UNFORCED);
 
        p->interface = state->interface;
@@ -752,13 +762,16 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port,
        ops = chip->info->ops;
 
        mv88e6xxx_reg_lock(chip);
-       /* Internal PHYs propagate their configuration directly to the MAC.
-        * External PHYs depend on whether the PPU is enabled for this port.
+       /* Force the link down if we know the port may not be automatically
+        * updated by the switch or if we are using fixed-link mode.
         */
-       if (((!mv88e6xxx_phy_is_internal(ds, port) &&
-             !mv88e6xxx_port_ppu_updates(chip, port)) ||
+       if ((!mv88e6xxx_port_ppu_updates(chip, port) ||
             mode == MLO_AN_FIXED) && ops->port_sync_link)
                err = ops->port_sync_link(chip, port, mode, false);
+
+       if (!err && ops->port_set_speed_duplex)
+               err = ops->port_set_speed_duplex(chip, port, SPEED_UNFORCED,
+                                                DUPLEX_UNFORCED);
        mv88e6xxx_reg_unlock(chip);
 
        if (err)
@@ -779,11 +792,11 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
        ops = chip->info->ops;
 
        mv88e6xxx_reg_lock(chip);
-       /* Internal PHYs propagate their configuration directly to the MAC.
-        * External PHYs depend on whether the PPU is enabled for this port.
+       /* Configure and force the link up if we know that the port may not
+        * automatically updated by the switch or if we are using fixed-link
+        * mode.
         */
-       if ((!mv88e6xxx_phy_is_internal(ds, port) &&
-            !mv88e6xxx_port_ppu_updates(chip, port)) ||
+       if (!mv88e6xxx_port_ppu_updates(chip, port) ||
            mode == MLO_AN_FIXED) {
                /* FIXME: for an automedia port, should we force the link
                 * down here - what if the link comes up due to "other" media
index d9817b2..ab41619 100644 (file)
@@ -283,7 +283,7 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
        if (err)
                return err;
 
-       if (speed)
+       if (speed != SPEED_UNFORCED)
                dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
        else
                dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
@@ -516,7 +516,7 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
        if (err)
                return err;
 
-       if (speed)
+       if (speed != SPEED_UNFORCED)
                dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
        else
                dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
index 5527301..2b05ead 100644 (file)
@@ -830,7 +830,7 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
                           bool up)
 {
        u8 cmode = chip->ports[port].cmode;
-       int err = 0;
+       int err;
 
        switch (cmode) {
        case MV88E6XXX_PORT_STS_CMODE_SGMII:
@@ -842,6 +842,9 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
        case MV88E6XXX_PORT_STS_CMODE_RXAUI:
                err = mv88e6390_serdes_power_10g(chip, lane, up);
                break;
+       default:
+               err = -EINVAL;
+               break;
        }
 
        if (!err && up)
@@ -1541,6 +1544,9 @@ int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
        case MV88E6393X_PORT_STS_CMODE_10GBASER:
                err = mv88e6390_serdes_power_10g(chip, lane, on);
                break;
+       default:
+               err = -EINVAL;
+               break;
        }
 
        if (err)
index 327cc46..f1a05e7 100644 (file)
@@ -290,8 +290,11 @@ static int felix_setup_mmio_filtering(struct felix *felix)
                }
        }
 
-       if (cpu < 0)
+       if (cpu < 0) {
+               kfree(tagging_rule);
+               kfree(redirect_rule);
                return -EINVAL;
+       }
 
        tagging_rule->key_type = OCELOT_VCAP_KEY_ETYPE;
        *(__be16 *)tagging_rule->key.etype.etype.value = htons(ETH_P_1588);
index d75d95a..993b2fb 100644 (file)
@@ -1430,16 +1430,19 @@ static int altera_tse_probe(struct platform_device *pdev)
                priv->rxdescmem_busaddr = dma_res->start;
 
        } else {
+               ret = -ENODEV;
                goto err_free_netdev;
        }
 
-       if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
+       if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask))) {
                dma_set_coherent_mask(priv->device,
                                      DMA_BIT_MASK(priv->dmaops->dmamask));
-       else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
+       } else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) {
                dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
-       else
+       } else {
+               ret = -EIO;
                goto err_free_netdev;
+       }
 
        /* MAC address space */
        ret = request_and_map(pdev, "control_port", &control_port,
index 7cc5213..b07cb9b 100644 (file)
@@ -708,7 +708,9 @@ static int bcm4908_enet_probe(struct platform_device *pdev)
 
        enet->irq_tx = platform_get_irq_byname(pdev, "tx");
 
-       dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+       err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+       if (err)
+               return err;
 
        err = bcm4908_enet_dma_alloc(enet);
        if (err)
index 40933bf..60dde29 100644 (file)
@@ -1309,11 +1309,11 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
        struct bcm_sysport_priv *priv = netdev_priv(dev);
        struct device *kdev = &priv->pdev->dev;
        struct bcm_sysport_tx_ring *ring;
+       unsigned long flags, desc_flags;
        struct bcm_sysport_cb *cb;
        struct netdev_queue *txq;
        u32 len_status, addr_lo;
        unsigned int skb_len;
-       unsigned long flags;
        dma_addr_t mapping;
        u16 queue;
        int ret;
@@ -1373,8 +1373,10 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
        ring->desc_count--;
 
        /* Ports are latched, so write upper address first */
+       spin_lock_irqsave(&priv->desc_lock, desc_flags);
        tdma_writel(priv, len_status, TDMA_WRITE_PORT_HI(ring->index));
        tdma_writel(priv, addr_lo, TDMA_WRITE_PORT_LO(ring->index));
+       spin_unlock_irqrestore(&priv->desc_lock, desc_flags);
 
        /* Check ring space and update SW control flow */
        if (ring->desc_count == 0)
@@ -2013,6 +2015,7 @@ static int bcm_sysport_open(struct net_device *dev)
        }
 
        /* Initialize both hardware and software ring */
+       spin_lock_init(&priv->desc_lock);
        for (i = 0; i < dev->num_tx_queues; i++) {
                ret = bcm_sysport_init_tx_ring(priv, i);
                if (ret) {
index 984f76e..16b73bb 100644 (file)
@@ -711,6 +711,7 @@ struct bcm_sysport_priv {
        int                     wol_irq;
 
        /* Transmit rings */
+       spinlock_t              desc_lock;
        struct bcm_sysport_tx_ring *tx_rings;
 
        /* Receive queue */
index 5f25964..c888dde 100644 (file)
@@ -589,9 +589,9 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv)
                 * Internal or external PHY with MDIO access
                 */
                phydev = phy_attach(priv->dev, phy_name, pd->phy_interface);
-               if (!phydev) {
+               if (IS_ERR(phydev)) {
                        dev_err(kdev, "failed to register PHY device\n");
-                       return -ENODEV;
+                       return PTR_ERR(phydev);
                }
        } else {
                /*
index 2085844..e54e70e 100644 (file)
@@ -388,6 +388,8 @@ struct dpaa2_eth_ch_stats {
        __u64 bytes_per_cdan;
 };
 
+#define DPAA2_ETH_CH_STATS     7
+
 /* Maximum number of queues associated with a DPNI */
 #define DPAA2_ETH_MAX_TCS              8
 #define DPAA2_ETH_MAX_RX_QUEUES_PER_TC 16
index adb8ce5..3fdbf87 100644 (file)
@@ -278,7 +278,7 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
        /* Per-channel stats */
        for (k = 0; k < priv->num_channels; k++) {
                ch_stats = &priv->channel[k]->stats;
-               for (j = 0; j < sizeof(*ch_stats) / sizeof(__u64) - 1; j++)
+               for (j = 0; j < DPAA2_ETH_CH_STATS; j++)
                        *((__u64 *)data + i + j) += *((__u64 *)ch_stats + j);
        }
        i += j;
index 7b4961d..ed7301b 100644 (file)
@@ -377,6 +377,9 @@ struct bufdesc_ex {
 #define FEC_ENET_WAKEUP        ((uint)0x00020000)      /* Wakeup request */
 #define FEC_ENET_TXF   (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
 #define FEC_ENET_RXF   (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
+#define FEC_ENET_RXF_GET(X)    (((X) == 0) ? FEC_ENET_RXF_0 :  \
+                               (((X) == 1) ? FEC_ENET_RXF_1 :  \
+                               FEC_ENET_RXF_2))
 #define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
 #define FEC_ENET_TS_TIMER       ((uint)0x00008000)
 
index bc418b9..1b1f7f2 100644 (file)
@@ -1480,7 +1480,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
                        break;
                pkt_received++;
 
-               writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
+               writel(FEC_ENET_RXF_GET(queue_id), fep->hwp + FEC_IEVENT);
 
                /* Check for errors. */
                status ^= BD_ENET_RX_LAST;
index 88ca49c..d57508b 100644 (file)
@@ -68,6 +68,9 @@ struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
                set_protocol = ctx->curr_frag_cnt == ctx->expected_frag_cnt - 1;
        } else {
                skb = napi_alloc_skb(napi, len);
+
+               if (unlikely(!skb))
+                       return NULL;
                set_protocol = true;
        }
        __skb_put(skb, len);
index 3f7a9a4..63f5abc 100644 (file)
@@ -839,6 +839,8 @@ struct hnae3_handle {
 
        u8 netdev_flags;
        struct dentry *hnae3_dbgfs;
+       /* protects concurrent contention between debugfs commands */
+       struct mutex dbgfs_lock;
 
        /* Network interface message level enabled bits */
        u32 msg_enable;
index 081295b..c381f8a 100644 (file)
@@ -1226,6 +1226,7 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
        if (ret)
                return ret;
 
+       mutex_lock(&handle->dbgfs_lock);
        save_buf = &hns3_dbg_cmd[index].buf;
 
        if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) ||
@@ -1238,15 +1239,15 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
                read_buf = *save_buf;
        } else {
                read_buf = kvzalloc(hns3_dbg_cmd[index].buf_len, GFP_KERNEL);
-               if (!read_buf)
-                       return -ENOMEM;
+               if (!read_buf) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
 
                /* save the buffer addr until the last read operation */
                *save_buf = read_buf;
-       }
 
-       /* get data ready for the first time to read */
-       if (!*ppos) {
+               /* get data ready for the first time to read */
                ret = hns3_dbg_read_cmd(dbg_data, hns3_dbg_cmd[index].cmd,
                                        read_buf, hns3_dbg_cmd[index].buf_len);
                if (ret)
@@ -1255,8 +1256,10 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer,
 
        size = simple_read_from_buffer(buffer, count, ppos, read_buf,
                                       strlen(read_buf));
-       if (size > 0)
+       if (size > 0) {
+               mutex_unlock(&handle->dbgfs_lock);
                return size;
+       }
 
 out:
        /* free the buffer for the last read operation */
@@ -1265,6 +1268,7 @@ out:
                *save_buf = NULL;
        }
 
+       mutex_unlock(&handle->dbgfs_lock);
        return ret;
 }
 
@@ -1337,6 +1341,8 @@ int hns3_dbg_init(struct hnae3_handle *handle)
                        debugfs_create_dir(hns3_dbg_dentry[i].name,
                                           handle->hnae3_dbgfs);
 
+       mutex_init(&handle->dbgfs_lock);
+
        for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) {
                if ((hns3_dbg_cmd[i].cmd == HNAE3_DBG_CMD_TM_NODES &&
                     ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2) ||
@@ -1363,6 +1369,7 @@ int hns3_dbg_init(struct hnae3_handle *handle)
        return 0;
 
 out:
+       mutex_destroy(&handle->dbgfs_lock);
        debugfs_remove_recursive(handle->hnae3_dbgfs);
        handle->hnae3_dbgfs = NULL;
        return ret;
@@ -1378,6 +1385,7 @@ void hns3_dbg_uninit(struct hnae3_handle *handle)
                        hns3_dbg_cmd[i].buf = NULL;
                }
 
+       mutex_destroy(&handle->dbgfs_lock);
        debugfs_remove_recursive(handle->hnae3_dbgfs);
        handle->hnae3_dbgfs = NULL;
 }
index fdc66fa..c5ac6ec 100644 (file)
@@ -114,7 +114,8 @@ int hclgevf_send_mbx_msg(struct hclgevf_dev *hdev,
 
        memcpy(&req->msg, send_msg, sizeof(struct hclge_vf_to_pf_msg));
 
-       trace_hclge_vf_mbx_send(hdev, req);
+       if (test_bit(HCLGEVF_STATE_NIC_REGISTERED, &hdev->state))
+               trace_hclge_vf_mbx_send(hdev, req);
 
        /* synchronous send */
        if (need_resp) {
index a78c398..01e7d3c 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/interrupt.h>
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
+#include <linux/module.h>
 
 #include "hinic_hw_dev.h"
 #include "hinic_dev.h"
index 291e61a..2c1b1da 100644 (file)
@@ -553,6 +553,14 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
                dev_info(&pf->pdev->dev, "vsi %d not found\n", vsi_seid);
                return;
        }
+       if (vsi->type != I40E_VSI_MAIN &&
+           vsi->type != I40E_VSI_FDIR &&
+           vsi->type != I40E_VSI_VMDQ2) {
+               dev_info(&pf->pdev->dev,
+                        "vsi %d type %d descriptor rings not available\n",
+                        vsi_seid, vsi->type);
+               return;
+       }
        if (type == RING_TYPE_XDP && !i40e_enabled_xdp_vsi(vsi)) {
                dev_info(&pf->pdev->dev, "XDP not enabled on VSI %d\n", vsi_seid);
                return;
index 80ae264..2ea4deb 100644 (file)
@@ -1949,6 +1949,32 @@ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf,
 }
 
 /**
+ * i40e_sync_vf_state
+ * @vf: pointer to the VF info
+ * @state: VF state
+ *
+ * Called from a VF message to synchronize the service with a potential
+ * VF reset state
+ **/
+static bool i40e_sync_vf_state(struct i40e_vf *vf, enum i40e_vf_states state)
+{
+       int i;
+
+       /* When handling some messages, it needs VF state to be set.
+        * It is possible that this flag is cleared during VF reset,
+        * so there is a need to wait until the end of the reset to
+        * handle the request message correctly.
+        */
+       for (i = 0; i < I40E_VF_STATE_WAIT_COUNT; i++) {
+               if (test_bit(state, &vf->vf_states))
+                       return true;
+               usleep_range(10000, 20000);
+       }
+
+       return test_bit(state, &vf->vf_states);
+}
+
+/**
  * i40e_vc_get_version_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -2008,7 +2034,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
        size_t len = 0;
        int ret;
 
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_INIT)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -2131,7 +2157,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg)
        bool allmulti = false;
        bool alluni = false;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err_out;
        }
@@ -2219,7 +2245,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
        struct i40e_vsi *vsi;
        u16 num_qps_all = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
        }
@@ -2368,7 +2394,7 @@ static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        int i;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
        }
@@ -2540,7 +2566,7 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
        struct i40e_pf *pf = vf->pf;
        i40e_status aq_ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
        }
@@ -2590,7 +2616,7 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
        u8 cur_pairs = vf->num_queue_pairs;
        struct i40e_pf *pf = vf->pf;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE))
                return -EINVAL;
 
        if (req_pairs > I40E_MAX_VF_QUEUES) {
@@ -2635,7 +2661,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg)
 
        memset(&stats, 0, sizeof(struct i40e_eth_stats));
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
        }
@@ -2752,7 +2778,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
        i40e_status ret = 0;
        int i;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
            !i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
                ret = I40E_ERR_PARAM;
                goto error_param;
@@ -2824,7 +2850,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
        i40e_status ret = 0;
        int i;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
            !i40e_vc_isvalid_vsi_id(vf, al->vsi_id)) {
                ret = I40E_ERR_PARAM;
                goto error_param;
@@ -2968,7 +2994,7 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        int i;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
            !i40e_vc_isvalid_vsi_id(vf, vfl->vsi_id)) {
                aq_ret = I40E_ERR_PARAM;
                goto error_param;
@@ -3088,9 +3114,9 @@ static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg)
        struct i40e_vsi *vsi = NULL;
        i40e_status aq_ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
            !i40e_vc_isvalid_vsi_id(vf, vrk->vsi_id) ||
-           (vrk->key_len != I40E_HKEY_ARRAY_SIZE)) {
+           vrk->key_len != I40E_HKEY_ARRAY_SIZE) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3119,9 +3145,9 @@ static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        u16 i;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE) ||
            !i40e_vc_isvalid_vsi_id(vf, vrl->vsi_id) ||
-           (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)) {
+           vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3154,7 +3180,7 @@ static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        int len = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3190,7 +3216,7 @@ static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg)
        struct i40e_hw *hw = &pf->hw;
        i40e_status aq_ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3215,7 +3241,7 @@ static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        struct i40e_vsi *vsi;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3241,7 +3267,7 @@ static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        struct i40e_vsi *vsi;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3468,7 +3494,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        int i, ret;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3599,7 +3625,7 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        int i, ret;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err_out;
        }
@@ -3708,7 +3734,7 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
        i40e_status aq_ret = 0;
        u64 speed = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
@@ -3797,11 +3823,6 @@ static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
 
        /* set this flag only after making sure all inputs are sane */
        vf->adq_enabled = true;
-       /* num_req_queues is set when user changes number of queues via ethtool
-        * and this causes issue for default VSI(which depends on this variable)
-        * when ADq is enabled, hence reset it.
-        */
-       vf->num_req_queues = 0;
 
        /* reset the VF in order to allocate resources */
        i40e_vc_reset_vf(vf, true);
@@ -3824,7 +3845,7 @@ static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
        struct i40e_pf *pf = vf->pf;
        i40e_status aq_ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+       if (!i40e_sync_vf_state(vf, I40E_VF_STATE_ACTIVE)) {
                aq_ret = I40E_ERR_PARAM;
                goto err;
        }
index 091e32c..49575a6 100644 (file)
@@ -18,6 +18,8 @@
 
 #define I40E_MAX_VF_PROMISC_FLAGS      3
 
+#define I40E_VF_STATE_WAIT_COUNT       20
+
 /* Various queue ctrls */
 enum i40e_queue_ctrl {
        I40E_QUEUE_CTRL_UNKNOWN = 0,
index 0cecaff..461f523 100644 (file)
@@ -615,23 +615,44 @@ static int iavf_set_ringparam(struct net_device *netdev,
        if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
                return -EINVAL;
 
-       new_tx_count = clamp_t(u32, ring->tx_pending,
-                              IAVF_MIN_TXD,
-                              IAVF_MAX_TXD);
-       new_tx_count = ALIGN(new_tx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+       if (ring->tx_pending > IAVF_MAX_TXD ||
+           ring->tx_pending < IAVF_MIN_TXD ||
+           ring->rx_pending > IAVF_MAX_RXD ||
+           ring->rx_pending < IAVF_MIN_RXD) {
+               netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",
+                          ring->tx_pending, ring->rx_pending, IAVF_MIN_TXD,
+                          IAVF_MAX_RXD, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+               return -EINVAL;
+       }
 
-       new_rx_count = clamp_t(u32, ring->rx_pending,
-                              IAVF_MIN_RXD,
-                              IAVF_MAX_RXD);
-       new_rx_count = ALIGN(new_rx_count, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+       new_tx_count = ALIGN(ring->tx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+       if (new_tx_count != ring->tx_pending)
+               netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n",
+                           new_tx_count);
+
+       new_rx_count = ALIGN(ring->rx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);
+       if (new_rx_count != ring->rx_pending)
+               netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n",
+                           new_rx_count);
 
        /* if nothing to do return success */
        if ((new_tx_count == adapter->tx_desc_count) &&
-           (new_rx_count == adapter->rx_desc_count))
+           (new_rx_count == adapter->rx_desc_count)) {
+               netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n");
                return 0;
+       }
 
-       adapter->tx_desc_count = new_tx_count;
-       adapter->rx_desc_count = new_rx_count;
+       if (new_tx_count != adapter->tx_desc_count) {
+               netdev_dbg(netdev, "Changing Tx descriptor count from %d to %d\n",
+                          adapter->tx_desc_count, new_tx_count);
+               adapter->tx_desc_count = new_tx_count;
+       }
+
+       if (new_rx_count != adapter->rx_desc_count) {
+               netdev_dbg(netdev, "Changing Rx descriptor count from %d to %d\n",
+                          adapter->rx_desc_count, new_rx_count);
+               adapter->rx_desc_count = new_rx_count;
+       }
 
        if (netif_running(netdev)) {
                adapter->flags |= IAVF_FLAG_RESET_NEEDED;
index 14934a7..4e7c040 100644 (file)
@@ -2046,6 +2046,7 @@ static void iavf_watchdog_task(struct work_struct *work)
                }
                adapter->aq_required = 0;
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+               mutex_unlock(&adapter->crit_lock);
                queue_delayed_work(iavf_wq,
                                   &adapter->watchdog_task,
                                   msecs_to_jiffies(10));
@@ -2076,16 +2077,14 @@ static void iavf_watchdog_task(struct work_struct *work)
                        iavf_detect_recover_hung(&adapter->vsi);
                break;
        case __IAVF_REMOVE:
-               mutex_unlock(&adapter->crit_lock);
-               return;
        default:
+               mutex_unlock(&adapter->crit_lock);
                return;
        }
 
        /* check for hw reset */
        reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
        if (!reg_val) {
-               iavf_change_state(adapter, __IAVF_RESETTING);
                adapter->flags |= IAVF_FLAG_RESET_PENDING;
                adapter->aq_required = 0;
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
@@ -2248,6 +2247,7 @@ static void iavf_reset_task(struct work_struct *work)
        }
 
        pci_set_master(adapter->pdev);
+       pci_restore_msi_state(adapter->pdev);
 
        if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) {
                dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
index 7fdeb41..3eb0173 100644 (file)
@@ -97,6 +97,9 @@ static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets)
 
        new_cfg->etscfg.maxtcs = pf->hw.func_caps.common_cap.maxtc;
 
+       if (!bwcfg)
+               new_cfg->etscfg.tcbwtable[0] = 100;
+
        if (!bwrec)
                new_cfg->etsrec.tcbwtable[0] = 100;
 
@@ -167,15 +170,18 @@ static u8 ice_dcbnl_setdcbx(struct net_device *netdev, u8 mode)
        if (mode == pf->dcbx_cap)
                return ICE_DCB_NO_HW_CHG;
 
-       pf->dcbx_cap = mode;
        qos_cfg = &pf->hw.port_info->qos_cfg;
-       if (mode & DCB_CAP_DCBX_VER_CEE) {
-               if (qos_cfg->local_dcbx_cfg.pfc_mode == ICE_QOS_MODE_DSCP)
-                       return ICE_DCB_NO_HW_CHG;
+
+       /* DSCP configuration is not DCBx negotiated */
+       if (qos_cfg->local_dcbx_cfg.pfc_mode == ICE_QOS_MODE_DSCP)
+               return ICE_DCB_NO_HW_CHG;
+
+       pf->dcbx_cap = mode;
+
+       if (mode & DCB_CAP_DCBX_VER_CEE)
                qos_cfg->local_dcbx_cfg.dcbx_mode = ICE_DCBX_MODE_CEE;
-       } else {
+       else
                qos_cfg->local_dcbx_cfg.dcbx_mode = ICE_DCBX_MODE_IEEE;
-       }
 
        dev_info(ice_pf_to_dev(pf), "DCBx mode = 0x%x\n", mode);
        return ICE_DCB_HW_CHG_RST;
index 38960bc..b6e7f47 100644 (file)
@@ -1268,7 +1268,7 @@ ice_fdir_write_all_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input,
                bool is_tun = tun == ICE_FD_HW_SEG_TUN;
                int err;
 
-               if (is_tun && !ice_get_open_tunnel_port(&pf->hw, &port_num))
+               if (is_tun && !ice_get_open_tunnel_port(&pf->hw, &port_num, TNL_ALL))
                        continue;
                err = ice_fdir_write_fltr(pf, input, add, is_tun);
                if (err)
@@ -1652,7 +1652,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
        }
 
        /* return error if not an update and no available filters */
-       fltrs_needed = ice_get_open_tunnel_port(hw, &tunnel_port) ? 2 : 1;
+       fltrs_needed = ice_get_open_tunnel_port(hw, &tunnel_port, TNL_ALL) ? 2 : 1;
        if (!ice_fdir_find_fltr_by_idx(hw, fsp->location) &&
            ice_fdir_num_avail_fltr(hw, pf->vsi[vsi->idx]) < fltrs_needed) {
                dev_err(dev, "Failed to add filter.  The maximum number of flow director filters has been reached.\n");
index cbd8424..4dca009 100644 (file)
@@ -924,7 +924,7 @@ ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input,
                memcpy(pkt, ice_fdir_pkt[idx].pkt, ice_fdir_pkt[idx].pkt_len);
                loc = pkt;
        } else {
-               if (!ice_get_open_tunnel_port(hw, &tnl_port))
+               if (!ice_get_open_tunnel_port(hw, &tnl_port, TNL_ALL))
                        return ICE_ERR_DOES_NOT_EXIST;
                if (!ice_fdir_pkt[idx].tun_pkt)
                        return ICE_ERR_PARAM;
index 23cfcce..6ad1c25 100644 (file)
@@ -1899,9 +1899,11 @@ static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
  * ice_get_open_tunnel_port - retrieve an open tunnel port
  * @hw: pointer to the HW structure
  * @port: returns open port
+ * @type: type of tunnel, can be TNL_LAST if it doesn't matter
  */
 bool
-ice_get_open_tunnel_port(struct ice_hw *hw, u16 *port)
+ice_get_open_tunnel_port(struct ice_hw *hw, u16 *port,
+                        enum ice_tunnel_type type)
 {
        bool res = false;
        u16 i;
@@ -1909,7 +1911,8 @@ ice_get_open_tunnel_port(struct ice_hw *hw, u16 *port)
        mutex_lock(&hw->tnl_lock);
 
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
-               if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].port) {
+               if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].port &&
+                   (type == TNL_LAST || type == hw->tnl.tbl[i].type)) {
                        *port = hw->tnl.tbl[i].port;
                        res = true;
                        break;
index 344c263..a2863f3 100644 (file)
@@ -33,7 +33,8 @@ enum ice_status
 ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
                   unsigned long *bm, struct list_head *fv_list);
 bool
-ice_get_open_tunnel_port(struct ice_hw *hw, u16 *port);
+ice_get_open_tunnel_port(struct ice_hw *hw, u16 *port,
+                        enum ice_tunnel_type type);
 int ice_udp_tunnel_set_port(struct net_device *netdev, unsigned int table,
                            unsigned int idx, struct udp_tunnel_info *ti);
 int ice_udp_tunnel_unset_port(struct net_device *netdev, unsigned int table,
index 4d1fc48..73c61cd 100644 (file)
@@ -5881,6 +5881,9 @@ static int ice_up_complete(struct ice_vsi *vsi)
                netif_carrier_on(vsi->netdev);
        }
 
+       /* clear this now, and the first stats read will be used as baseline */
+       vsi->stat_offsets_loaded = false;
+
        ice_service_task_schedule(pf);
 
        return 0;
@@ -5927,14 +5930,15 @@ ice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp, struct ice_q_stats st
 /**
  * ice_update_vsi_tx_ring_stats - Update VSI Tx ring stats counters
  * @vsi: the VSI to be updated
+ * @vsi_stats: the stats struct to be updated
  * @rings: rings to work on
  * @count: number of rings
  */
 static void
-ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi, struct ice_tx_ring **rings,
-                            u16 count)
+ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
+                            struct rtnl_link_stats64 *vsi_stats,
+                            struct ice_tx_ring **rings, u16 count)
 {
-       struct rtnl_link_stats64 *vsi_stats = &vsi->net_stats;
        u16 i;
 
        for (i = 0; i < count; i++) {
@@ -5958,15 +5962,13 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi, struct ice_tx_ring **rings,
  */
 static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
 {
-       struct rtnl_link_stats64 *vsi_stats = &vsi->net_stats;
+       struct rtnl_link_stats64 *vsi_stats;
        u64 pkts, bytes;
        int i;
 
-       /* reset netdev stats */
-       vsi_stats->tx_packets = 0;
-       vsi_stats->tx_bytes = 0;
-       vsi_stats->rx_packets = 0;
-       vsi_stats->rx_bytes = 0;
+       vsi_stats = kzalloc(sizeof(*vsi_stats), GFP_ATOMIC);
+       if (!vsi_stats)
+               return;
 
        /* reset non-netdev (extended) stats */
        vsi->tx_restart = 0;
@@ -5978,7 +5980,8 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
        rcu_read_lock();
 
        /* update Tx rings counters */
-       ice_update_vsi_tx_ring_stats(vsi, vsi->tx_rings, vsi->num_txq);
+       ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->tx_rings,
+                                    vsi->num_txq);
 
        /* update Rx rings counters */
        ice_for_each_rxq(vsi, i) {
@@ -5993,10 +5996,17 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
 
        /* update XDP Tx rings counters */
        if (ice_is_xdp_ena_vsi(vsi))
-               ice_update_vsi_tx_ring_stats(vsi, vsi->xdp_rings,
+               ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->xdp_rings,
                                             vsi->num_xdp_txq);
 
        rcu_read_unlock();
+
+       vsi->net_stats.tx_packets = vsi_stats->tx_packets;
+       vsi->net_stats.tx_bytes = vsi_stats->tx_bytes;
+       vsi->net_stats.rx_packets = vsi_stats->rx_packets;
+       vsi->net_stats.rx_bytes = vsi_stats->rx_bytes;
+
+       kfree(vsi_stats);
 }
 
 /**
index bf7247c..442b031 100644 (file)
@@ -705,7 +705,7 @@ static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
                scaled_ppm = -scaled_ppm;
        }
 
-       while ((u64)scaled_ppm > div_u64(U64_MAX, incval)) {
+       while ((u64)scaled_ppm > div64_u64(U64_MAX, incval)) {
                /* handle overflow by scaling down the scaled_ppm and
                 * the divisor, losing some precision
                 */
@@ -1540,19 +1540,16 @@ static void ice_ptp_tx_tstamp_work(struct kthread_work *work)
                if (err)
                        continue;
 
-               /* Check if the timestamp is valid */
-               if (!(raw_tstamp & ICE_PTP_TS_VALID))
+               /* Check if the timestamp is invalid or stale */
+               if (!(raw_tstamp & ICE_PTP_TS_VALID) ||
+                   raw_tstamp == tx->tstamps[idx].cached_tstamp)
                        continue;
 
-               /* clear the timestamp register, so that it won't show valid
-                * again when re-used.
-                */
-               ice_clear_phy_tstamp(hw, tx->quad, phy_idx);
-
                /* The timestamp is valid, so we'll go ahead and clear this
                 * index and then send the timestamp up to the stack.
                 */
                spin_lock(&tx->lock);
+               tx->tstamps[idx].cached_tstamp = raw_tstamp;
                clear_bit(idx, tx->in_use);
                skb = tx->tstamps[idx].skb;
                tx->tstamps[idx].skb = NULL;
index f71ad31..53c15fc 100644 (file)
@@ -55,15 +55,21 @@ struct ice_perout_channel {
  * struct ice_tx_tstamp - Tracking for a single Tx timestamp
  * @skb: pointer to the SKB for this timestamp request
  * @start: jiffies when the timestamp was first requested
+ * @cached_tstamp: last read timestamp
  *
  * This structure tracks a single timestamp request. The SKB pointer is
  * provided when initiating a request. The start time is used to ensure that
  * we discard old requests that were not fulfilled within a 2 second time
  * window.
+ * Timestamp values in the PHY are read only and do not get cleared except at
+ * hardware reset or when a new timestamp value is captured. The cached_tstamp
+ * field is used to detect the case where a new timestamp has not yet been
+ * captured, ensuring that we avoid sending stale timestamp data to the stack.
  */
 struct ice_tx_tstamp {
        struct sk_buff *skb;
        unsigned long start;
+       u64 cached_tstamp;
 };
 
 /**
index 793f4a9..183d930 100644 (file)
@@ -3796,10 +3796,13 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
  * ice_find_recp - find a recipe
  * @hw: pointer to the hardware structure
  * @lkup_exts: extension sequence to match
+ * @tun_type: type of recipe tunnel
  *
  * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
  */
-static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts)
+static u16
+ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
+             enum ice_sw_tunnel_type tun_type)
 {
        bool refresh_required = true;
        struct ice_sw_recipe *recp;
@@ -3860,8 +3863,9 @@ static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts)
                        }
                        /* If for "i"th recipe the found was never set to false
                         * then it means we found our match
+                        * Also tun type of recipe needs to be checked
                         */
-                       if (found)
+                       if (found && recp[i].tun_type == tun_type)
                                return i; /* Return the recipe ID */
                }
        }
@@ -4651,11 +4655,12 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        }
 
        /* Look for a recipe which matches our requested fv / mask list */
-       *rid = ice_find_recp(hw, lkup_exts);
+       *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type);
        if (*rid < ICE_MAX_NUM_RECIPES)
                /* Success if found a recipe that match the existing criteria */
                goto err_unroll;
 
+       rm->tun_type = rinfo->tun_type;
        /* Recipe we need does not exist, add a recipe */
        status = ice_add_sw_recipe(hw, rm, profiles);
        if (status)
@@ -4958,11 +4963,13 @@ ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type,
 
        switch (tun_type) {
        case ICE_SW_TUN_VXLAN:
+               if (!ice_get_open_tunnel_port(hw, &open_port, TNL_VXLAN))
+                       return ICE_ERR_CFG;
+               break;
        case ICE_SW_TUN_GENEVE:
-               if (!ice_get_open_tunnel_port(hw, &open_port))
+               if (!ice_get_open_tunnel_port(hw, &open_port, TNL_GENEVE))
                        return ICE_ERR_CFG;
                break;
-
        default:
                /* Nothing needs to be done for this tunnel type */
                return 0;
@@ -5555,7 +5562,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (status)
                return status;
 
-       rid = ice_find_recp(hw, &lkup_exts);
+       rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type);
        /* If did not find a recipe that match the existing criteria */
        if (rid == ICE_MAX_NUM_RECIPES)
                return ICE_ERR_PARAM;
index e5d23fe..25cca5c 100644 (file)
@@ -74,21 +74,13 @@ static enum ice_protocol_type ice_proto_type_from_ipv6(bool inner)
        return inner ? ICE_IPV6_IL : ICE_IPV6_OFOS;
 }
 
-static enum ice_protocol_type
-ice_proto_type_from_l4_port(bool inner, u16 ip_proto)
+static enum ice_protocol_type ice_proto_type_from_l4_port(u16 ip_proto)
 {
-       if (inner) {
-               switch (ip_proto) {
-               case IPPROTO_UDP:
-                       return ICE_UDP_ILOS;
-               }
-       } else {
-               switch (ip_proto) {
-               case IPPROTO_TCP:
-                       return ICE_TCP_IL;
-               case IPPROTO_UDP:
-                       return ICE_UDP_OF;
-               }
+       switch (ip_proto) {
+       case IPPROTO_TCP:
+               return ICE_TCP_IL;
+       case IPPROTO_UDP:
+               return ICE_UDP_ILOS;
        }
 
        return 0;
@@ -191,8 +183,9 @@ ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr,
                i++;
        }
 
-       if (flags & ICE_TC_FLWR_FIELD_ENC_DEST_L4_PORT) {
-               list[i].type = ice_proto_type_from_l4_port(false, hdr->l3_key.ip_proto);
+       if ((flags & ICE_TC_FLWR_FIELD_ENC_DEST_L4_PORT) &&
+           hdr->l3_key.ip_proto == IPPROTO_UDP) {
+               list[i].type = ICE_UDP_OF;
                list[i].h_u.l4_hdr.dst_port = hdr->l4_key.dst_port;
                list[i].m_u.l4_hdr.dst_port = hdr->l4_mask.dst_port;
                i++;
@@ -317,7 +310,7 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
                     ICE_TC_FLWR_FIELD_SRC_L4_PORT)) {
                struct ice_tc_l4_hdr *l4_key, *l4_mask;
 
-               list[i].type = ice_proto_type_from_l4_port(inner, headers->l3_key.ip_proto);
+               list[i].type = ice_proto_type_from_l4_port(headers->l3_key.ip_proto);
                l4_key = &headers->l4_key;
                l4_mask = &headers->l4_mask;
 
@@ -802,7 +795,8 @@ ice_parse_tunnel_attr(struct net_device *dev, struct flow_rule *rule,
                headers->l3_mask.ttl = match.mask->ttl;
        }
 
-       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) &&
+           fltr->tunnel_type != TNL_VXLAN && fltr->tunnel_type != TNL_GENEVE) {
                struct flow_match_ports match;
 
                flow_rule_match_enc_ports(rule, &match);
index 217ff5e..6427e7e 100644 (file)
@@ -1617,6 +1617,7 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
                ice_vc_set_default_allowlist(vf);
 
                ice_vf_fdir_exit(vf);
+               ice_vf_fdir_init(vf);
                /* clean VF control VSI when resetting VFs since it should be
                 * setup only when VF creates its first FDIR rule.
                 */
@@ -1747,6 +1748,7 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
        }
 
        ice_vf_fdir_exit(vf);
+       ice_vf_fdir_init(vf);
        /* clean VF control VSI when resetting VF since it should be setup
         * only when VF creates its first FDIR rule.
         */
@@ -2021,6 +2023,10 @@ static int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs)
        if (ret)
                goto err_unroll_sriov;
 
+       /* rearm global interrupts */
+       if (test_and_clear_bit(ICE_OICR_INTR_DIS, pf->state))
+               ice_irq_dynamic_ena(hw, NULL, NULL);
+
        return 0;
 
 err_unroll_sriov:
index fd54d3e..b597b8b 100644 (file)
@@ -7648,6 +7648,20 @@ static int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf,
        struct vf_mac_filter *entry = NULL;
        int ret = 0;
 
+       if ((vf_data->flags & IGB_VF_FLAG_PF_SET_MAC) &&
+           !vf_data->trusted) {
+               dev_warn(&pdev->dev,
+                        "VF %d requested MAC filter but is administratively denied\n",
+                         vf);
+               return -EINVAL;
+       }
+       if (!is_valid_ether_addr(addr)) {
+               dev_warn(&pdev->dev,
+                        "VF %d attempted to set invalid MAC filter\n",
+                         vf);
+               return -EINVAL;
+       }
+
        switch (info) {
        case E1000_VF_MAC_FILTER_CLR:
                /* remove all unicast MAC filters related to the current VF */
@@ -7661,20 +7675,6 @@ static int igb_set_vf_mac_filter(struct igb_adapter *adapter, const int vf,
                }
                break;
        case E1000_VF_MAC_FILTER_ADD:
-               if ((vf_data->flags & IGB_VF_FLAG_PF_SET_MAC) &&
-                   !vf_data->trusted) {
-                       dev_warn(&pdev->dev,
-                                "VF %d requested MAC filter but is administratively denied\n",
-                                vf);
-                       return -EINVAL;
-               }
-               if (!is_valid_ether_addr(addr)) {
-                       dev_warn(&pdev->dev,
-                                "VF %d attempted to set invalid MAC filter\n",
-                                vf);
-                       return -EINVAL;
-               }
-
                /* try to find empty slot in the list */
                list_for_each(pos, &adapter->vf_macs.l) {
                        entry = list_entry(pos, struct vf_mac_filter, l);
index 74ccd62..4d988da 100644 (file)
@@ -2859,6 +2859,7 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
 err_hw_init:
+       netif_napi_del(&adapter->rx_ring->napi);
        kfree(adapter->tx_ring);
        kfree(adapter->rx_ring);
 err_sw_init:
index b2ef9fd..b6807e1 100644 (file)
@@ -636,7 +636,7 @@ s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
                ltrv = rd32(IGC_LTRMAXV);
                if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
                        ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
-                              (scale_min << IGC_LTRMAXV_SCALE_SHIFT);
+                              (scale_max << IGC_LTRMAXV_SCALE_SHIFT);
                        wr32(IGC_LTRMAXV, ltrv);
                }
        }
index 0f9f022..45e2ec4 100644 (file)
@@ -5531,6 +5531,10 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
        if (!speed && hw->mac.ops.get_link_capabilities) {
                ret = hw->mac.ops.get_link_capabilities(hw, &speed,
                                                        &autoneg);
+               /* remove NBASE-T speeds from default autonegotiation
+                * to accommodate broken network switches in the field
+                * which cannot cope with advertised NBASE-T speeds
+                */
                speed &= ~(IXGBE_LINK_SPEED_5GB_FULL |
                           IXGBE_LINK_SPEED_2_5GB_FULL);
        }
index 9724ffb..e4b50c7 100644 (file)
@@ -3405,6 +3405,9 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
        /* flush pending Tx transactions */
        ixgbe_clear_tx_pending(hw);
 
+       /* set MDIO speed before talking to the PHY in case it's the 1st time */
+       ixgbe_set_mdio_speed(hw);
+
        /* PHY ops must be identified and initialized prior to reset */
        status = hw->phy.ops.init(hw);
        if (status == IXGBE_ERR_SFP_NOT_SUPPORTED ||
index 6480696..6da8a59 100644 (file)
@@ -2960,11 +2960,11 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
        mvpp2_rxq_status_update(port, rxq->id, 0, rxq->size);
 
        if (priv->percpu_pools) {
-               err = xdp_rxq_info_reg(&rxq->xdp_rxq_short, port->dev, rxq->id, 0);
+               err = xdp_rxq_info_reg(&rxq->xdp_rxq_short, port->dev, rxq->logic_rxq, 0);
                if (err < 0)
                        goto err_free_dma;
 
-               err = xdp_rxq_info_reg(&rxq->xdp_rxq_long, port->dev, rxq->id, 0);
+               err = xdp_rxq_info_reg(&rxq->xdp_rxq_long, port->dev, rxq->logic_rxq, 0);
                if (err < 0)
                        goto err_unregister_rxq_short;
 
index 0ef68fd..61c2090 100644 (file)
@@ -5,6 +5,8 @@
  *
  */
 
+#include <linux/module.h>
+
 #include "otx2_common.h"
 #include "otx2_ptp.h"
 
index 217e3b3..c34833f 100644 (file)
@@ -8494,7 +8494,8 @@ mlxsw_sp_rif_mac_profile_replace(struct mlxsw_sp *mlxsw_sp,
        u8 mac_profile;
        int err;
 
-       if (!mlxsw_sp_rif_mac_profile_is_shared(rif))
+       if (!mlxsw_sp_rif_mac_profile_is_shared(rif) &&
+           !mlxsw_sp_rif_mac_profile_find(mlxsw_sp, new_mac))
                return mlxsw_sp_rif_mac_profile_edit(rif, new_mac);
 
        err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, new_mac,
index 34b971f..078d6a5 100644 (file)
@@ -480,16 +480,16 @@ static int mana_hwc_create_wq(struct hw_channel_context *hwc,
        if (err)
                goto out;
 
-       err = mana_hwc_alloc_dma_buf(hwc, q_depth, max_msg_size,
-                                    &hwc_wq->msg_buf);
-       if (err)
-               goto out;
-
        hwc_wq->hwc = hwc;
        hwc_wq->gdma_wq = queue;
        hwc_wq->queue_depth = q_depth;
        hwc_wq->hwc_cq = hwc_cq;
 
+       err = mana_hwc_alloc_dma_buf(hwc, q_depth, max_msg_size,
+                                    &hwc_wq->msg_buf);
+       if (err)
+               goto out;
+
        *hwc_wq_ptr = hwc_wq;
        return 0;
 out:
index d7ac030..34c0d2d 100644 (file)
@@ -803,8 +803,10 @@ int nfp_cpp_area_cache_add(struct nfp_cpp *cpp, size_t size)
                return -ENOMEM;
 
        cache = kzalloc(sizeof(*cache), GFP_KERNEL);
-       if (!cache)
+       if (!cache) {
+               nfp_cpp_area_free(area);
                return -ENOMEM;
+       }
 
        cache->id = 0;
        cache->addr = 0;
index 065e900..999abcf 100644 (file)
@@ -1643,6 +1643,13 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        data_split = true;
                }
        } else {
+               if (unlikely(skb->len > ETH_TX_MAX_NON_LSO_PKT_LEN)) {
+                       DP_ERR(edev, "Unexpected non LSO skb length = 0x%x\n", skb->len);
+                       qede_free_failed_tx_pkt(txq, first_bd, 0, false);
+                       qede_update_tx_producer(txq);
+                       return NETDEV_TX_OK;
+               }
+
                val |= ((skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) <<
                         ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT);
        }
index 1e6d72a..71523d7 100644 (file)
@@ -3480,20 +3480,19 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
 
        spin_lock_irqsave(&qdev->hw_lock, hw_flags);
 
-       err = ql_wait_for_drvr_lock(qdev);
-       if (err) {
-               err = ql_adapter_initialize(qdev);
-               if (err) {
-                       netdev_err(ndev, "Unable to initialize adapter\n");
-                       goto err_init;
-               }
-               netdev_err(ndev, "Releasing driver lock\n");
-               ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
-       } else {
+       if (!ql_wait_for_drvr_lock(qdev)) {
                netdev_err(ndev, "Could not acquire driver lock\n");
+               err = -ENODEV;
                goto err_lock;
        }
 
+       err = ql_adapter_initialize(qdev);
+       if (err) {
+               netdev_err(ndev, "Unable to initialize adapter\n");
+               goto err_init;
+       }
+       ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+
        spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 
        set_bit(QL_ADAPTER_UP, &qdev->flags);
index 6aa8122..e77a5cb 100644 (file)
@@ -609,6 +609,9 @@ static size_t ef100_update_stats(struct efx_nic *efx,
        ef100_common_stat_mask(mask);
        ef100_ethtool_stat_mask(mask);
 
+       if (!mc_stats)
+               return 0;
+
        efx_nic_copy_stats(efx, mc_stats);
        efx_nic_update_stats(ef100_stat_desc, EF100_STAT_COUNT, mask,
                             stats, mc_stats, false);
index 6924a6a..c469abc 100644 (file)
@@ -33,6 +33,7 @@ struct rk_gmac_ops {
        void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
        void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
        void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
+       bool regs_valid;
        u32 regs[];
 };
 
@@ -1092,6 +1093,7 @@ static const struct rk_gmac_ops rk3568_ops = {
        .set_to_rmii = rk3568_set_to_rmii,
        .set_rgmii_speed = rk3568_set_gmac_speed,
        .set_rmii_speed = rk3568_set_gmac_speed,
+       .regs_valid = true,
        .regs = {
                0xfe2a0000, /* gmac0 */
                0xfe010000, /* gmac1 */
@@ -1383,7 +1385,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
         * to be distinguished.
         */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res) {
+       if (res && ops->regs_valid) {
                int i = 0;
 
                while (ops->regs[i]) {
index 5f12973..873b9e3 100644 (file)
@@ -172,6 +172,19 @@ struct stmmac_flow_entry {
        int is_l4;
 };
 
+/* Rx Frame Steering */
+enum stmmac_rfs_type {
+       STMMAC_RFS_T_VLAN,
+       STMMAC_RFS_T_MAX,
+};
+
+struct stmmac_rfs_entry {
+       unsigned long cookie;
+       int in_use;
+       int type;
+       int tc;
+};
+
 struct stmmac_priv {
        /* Frequently used values are kept adjacent for cache effect */
        u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
@@ -289,6 +302,10 @@ struct stmmac_priv {
        struct stmmac_tc_entry *tc_entries;
        unsigned int flow_entries_max;
        struct stmmac_flow_entry *flow_entries;
+       unsigned int rfs_entries_max[STMMAC_RFS_T_MAX];
+       unsigned int rfs_entries_cnt[STMMAC_RFS_T_MAX];
+       unsigned int rfs_entries_total;
+       struct stmmac_rfs_entry *rfs_entries;
 
        /* Pulse Per Second output */
        struct stmmac_pps_cfg pps[STMMAC_PPS_MAX];
index da8306f..8ded4be 100644 (file)
@@ -1461,16 +1461,20 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
 {
        struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
        struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+       gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
+
+       if (priv->dma_cap.addr64 <= 32)
+               gfp |= GFP_DMA32;
 
        if (!buf->page) {
-               buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
+               buf->page = page_pool_alloc_pages(rx_q->page_pool, gfp);
                if (!buf->page)
                        return -ENOMEM;
                buf->page_offset = stmmac_rx_offset(priv);
        }
 
        if (priv->sph && !buf->sec_page) {
-               buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
+               buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp);
                if (!buf->sec_page)
                        return -ENOMEM;
 
@@ -4482,6 +4486,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
        struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
        int dirty = stmmac_rx_dirty(priv, queue);
        unsigned int entry = rx_q->dirty_rx;
+       gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN);
+
+       if (priv->dma_cap.addr64 <= 32)
+               gfp |= GFP_DMA32;
 
        while (dirty-- > 0) {
                struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry];
@@ -4494,13 +4502,13 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
                        p = rx_q->dma_rx + entry;
 
                if (!buf->page) {
-                       buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
+                       buf->page = page_pool_alloc_pages(rx_q->page_pool, gfp);
                        if (!buf->page)
                                break;
                }
 
                if (priv->sph && !buf->sec_page) {
-                       buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
+                       buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp);
                        if (!buf->sec_page)
                                break;
 
index 1c4ea0b..d0a2b28 100644 (file)
@@ -232,11 +232,33 @@ static int tc_setup_cls_u32(struct stmmac_priv *priv,
        }
 }
 
+static int tc_rfs_init(struct stmmac_priv *priv)
+{
+       int i;
+
+       priv->rfs_entries_max[STMMAC_RFS_T_VLAN] = 8;
+
+       for (i = 0; i < STMMAC_RFS_T_MAX; i++)
+               priv->rfs_entries_total += priv->rfs_entries_max[i];
+
+       priv->rfs_entries = devm_kcalloc(priv->device,
+                                        priv->rfs_entries_total,
+                                        sizeof(*priv->rfs_entries),
+                                        GFP_KERNEL);
+       if (!priv->rfs_entries)
+               return -ENOMEM;
+
+       dev_info(priv->device, "Enabled RFS Flow TC (entries=%d)\n",
+                priv->rfs_entries_total);
+
+       return 0;
+}
+
 static int tc_init(struct stmmac_priv *priv)
 {
        struct dma_features *dma_cap = &priv->dma_cap;
        unsigned int count;
-       int i;
+       int ret, i;
 
        if (dma_cap->l3l4fnum) {
                priv->flow_entries_max = dma_cap->l3l4fnum;
@@ -250,10 +272,14 @@ static int tc_init(struct stmmac_priv *priv)
                for (i = 0; i < priv->flow_entries_max; i++)
                        priv->flow_entries[i].idx = i;
 
-               dev_info(priv->device, "Enabled Flow TC (entries=%d)\n",
+               dev_info(priv->device, "Enabled L3L4 Flow TC (entries=%d)\n",
                         priv->flow_entries_max);
        }
 
+       ret = tc_rfs_init(priv);
+       if (ret)
+               return -ENOMEM;
+
        if (!priv->plat->fpe_cfg) {
                priv->plat->fpe_cfg = devm_kzalloc(priv->device,
                                                   sizeof(*priv->plat->fpe_cfg),
@@ -607,16 +633,45 @@ static int tc_del_flow(struct stmmac_priv *priv,
        return ret;
 }
 
+static struct stmmac_rfs_entry *tc_find_rfs(struct stmmac_priv *priv,
+                                           struct flow_cls_offload *cls,
+                                           bool get_free)
+{
+       int i;
+
+       for (i = 0; i < priv->rfs_entries_total; i++) {
+               struct stmmac_rfs_entry *entry = &priv->rfs_entries[i];
+
+               if (entry->cookie == cls->cookie)
+                       return entry;
+               if (get_free && entry->in_use == false)
+                       return entry;
+       }
+
+       return NULL;
+}
+
 #define VLAN_PRIO_FULL_MASK (0x07)
 
 static int tc_add_vlan_flow(struct stmmac_priv *priv,
                            struct flow_cls_offload *cls)
 {
+       struct stmmac_rfs_entry *entry = tc_find_rfs(priv, cls, false);
        struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
        struct flow_dissector *dissector = rule->match.dissector;
        int tc = tc_classid_to_hwtc(priv->dev, cls->classid);
        struct flow_match_vlan match;
 
+       if (!entry) {
+               entry = tc_find_rfs(priv, cls, true);
+               if (!entry)
+                       return -ENOENT;
+       }
+
+       if (priv->rfs_entries_cnt[STMMAC_RFS_T_VLAN] >=
+           priv->rfs_entries_max[STMMAC_RFS_T_VLAN])
+               return -ENOENT;
+
        /* Nothing to do here */
        if (!dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_VLAN))
                return -EINVAL;
@@ -638,6 +693,12 @@ static int tc_add_vlan_flow(struct stmmac_priv *priv,
 
                prio = BIT(match.key->vlan_priority);
                stmmac_rx_queue_prio(priv, priv->hw, prio, tc);
+
+               entry->in_use = true;
+               entry->cookie = cls->cookie;
+               entry->tc = tc;
+               entry->type = STMMAC_RFS_T_VLAN;
+               priv->rfs_entries_cnt[STMMAC_RFS_T_VLAN]++;
        }
 
        return 0;
@@ -646,20 +707,19 @@ static int tc_add_vlan_flow(struct stmmac_priv *priv,
 static int tc_del_vlan_flow(struct stmmac_priv *priv,
                            struct flow_cls_offload *cls)
 {
-       struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
-       struct flow_dissector *dissector = rule->match.dissector;
-       int tc = tc_classid_to_hwtc(priv->dev, cls->classid);
+       struct stmmac_rfs_entry *entry = tc_find_rfs(priv, cls, false);
 
-       /* Nothing to do here */
-       if (!dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_VLAN))
-               return -EINVAL;
+       if (!entry || !entry->in_use || entry->type != STMMAC_RFS_T_VLAN)
+               return -ENOENT;
 
-       if (tc < 0) {
-               netdev_err(priv->dev, "Invalid traffic class\n");
-               return -EINVAL;
-       }
+       stmmac_rx_queue_prio(priv, priv->hw, 0, entry->tc);
+
+       entry->in_use = false;
+       entry->cookie = 0;
+       entry->tc = 0;
+       entry->type = 0;
 
-       stmmac_rx_queue_prio(priv, priv->hw, 0, tc);
+       priv->rfs_entries_cnt[STMMAC_RFS_T_VLAN]--;
 
        return 0;
 }
index c092cb6..ffbbda8 100644 (file)
@@ -1844,13 +1844,14 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                if (ret < 0) {
                        dev_err(dev, "%pOF error reading port_id %d\n",
                                port_np, ret);
-                       return ret;
+                       goto of_node_put;
                }
 
                if (!port_id || port_id > common->port_num) {
                        dev_err(dev, "%pOF has invalid port_id %u %s\n",
                                port_np, port_id, port_np->name);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto of_node_put;
                }
 
                port = am65_common_get_port(common, port_id);
@@ -1866,8 +1867,10 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                                (AM65_CPSW_NU_FRAM_PORT_OFFSET * (port_id - 1));
 
                port->slave.mac_sl = cpsw_sl_get("am65", dev, port->port_base);
-               if (IS_ERR(port->slave.mac_sl))
-                       return PTR_ERR(port->slave.mac_sl);
+               if (IS_ERR(port->slave.mac_sl)) {
+                       ret = PTR_ERR(port->slave.mac_sl);
+                       goto of_node_put;
+               }
 
                port->disabled = !of_device_is_available(port_np);
                if (port->disabled) {
@@ -1880,7 +1883,7 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                        ret = PTR_ERR(port->slave.ifphy);
                        dev_err(dev, "%pOF error retrieving port phy: %d\n",
                                port_np, ret);
-                       return ret;
+                       goto of_node_put;
                }
 
                port->slave.mac_only =
@@ -1889,10 +1892,12 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                /* get phy/link info */
                if (of_phy_is_fixed_link(port_np)) {
                        ret = of_phy_register_fixed_link(port_np);
-                       if (ret)
-                               return dev_err_probe(dev, ret,
+                       if (ret) {
+                               ret = dev_err_probe(dev, ret,
                                                     "failed to register fixed-link phy %pOF\n",
                                                     port_np);
+                               goto of_node_put;
+                       }
                        port->slave.phy_node = of_node_get(port_np);
                } else {
                        port->slave.phy_node =
@@ -1902,14 +1907,15 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                if (!port->slave.phy_node) {
                        dev_err(dev,
                                "slave[%d] no phy found\n", port_id);
-                       return -ENODEV;
+                       ret = -ENODEV;
+                       goto of_node_put;
                }
 
                ret = of_get_phy_mode(port_np, &port->slave.phy_if);
                if (ret) {
                        dev_err(dev, "%pOF read phy-mode err %d\n",
                                port_np, ret);
-                       return ret;
+                       goto of_node_put;
                }
 
                ret = of_get_mac_address(port_np, port->slave.mac_addr);
@@ -1932,6 +1938,11 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
        }
 
        return 0;
+
+of_node_put:
+       of_node_put(port_np);
+       of_node_put(node);
+       return ret;
 }
 
 static void am65_cpsw_pcpu_stats_free(void *data)
index 90aafb5..a438202 100644 (file)
@@ -514,6 +514,7 @@ nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
                                goto err_free;
                        key = nmap->entry[i].key;
                        *key = i;
+                       memset(nmap->entry[i].value, 0, offmap->map.value_size);
                }
        }
 
index 0ab6a40..a6a713b 100644 (file)
@@ -77,7 +77,10 @@ static int nsim_set_ringparam(struct net_device *dev,
 {
        struct netdevsim *ns = netdev_priv(dev);
 
-       memcpy(&ns->ethtool.ring, ring, sizeof(ns->ethtool.ring));
+       ns->ethtool.ring.rx_pending = ring->rx_pending;
+       ns->ethtool.ring.rx_jumbo_pending = ring->rx_jumbo_pending;
+       ns->ethtool.ring.rx_mini_pending = ring->rx_mini_pending;
+       ns->ethtool.ring.tx_pending = ring->tx_pending;
        return 0;
 }
 
index c204067..c198722 100644 (file)
@@ -460,6 +460,9 @@ static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
 
                if (addr == mdiodev->addr) {
                        device_set_node(dev, of_fwnode_handle(child));
+                       /* The refcount on "child" is passed to the mdio
+                        * device. Do _not_ use of_node_put(child) here.
+                        */
                        return;
                }
        }
index 5904546..ea82ea5 100644 (file)
@@ -1388,6 +1388,7 @@ EXPORT_SYMBOL_GPL(phylink_stop);
  * @mac_wol: true if the MAC needs to receive packets for Wake-on-Lan
  *
  * Handle a network device suspend event. There are several cases:
+ *
  * - If Wake-on-Lan is not active, we can bring down the link between
  *   the MAC and PHY by calling phylink_stop().
  * - If Wake-on-Lan is active, and being handled only by the PHY, we
index 24753a4..e303b52 100644 (file)
@@ -181,6 +181,8 @@ static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)
                min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth32);
 
        max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
+       if (max == 0)
+               max = CDC_NCM_NTB_MAX_SIZE_TX; /* dwNtbOutMaxSize not set */
 
        /* some devices set dwNtbOutMaxSize too low for the above default */
        min = min(min, max);
index 8cd265f..075f8ab 100644 (file)
@@ -76,6 +76,8 @@
 #define LAN7801_USB_PRODUCT_ID         (0x7801)
 #define LAN78XX_EEPROM_MAGIC           (0x78A5)
 #define LAN78XX_OTP_MAGIC              (0x78F3)
+#define AT29M2AF_USB_VENDOR_ID         (0x07C9)
+#define AT29M2AF_USB_PRODUCT_ID        (0x0012)
 
 #define        MII_READ                        1
 #define        MII_WRITE                       0
@@ -4734,6 +4736,10 @@ static const struct usb_device_id products[] = {
        /* LAN7801 USB Gigabit Ethernet Device */
        USB_DEVICE(LAN78XX_USB_VENDOR_ID, LAN7801_USB_PRODUCT_ID),
        },
+       {
+       /* ATM2-AF USB Gigabit Ethernet Device */
+       USB_DEVICE(AT29M2AF_USB_VENDOR_ID, AT29M2AF_USB_PRODUCT_ID),
+       },
        {},
 };
 MODULE_DEVICE_TABLE(usb, products);
index 86b814e..f510e82 100644 (file)
@@ -1358,6 +1358,7 @@ static const struct usb_device_id products[] = {
        {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */
        {QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */
        {QMI_QUIRK_SET_DTR(0x1bc7, 0x1060, 2)}, /* Telit LN920 */
+       {QMI_QUIRK_SET_DTR(0x1bc7, 0x1070, 2)}, /* Telit FN990 */
        {QMI_FIXED_INTF(0x1bc7, 0x1100, 3)},    /* Telit ME910 */
        {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)},    /* Telit ME910 dual modem */
        {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
index 55db6a3..b107835 100644 (file)
@@ -733,7 +733,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
                pr_debug("%s: rx error: len %u exceeds max size %d\n",
                         dev->name, len, GOOD_PACKET_LEN);
                dev->stats.rx_length_errors++;
-               goto err_len;
+               goto err;
        }
 
        if (likely(!vi->xdp_enabled)) {
@@ -825,10 +825,8 @@ static struct sk_buff *receive_small(struct net_device *dev,
 
 skip_xdp:
        skb = build_skb(buf, buflen);
-       if (!skb) {
-               put_page(page);
+       if (!skb)
                goto err;
-       }
        skb_reserve(skb, headroom - delta);
        skb_put(skb, len);
        if (!xdp_prog) {
@@ -839,13 +837,12 @@ skip_xdp:
        if (metasize)
                skb_metadata_set(skb, metasize);
 
-err:
        return skb;
 
 err_xdp:
        rcu_read_unlock();
        stats->xdp_drops++;
-err_len:
+err:
        stats->drops++;
        put_page(page);
 xdp_xmit:
index 14fae31..fd407c0 100644 (file)
@@ -3261,7 +3261,7 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
 
 #ifdef CONFIG_PCI_MSI
        if (adapter->intr.type == VMXNET3_IT_MSIX) {
-               int i, nvec;
+               int i, nvec, nvec_allocated;
 
                nvec  = adapter->share_intr == VMXNET3_INTR_TXSHARE ?
                        1 : adapter->num_tx_queues;
@@ -3274,14 +3274,15 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
                for (i = 0; i < nvec; i++)
                        adapter->intr.msix_entries[i].entry = i;
 
-               nvec = vmxnet3_acquire_msix_vectors(adapter, nvec);
-               if (nvec < 0)
+               nvec_allocated = vmxnet3_acquire_msix_vectors(adapter, nvec);
+               if (nvec_allocated < 0)
                        goto msix_err;
 
                /* If we cannot allocate one MSIx vector per queue
                 * then limit the number of rx queues to 1
                 */
-               if (nvec == VMXNET3_LINUX_MIN_MSIX_VECT) {
+               if (nvec_allocated == VMXNET3_LINUX_MIN_MSIX_VECT &&
+                   nvec != VMXNET3_LINUX_MIN_MSIX_VECT) {
                        if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
                            || adapter->num_rx_queues != 1) {
                                adapter->share_intr = VMXNET3_INTR_TXSHARE;
@@ -3291,14 +3292,14 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
                        }
                }
 
-               adapter->intr.num_intrs = nvec;
+               adapter->intr.num_intrs = nvec_allocated;
                return;
 
 msix_err:
                /* If we cannot allocate MSIx vectors use only one rx queue */
                dev_info(&adapter->pdev->dev,
                         "Failed to enable MSI-X, error %d. "
-                        "Limiting #rx queues to 1, try MSI.\n", nvec);
+                        "Limiting #rx queues to 1, try MSI.\n", nvec_allocated);
 
                adapter->intr.type = VMXNET3_IT_MSI;
        }
index 131c745..b2242a0 100644 (file)
@@ -770,8 +770,6 @@ static struct sk_buff *vrf_ip6_out_direct(struct net_device *vrf_dev,
 
        skb->dev = vrf_dev;
 
-       vrf_nf_set_untracked(skb);
-
        err = nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk,
                      skb, NULL, vrf_dev, vrf_ip6_out_direct_finish);
 
@@ -792,6 +790,8 @@ static struct sk_buff *vrf_ip6_out(struct net_device *vrf_dev,
        if (rt6_need_strict(&ipv6_hdr(skb)->daddr))
                return skb;
 
+       vrf_nf_set_untracked(skb);
+
        if (qdisc_tx_is_default(vrf_dev) ||
            IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
                return vrf_ip6_out_direct(vrf_dev, sk, skb);
@@ -1000,8 +1000,6 @@ static struct sk_buff *vrf_ip_out_direct(struct net_device *vrf_dev,
 
        skb->dev = vrf_dev;
 
-       vrf_nf_set_untracked(skb);
-
        err = nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, sk,
                      skb, NULL, vrf_dev, vrf_ip_out_direct_finish);
 
@@ -1023,6 +1021,8 @@ static struct sk_buff *vrf_ip_out(struct net_device *vrf_dev,
            ipv4_is_lbcast(ip_hdr(skb)->daddr))
                return skb;
 
+       vrf_nf_set_untracked(skb);
+
        if (qdisc_tx_is_default(vrf_dev) ||
            IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
                return vrf_ip_out_direct(vrf_dev, sk, skb);
index 26c7ae2..49c0b1a 100644 (file)
@@ -533,7 +533,11 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci,
                ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
                break;
        case ATH11K_MHI_RESUME:
-               ret = mhi_pm_resume(ab_pci->mhi_ctrl);
+               /* Do force MHI resume as some devices like QCA6390, WCN6855
+                * are not in M3 state but they are functional. So just ignore
+                * the MHI state while resuming.
+                */
+               ret = mhi_pm_resume_force(ab_pci->mhi_ctrl);
                break;
        case ATH11K_MHI_TRIGGER_RDDM:
                ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl);
index 5bf2318..3a1a35b 100644 (file)
@@ -7,16 +7,20 @@ config BRCMSMAC
        depends on MAC80211
        depends on BCMA_POSSIBLE
        select BCMA
-       select NEW_LEDS if BCMA_DRIVER_GPIO
-       select LEDS_CLASS if BCMA_DRIVER_GPIO
        select BRCMUTIL
        select FW_LOADER
        select CORDIC
        help
          This module adds support for PCIe wireless adapters based on Broadcom
-         IEEE802.11n SoftMAC chipsets. It also has WLAN led support, which will
-         be available if you select BCMA_DRIVER_GPIO. If you choose to build a
-         module, the driver will be called brcmsmac.ko.
+         IEEE802.11n SoftMAC chipsets. If you choose to build a module, the
+         driver will be called brcmsmac.ko.
+
+config BRCMSMAC_LEDS
+       def_bool BRCMSMAC && BCMA_DRIVER_GPIO && MAC80211_LEDS
+       help
+         The brcmsmac LED support depends on the presence of the
+         BCMA_DRIVER_GPIO driver, and it only works if LED support
+         is enabled and reachable from the driver module.
 
 source "drivers/net/wireless/broadcom/brcm80211/brcmfmac/Kconfig"
 
index 482d773..0907577 100644 (file)
@@ -42,6 +42,6 @@ brcmsmac-y := \
        brcms_trace_events.o \
        debug.o
 
-brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o
+brcmsmac-$(CONFIG_BRCMSMAC_LEDS) += led.o
 
 obj-$(CONFIG_BRCMSMAC) += brcmsmac.o
index d65f5c2..2a5cbeb 100644 (file)
@@ -24,7 +24,7 @@ struct brcms_led {
        struct gpio_desc *gpiod;
 };
 
-#ifdef CONFIG_BCMA_DRIVER_GPIO
+#ifdef CONFIG_BRCMSMAC_LEDS
 void brcms_led_unregister(struct brcms_info *wl);
 int brcms_led_register(struct brcms_info *wl);
 #else
index 24fe3f6..7eacc8e 100644 (file)
@@ -2,14 +2,13 @@
 config IWLEGACY
        tristate
        select FW_LOADER
-       select NEW_LEDS
-       select LEDS_CLASS
        select LEDS_TRIGGERS
        select MAC80211_LEDS
 
 config IWL4965
        tristate "Intel Wireless WiFi 4965AGN (iwl4965)"
        depends on PCI && MAC80211
+       depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211
        select IWLEGACY
        help
          This option enables support for
@@ -38,6 +37,7 @@ config IWL4965
 config IWL3945
        tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
        depends on PCI && MAC80211
+       depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211
        select IWLEGACY
        help
          Select to build the driver supporting the:
index 1085afb..418ae4f 100644 (file)
@@ -47,7 +47,7 @@ if IWLWIFI
 
 config IWLWIFI_LEDS
        bool
-       depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI
+       depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211
        depends on IWLMVM || IWLDVM
        select LEDS_TRIGGERS
        select MAC80211_LEDS
index bdd4ee4..76e0b7b 100644 (file)
@@ -269,17 +269,18 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
        u8 rate_plcp;
        u32 rate_flags = 0;
        bool is_cck;
-       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 
        /* info->control is only relevant for non HW rate control */
        if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) {
+               struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
                /* HT rate doesn't make sense for a non data frame */
                WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS &&
                          !ieee80211_is_data(fc),
                          "Got a HT rate (flags:0x%x/mcs:%d/fc:0x%x/state:%d) for a non data frame\n",
                          info->control.rates[0].flags,
                          info->control.rates[0].idx,
-                         le16_to_cpu(fc), mvmsta->sta_state);
+                         le16_to_cpu(fc), sta ? mvmsta->sta_state : -1);
 
                rate_idx = info->control.rates[0].idx;
        }
index 79ab850..c78ae4b 100644 (file)
@@ -34,4 +34,4 @@ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
 obj-$(CONFIG_MT7603E) += mt7603/
 obj-$(CONFIG_MT7615_COMMON) += mt7615/
 obj-$(CONFIG_MT7915E) += mt7915/
-obj-$(CONFIG_MT7921E) += mt7921/
+obj-$(CONFIG_MT7921_COMMON) += mt7921/
index cff3b43..12c03da 100644 (file)
@@ -181,9 +181,9 @@ void ipc_imem_hrtimer_stop(struct hrtimer *hr_timer)
 bool ipc_imem_ul_write_td(struct iosm_imem *ipc_imem)
 {
        struct ipc_mem_channel *channel;
+       bool hpda_ctrl_pending = false;
        struct sk_buff_head *ul_list;
        bool hpda_pending = false;
-       bool forced_hpdu = false;
        struct ipc_pipe *pipe;
        int i;
 
@@ -200,15 +200,19 @@ bool ipc_imem_ul_write_td(struct iosm_imem *ipc_imem)
                ul_list = &channel->ul_list;
 
                /* Fill the transfer descriptor with the uplink buffer info. */
-               hpda_pending |= ipc_protocol_ul_td_send(ipc_imem->ipc_protocol,
+               if (!ipc_imem_check_wwan_ips(channel)) {
+                       hpda_ctrl_pending |=
+                               ipc_protocol_ul_td_send(ipc_imem->ipc_protocol,
                                                        pipe, ul_list);
-
-               /* forced HP update needed for non data channels */
-               if (hpda_pending && !ipc_imem_check_wwan_ips(channel))
-                       forced_hpdu = true;
+               } else {
+                       hpda_pending |=
+                               ipc_protocol_ul_td_send(ipc_imem->ipc_protocol,
+                                                       pipe, ul_list);
+               }
        }
 
-       if (forced_hpdu) {
+       /* forced HP update needed for non data channels */
+       if (hpda_ctrl_pending) {
                hpda_pending = false;
                ipc_protocol_doorbell_trigger(ipc_imem->ipc_protocol,
                                              IPC_HP_UL_WRITE_TD);
@@ -527,6 +531,9 @@ static void ipc_imem_run_state_worker(struct work_struct *instance)
                return;
        }
 
+       if (test_and_clear_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag))
+               ipc_devlink_deinit(ipc_imem->ipc_devlink);
+
        if (!ipc_imem_setup_cp_mux_cap_init(ipc_imem, &mux_cfg))
                ipc_imem->mux = ipc_mux_init(&mux_cfg, ipc_imem);
 
@@ -1167,7 +1174,7 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem)
                ipc_port_deinit(ipc_imem->ipc_port);
        }
 
-       if (ipc_imem->ipc_devlink)
+       if (test_and_clear_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag))
                ipc_devlink_deinit(ipc_imem->ipc_devlink);
 
        ipc_imem_device_ipc_uninit(ipc_imem);
@@ -1263,7 +1270,6 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
 
        ipc_imem->pci_device_id = device_id;
 
-       ipc_imem->ev_cdev_write_pending = false;
        ipc_imem->cp_version = 0;
        ipc_imem->device_sleep = IPC_HOST_SLEEP_ENTER_SLEEP;
 
@@ -1331,6 +1337,8 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id,
 
                if (ipc_flash_link_establish(ipc_imem))
                        goto devlink_channel_fail;
+
+               set_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag);
        }
        return ipc_imem;
 devlink_channel_fail:
index 6be6708..6b8a837 100644 (file)
@@ -101,6 +101,7 @@ struct ipc_chnl_cfg;
 #define IOSM_CHIP_INFO_SIZE_MAX 100
 
 #define FULLY_FUNCTIONAL 0
+#define IOSM_DEVLINK_INIT 1
 
 /* List of the supported UL/DL pipes. */
 enum ipc_mem_pipes {
@@ -335,8 +336,6 @@ enum ipc_phase {
  *                             process the irq actions.
  * @flag:                      Flag to monitor the state of driver
  * @td_update_timer_suspended: if true then td update timer suspend
- * @ev_cdev_write_pending:     0 means inform the IPC tasklet to pass
- *                             the accumulated uplink buffers to CP.
  * @ev_mux_net_transmit_pending:0 means inform the IPC tasklet to pass
  * @reset_det_n:               Reset detect flag
  * @pcie_wake_n:               Pcie wake flag
@@ -374,7 +373,6 @@ struct iosm_imem {
        u8 ev_irq_pending[IPC_IRQ_VECTORS];
        unsigned long flag;
        u8 td_update_timer_suspended:1,
-          ev_cdev_write_pending:1,
           ev_mux_net_transmit_pending:1,
           reset_det_n:1,
           pcie_wake_n:1;
index 825e8e5..831cdae 100644 (file)
@@ -41,7 +41,6 @@ void ipc_imem_sys_wwan_close(struct iosm_imem *ipc_imem, int if_id,
 static int ipc_imem_tq_cdev_write(struct iosm_imem *ipc_imem, int arg,
                                  void *msg, size_t size)
 {
-       ipc_imem->ev_cdev_write_pending = false;
        ipc_imem_ul_send(ipc_imem);
 
        return 0;
@@ -50,11 +49,6 @@ static int ipc_imem_tq_cdev_write(struct iosm_imem *ipc_imem, int arg,
 /* Through tasklet to do sio write. */
 static int ipc_imem_call_cdev_write(struct iosm_imem *ipc_imem)
 {
-       if (ipc_imem->ev_cdev_write_pending)
-               return -1;
-
-       ipc_imem->ev_cdev_write_pending = true;
-
        return ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_cdev_write, 0,
                                        NULL, 0, false);
 }
@@ -450,6 +444,7 @@ void ipc_imem_sys_devlink_close(struct iosm_devlink *ipc_devlink)
        /* Release the pipe resources */
        ipc_imem_pipe_cleanup(ipc_imem, &channel->ul_pipe);
        ipc_imem_pipe_cleanup(ipc_imem, &channel->dl_pipe);
+       ipc_imem->nr_of_channels--;
 }
 
 void ipc_imem_sys_devlink_notify_rx(struct iosm_devlink *ipc_devlink,
index 4c63564..1af8a45 100644 (file)
@@ -666,6 +666,7 @@ blk_status_t nvme_fail_nonready_command(struct nvme_ctrl *ctrl,
                struct request *rq)
 {
        if (ctrl->state != NVME_CTRL_DELETING_NOIO &&
+           ctrl->state != NVME_CTRL_DELETING &&
            ctrl->state != NVME_CTRL_DEAD &&
            !test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ctrl->flags) &&
            !blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
@@ -1749,9 +1750,20 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
                 */
                if (WARN_ON_ONCE(!(id->flbas & NVME_NS_FLBAS_META_EXT)))
                        return -EINVAL;
-               if (ctrl->max_integrity_segments)
-                       ns->features |=
-                               (NVME_NS_METADATA_SUPPORTED | NVME_NS_EXT_LBAS);
+
+               ns->features |= NVME_NS_EXT_LBAS;
+
+               /*
+                * The current fabrics transport drivers support namespace
+                * metadata formats only if nvme_ns_has_pi() returns true.
+                * Suppress support for all other formats so the namespace will
+                * have a 0 capacity and not be usable through the block stack.
+                *
+                * Note, this check will need to be modified if any drivers
+                * gain the ability to use other metadata formats.
+                */
+               if (ctrl->max_integrity_segments && nvme_ns_has_pi(ns))
+                       ns->features |= NVME_NS_METADATA_SUPPORTED;
        } else {
                /*
                 * For PCIe controllers, we can't easily remap the separate
@@ -2696,8 +2708,9 @@ static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
 
                if (tmp->cntlid == ctrl->cntlid) {
                        dev_err(ctrl->device,
-                               "Duplicate cntlid %u with %s, rejecting\n",
-                               ctrl->cntlid, dev_name(tmp->device));
+                               "Duplicate cntlid %u with %s, subsys %s, rejecting\n",
+                               ctrl->cntlid, dev_name(tmp->device),
+                               subsys->subnqn);
                        return false;
                }
 
index 7f2071f..13e5d50 100644 (file)
@@ -866,7 +866,7 @@ int nvme_mpath_init_identify(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
        }
        if (ana_log_size > ctrl->ana_log_size) {
                nvme_mpath_stop(ctrl);
-               kfree(ctrl->ana_log_buf);
+               nvme_mpath_uninit(ctrl);
                ctrl->ana_log_buf = kmalloc(ana_log_size, GFP_KERNEL);
                if (!ctrl->ana_log_buf)
                        return -ENOMEM;
@@ -886,4 +886,5 @@ void nvme_mpath_uninit(struct nvme_ctrl *ctrl)
 {
        kfree(ctrl->ana_log_buf);
        ctrl->ana_log_buf = NULL;
+       ctrl->ana_log_size = 0;
 }
index b334af8..9b095ee 100644 (file)
@@ -709,7 +709,7 @@ static inline bool nvme_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
                return true;
        if (ctrl->ops->flags & NVME_F_FABRICS &&
            ctrl->state == NVME_CTRL_DELETING)
-               return true;
+               return queue_live;
        return __nvme_check_ready(ctrl, rq, queue_live);
 }
 int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
index bfc259e..9f81beb 100644 (file)
@@ -166,7 +166,10 @@ static int nvme_zone_parse_entry(struct nvme_ns *ns,
        zone.len = ns->zsze;
        zone.capacity = nvme_lba_to_sect(ns, le64_to_cpu(entry->zcap));
        zone.start = nvme_lba_to_sect(ns, le64_to_cpu(entry->zslba));
-       zone.wp = nvme_lba_to_sect(ns, le64_to_cpu(entry->wp));
+       if (zone.cond == BLK_ZONE_COND_FULL)
+               zone.wp = zone.start + zone.len;
+       else
+               zone.wp = nvme_lba_to_sect(ns, le64_to_cpu(entry->wp));
 
        return cb(&zone, idx, data);
 }
index cb6a473..7c1c43c 100644 (file)
@@ -922,7 +922,14 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
        size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length);
        int ret;
 
-       if (!nvme_is_write(cmd->req.cmd) ||
+       /*
+        * This command has not been processed yet, hence we are trying to
+        * figure out if there is still pending data left to receive. If
+        * we don't, we can simply prepare for the next pdu and bail out,
+        * otherwise we will need to prepare a buffer and receive the
+        * stale data before continuing forward.
+        */
+       if (!nvme_is_write(cmd->req.cmd) || !data_len ||
            data_len > cmd->req.port->inline_data_size) {
                nvmet_prepare_receive_pdu(queue);
                return;
index b10f015..2b07677 100644 (file)
@@ -76,6 +76,26 @@ struct device_node *of_irq_find_parent(struct device_node *child)
 }
 EXPORT_SYMBOL_GPL(of_irq_find_parent);
 
+/*
+ * These interrupt controllers abuse interrupt-map for unspeakable
+ * reasons and rely on the core code to *ignore* it (the drivers do
+ * their own parsing of the property).
+ *
+ * If you think of adding to the list for something *new*, think
+ * again. There is a high chance that you will be sent back to the
+ * drawing board.
+ */
+static const char * const of_irq_imap_abusers[] = {
+       "CBEA,platform-spider-pic",
+       "sti,platform-spider-pic",
+       "realtek,rtl-intc",
+       "fsl,ls1021a-extirq",
+       "fsl,ls1043a-extirq",
+       "fsl,ls1088a-extirq",
+       "renesas,rza1-irqc",
+       NULL,
+};
+
 /**
  * of_irq_parse_raw - Low level interrupt tree parsing
  * @addr:      address specifier (start of "reg" property of the device) in be32 format
@@ -159,12 +179,15 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
                /*
                 * Now check if cursor is an interrupt-controller and
                 * if it is then we are done, unless there is an
-                * interrupt-map which takes precedence.
+                * interrupt-map which takes precedence except on one
+                * of these broken platforms that want to parse
+                * interrupt-map themselves for $reason.
                 */
                bool intc = of_property_read_bool(ipar, "interrupt-controller");
 
                imap = of_get_property(ipar, "interrupt-map", &imaplen);
-               if (imap == NULL && intc) {
+               if (intc &&
+                   (!imap || of_device_compatible_match(ipar, of_irq_imap_abusers))) {
                        pr_debug(" -> got it !\n");
                        return 0;
                }
index 93b1411..7fc5135 100644 (file)
@@ -332,8 +332,8 @@ config PCIE_APPLE
          If unsure, say Y if you have an Apple Silicon system.
 
 config PCIE_MT7621
-       tristate "MediaTek MT7621 PCIe Controller"
-       depends on (RALINK && SOC_MT7621) || (MIPS && COMPILE_TEST)
+       bool "MediaTek MT7621 PCIe Controller"
+       depends on SOC_MT7621 || (MIPS && COMPILE_TEST)
        select PHY_MT7621_PCI
        default SOC_MT7621
        help
index c24dab3..722dacd 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 #include <linux/regulator/consumer.h>
+#include <linux/module.h>
 
 #include "pcie-designware.h"
 
index 7b17da2..cfe66bf 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pm_domain.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
+#include <linux/module.h>
 
 #include "pcie-designware.h"
 
index c5300d4..c3b725a 100644 (file)
@@ -32,7 +32,6 @@
 #define PCIE_CORE_DEV_ID_REG                                   0x0
 #define PCIE_CORE_CMD_STATUS_REG                               0x4
 #define PCIE_CORE_DEV_REV_REG                                  0x8
-#define PCIE_CORE_EXP_ROM_BAR_REG                              0x30
 #define PCIE_CORE_PCIEXP_CAP                                   0xc0
 #define PCIE_CORE_ERR_CAPCTL_REG                               0x118
 #define     PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX                   BIT(5)
@@ -774,10 +773,6 @@ advk_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
                *value = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
                return PCI_BRIDGE_EMUL_HANDLED;
 
-       case PCI_ROM_ADDRESS1:
-               *value = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG);
-               return PCI_BRIDGE_EMUL_HANDLED;
-
        case PCI_INTERRUPT_LINE: {
                /*
                 * From the whole 32bit register we support reading from HW only
@@ -810,10 +805,6 @@ advk_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
                advk_writel(pcie, new, PCIE_CORE_CMD_STATUS_REG);
                break;
 
-       case PCI_ROM_ADDRESS1:
-               advk_writel(pcie, new, PCIE_CORE_EXP_ROM_BAR_REG);
-               break;
-
        case PCI_INTERRUPT_LINE:
                if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
                        u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
index 1bf4d75..b090924 100644 (file)
@@ -516,7 +516,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
        int ret, i;
 
        reset = gpiod_get_from_of_node(np, "reset-gpios", 0,
-                                      GPIOD_OUT_LOW, "#PERST");
+                                      GPIOD_OUT_LOW, "PERST#");
        if (IS_ERR(reset))
                return PTR_ERR(reset);
 
@@ -539,12 +539,22 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
 
        rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK);
 
+       /* Assert PERST# before setting up the clock */
+       gpiod_set_value(reset, 1);
+
        ret = apple_pcie_setup_refclk(pcie, port);
        if (ret < 0)
                return ret;
 
+       /* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */
+       usleep_range(100, 200);
+
+       /* Deassert PERST# */
        rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
-       gpiod_set_value(reset, 1);
+       gpiod_set_value(reset, 0);
+
+       /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */
+       msleep(100);
 
        ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat,
                                         stat & PORT_STATUS_READY, 100, 250000);
index 48e3f4e..d84cf30 100644 (file)
@@ -722,9 +722,6 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
                goto out_disable;
        }
 
-       /* Ensure that all table entries are masked. */
-       msix_mask_all(base, tsize);
-
        ret = msix_setup_entries(dev, base, entries, nvec, affd);
        if (ret)
                goto out_disable;
@@ -751,6 +748,16 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
        /* Set MSI-X enabled bits and unmask the function */
        pci_intx_for_msi(dev, 0);
        dev->msix_enabled = 1;
+
+       /*
+        * Ensure that all table entries are masked to prevent
+        * stale entries from firing in a crash kernel.
+        *
+        * Done late to deal with a broken Marvell NVME device
+        * which takes the MSI-X mask bits into account even
+        * when MSI-X is disabled, which prevents MSI delivery.
+        */
+       msix_mask_all(base, tsize);
        pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
 
        pcibios_free_irq(dev);
@@ -777,7 +784,7 @@ out_free:
        free_msi_irqs(dev);
 
 out_disable:
-       pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
+       pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE, 0);
 
        return ret;
 }
index c64c667..0ac9634 100644 (file)
@@ -757,8 +757,8 @@ static int hi3670_pcie_phy_get_resources(struct hi3670_pcie_phy *phy,
                return PTR_ERR(phy->sysctrl);
 
        phy->pmctrl = syscon_regmap_lookup_by_compatible("hisilicon,hi3670-pmctrl");
-       if (IS_ERR(phy->sysctrl))
-               return PTR_ERR(phy->sysctrl);
+       if (IS_ERR(phy->pmctrl))
+               return PTR_ERR(phy->pmctrl);
 
        /* clocks */
        phy->phy_ref_clk = devm_clk_get(dev, "phy_ref");
index 08d178a..aa27c79 100644 (file)
@@ -82,9 +82,9 @@
  * struct mvebu_cp110_utmi - PHY driver data
  *
  * @regs: PHY registers
- * @syscom: Regmap with system controller registers
+ * @syscon: Regmap with system controller registers
  * @dev: device driver handle
- * @caps: PHY capabilities
+ * @ops: phy ops
  */
 struct mvebu_cp110_utmi {
        void __iomem *regs;
index bfff0c8..fec1da4 100644 (file)
@@ -127,12 +127,13 @@ struct phy_drvdata {
 };
 
 /**
- * Write register and read back masked value to confirm it is written
+ * usb_phy_write_readback() - Write register and read back masked value to
+ * confirm it is written
  *
- * @base - QCOM DWC3 PHY base virtual address.
- * @offset - register offset.
- * @mask - register bitmask specifying what should be updated
- * @val - value to write.
+ * @phy_dwc3: QCOM DWC3 phy context
+ * @offset: register offset.
+ * @mask: register bitmask specifying what should be updated
+ * @val: value to write.
  */
 static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3,
                                          u32 offset,
@@ -171,11 +172,11 @@ static int wait_for_latch(void __iomem *addr)
 }
 
 /**
- * Write SSPHY register
+ * usb_ss_write_phycreg() - Write SSPHY register
  *
- * @base - QCOM DWC3 PHY base virtual address.
- * @addr - SSPHY address to write.
- * @val - value to write.
+ * @phy_dwc3: QCOM DWC3 phy context
+ * @addr: SSPHY address to write.
+ * @val: value to write.
  */
 static int usb_ss_write_phycreg(struct usb_phy *phy_dwc3,
                                u32 addr, u32 val)
@@ -209,10 +210,11 @@ err_wait:
 }
 
 /**
- * Read SSPHY register.
+ * usb_ss_read_phycreg() - Read SSPHY register.
  *
- * @base - QCOM DWC3 PHY base virtual address.
- * @addr - SSPHY address to read.
+ * @phy_dwc3: QCOM DWC3 phy context
+ * @addr: SSPHY address to read.
+ * @val: pointer in which read is store.
  */
 static int usb_ss_read_phycreg(struct usb_phy *phy_dwc3,
                               u32 addr, u32 *val)
index 456a59d..c96639d 100644 (file)
@@ -2973,6 +2973,9 @@ struct qmp_phy_combo_cfg {
  * @qmp: QMP phy to which this lane belongs
  * @lane_rst: lane's reset controller
  * @mode: current PHY mode
+ * @dp_aux_cfg: Display port aux config
+ * @dp_opts: Display port optional config
+ * @dp_clks: Display port clocks
  */
 struct qmp_phy {
        struct phy *phy;
index 04d18d5..716a777 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
  * Copyright (C) 2016 Linaro Ltd
  */
 #include <linux/module.h>
index 7df6a63..e4f4a9b 100644 (file)
@@ -478,7 +478,7 @@ static void stm32_usbphyc_phy_tuning(struct stm32_usbphyc *usbphyc,
        if (!of_property_read_bool(np, "st,no-lsfs-fb-cap"))
                usbphyc_phy->tune |= LFSCAPEN;
 
-       if (of_property_read_bool(np, "st,slow-hs-slew-rate"))
+       if (of_property_read_bool(np, "st,decrease-hs-slew-rate"))
                usbphyc_phy->tune |= HSDRVSLEW;
 
        ret = of_property_read_u32(np, "st,tune-hs-dc-level", &val);
index 2ff56ce..c1211c4 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/**
+/*
  * PCIe SERDES driver for AM654x SoC
  *
  * Copyright (C) 2018 - 2019 Texas Instruments Incorporated - http://www.ti.com/
index 126f5b8..b3384c3 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/**
+/*
  * Wrapper driver for SERDES used in J721E
  *
  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
index ebceb15..3a505fe 100644 (file)
@@ -89,9 +89,9 @@ static inline void omap_usb_writel(void __iomem *addr, unsigned int offset,
 }
 
 /**
- * omap_usb2_set_comparator - links the comparator present in the system with
- *     this phy
- * @comparator - the companion phy(comparator) for this phy
+ * omap_usb2_set_comparator() - links the comparator present in the system with this phy
+ *
+ * @comparator the companion phy(comparator) for this phy
  *
  * The phy companion driver should call this API passing the phy_companion
  * filled with set_vbus and start_srp to be used by usb phy.
index a63213f..15c1c79 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
  * tusb1210.c - TUSB1210 USB ULPI PHY driver
  *
  * Copyright (C) 2015 Intel Corporation
index b7e50ed..841c44c 100644 (file)
@@ -76,7 +76,7 @@
 #define AMD_CPU_ID_CZN                 AMD_CPU_ID_RN
 #define AMD_CPU_ID_YC                  0x14B5
 
-#define PMC_MSG_DELAY_MIN_US           100
+#define PMC_MSG_DELAY_MIN_US           50
 #define RESPONSE_REGISTER_LOOP_MAX     20000
 
 #define SOC_SUBSYSTEM_IP_MAX   12
index 0859894..13f8cf7 100644 (file)
@@ -99,6 +99,13 @@ static const struct dmi_system_id button_array_table[] = {
                        DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Tablet Gen 2"),
                },
        },
+       {
+               .ident = "Microsoft Surface Go 3",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
+               },
+       },
        { }
 };
 
index ae92930..a91847a 100644 (file)
@@ -657,6 +657,18 @@ static int acpi_add(struct acpi_device *device)
        if (product && strlen(product) > 4)
                switch (product[4]) {
                case '5':
+                       if (strlen(product) > 5)
+                               switch (product[5]) {
+                               case 'N':
+                                       year = 2021;
+                                       break;
+                               case '0':
+                                       year = 2016;
+                                       break;
+                               default:
+                                       year = 2022;
+                               }
+                       break;
                case '6':
                        year = 2016;
                        break;
index b3ac9c3..bb1abb9 100644 (file)
@@ -3015,6 +3015,8 @@ static struct attribute *hotkey_attributes[] = {
        &dev_attr_hotkey_all_mask.attr,
        &dev_attr_hotkey_adaptive_all_mask.attr,
        &dev_attr_hotkey_recommended_mask.attr,
+       &dev_attr_hotkey_tablet_mode.attr,
+       &dev_attr_hotkey_radio_sw.attr,
 #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
        &dev_attr_hotkey_source_mask.attr,
        &dev_attr_hotkey_poll_freq.attr,
@@ -5726,11 +5728,11 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
        "tpacpi::standby",
        "tpacpi::dock_status1",
        "tpacpi::dock_status2",
-       "tpacpi::unknown_led2",
+       "tpacpi::lid_logo_dot",
        "tpacpi::unknown_led3",
        "tpacpi::thinkvantage",
 };
-#define TPACPI_SAFE_LEDS       0x1081U
+#define TPACPI_SAFE_LEDS       0x1481U
 
 static inline bool tpacpi_is_led_restricted(const unsigned int led)
 {
index fa88120..17dd54d 100644 (file)
@@ -905,6 +905,16 @@ static const struct ts_dmi_data trekstor_primetab_t13b_data = {
        .properties = trekstor_primetab_t13b_props,
 };
 
+static const struct property_entry trekstor_surftab_duo_w1_props[] = {
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
+       { }
+};
+
+static const struct ts_dmi_data trekstor_surftab_duo_w1_data = {
+       .acpi_name      = "GDIX1001:00",
+       .properties     = trekstor_surftab_duo_w1_props,
+};
+
 static const struct property_entry trekstor_surftab_twin_10_1_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-min-x", 20),
        PROPERTY_ENTRY_U32("touchscreen-min-y", 0),
@@ -1503,6 +1513,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                },
        },
        {
+               /* TrekStor SurfTab duo W1 10.1 ST10432-10b */
+               .driver_data = (void *)&trekstor_surftab_duo_w1_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab duo W1 10.1 (VT4)"),
+               },
+       },
+       {
                /* TrekStor SurfTab twin 10.1 ST10432-8 */
                .driver_data = (void *)&trekstor_surftab_twin_10_1_data,
                .matches = {
index 4c5bba5..24d3395 100644 (file)
@@ -20,7 +20,6 @@ static int tegra_bpmp_reset_common(struct reset_controller_dev *rstc,
        struct tegra_bpmp *bpmp = to_tegra_bpmp(rstc);
        struct mrq_reset_request request;
        struct tegra_bpmp_message msg;
-       int err;
 
        memset(&request, 0, sizeof(request));
        request.cmd = command;
@@ -31,13 +30,7 @@ static int tegra_bpmp_reset_common(struct reset_controller_dev *rstc,
        msg.tx.data = &request;
        msg.tx.size = sizeof(request);
 
-       err = tegra_bpmp_transfer(bpmp, &msg);
-       if (err)
-               return err;
-       if (msg.rx.ret)
-               return -EINVAL;
-
-       return 0;
+       return tegra_bpmp_transfer(bpmp, &msg);
 }
 
 static int tegra_bpmp_reset_module(struct reset_controller_dev *rstc,
index bed8cc1..fbfeb0b 100644 (file)
@@ -282,12 +282,12 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
        if (rc) {
                pm8001_dbg(pm8001_ha, FAIL,
                           "pm8001_setup_irq failed [ret: %d]\n", rc);
-               goto err_out_shost;
+               goto err_out;
        }
        /* Request Interrupt */
        rc = pm8001_request_irq(pm8001_ha);
        if (rc)
-               goto err_out_shost;
+               goto err_out;
 
        count = pm8001_ha->max_q_num;
        /* Queues are chosen based on the number of cores/msix availability */
@@ -423,8 +423,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,
        pm8001_tag_init(pm8001_ha);
        return 0;
 
-err_out_shost:
-       scsi_remove_host(pm8001_ha->shost);
 err_out_nodev:
        for (i = 0; i < pm8001_ha->max_memcnt; i++) {
                if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) {
index b9f6d83..2101fc5 100644 (file)
@@ -3053,7 +3053,6 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
        struct smp_completion_resp *psmpPayload;
        struct task_status_struct *ts;
        struct pm8001_device *pm8001_dev;
-       char *pdma_respaddr = NULL;
 
        psmpPayload = (struct smp_completion_resp *)(piomb + 4);
        status = le32_to_cpu(psmpPayload->status);
@@ -3080,19 +3079,23 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                if (pm8001_dev)
                        atomic_dec(&pm8001_dev->running_req);
                if (pm8001_ha->smp_exp_mode == SMP_DIRECT) {
+                       struct scatterlist *sg_resp = &t->smp_task.smp_resp;
+                       u8 *payload;
+                       void *to;
+
                        pm8001_dbg(pm8001_ha, IO,
                                   "DIRECT RESPONSE Length:%d\n",
                                   param);
-                       pdma_respaddr = (char *)(phys_to_virt(cpu_to_le64
-                                               ((u64)sg_dma_address
-                                               (&t->smp_task.smp_resp))));
+                       to = kmap_atomic(sg_page(sg_resp));
+                       payload = to + sg_resp->offset;
                        for (i = 0; i < param; i++) {
-                               *(pdma_respaddr+i) = psmpPayload->_r_a[i];
+                               *(payload + i) = psmpPayload->_r_a[i];
                                pm8001_dbg(pm8001_ha, IO,
                                           "SMP Byte%d DMA data 0x%x psmp 0x%x\n",
-                                          i, *(pdma_respaddr + i),
+                                          i, *(payload + i),
                                           psmpPayload->_r_a[i]);
                        }
+                       kunmap_atomic(to);
                }
                break;
        case IO_ABORTED:
@@ -4236,14 +4239,14 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
        struct sas_task *task = ccb->task;
        struct domain_device *dev = task->dev;
        struct pm8001_device *pm8001_dev = dev->lldd_dev;
-       struct scatterlist *sg_req, *sg_resp;
+       struct scatterlist *sg_req, *sg_resp, *smp_req;
        u32 req_len, resp_len;
        struct smp_req smp_cmd;
        u32 opc;
        struct inbound_queue_table *circularQ;
-       char *preq_dma_addr = NULL;
-       __le64 tmp_addr;
        u32 i, length;
+       u8 *payload;
+       u8 *to;
 
        memset(&smp_cmd, 0, sizeof(smp_cmd));
        /*
@@ -4280,8 +4283,9 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
                pm8001_ha->smp_exp_mode = SMP_INDIRECT;
 
 
-       tmp_addr = cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
-       preq_dma_addr = (char *)phys_to_virt(tmp_addr);
+       smp_req = &task->smp_task.smp_req;
+       to = kmap_atomic(sg_page(smp_req));
+       payload = to + smp_req->offset;
 
        /* INDIRECT MODE command settings. Use DMA */
        if (pm8001_ha->smp_exp_mode == SMP_INDIRECT) {
@@ -4289,7 +4293,7 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
                /* for SPCv indirect mode. Place the top 4 bytes of
                 * SMP Request header here. */
                for (i = 0; i < 4; i++)
-                       smp_cmd.smp_req16[i] = *(preq_dma_addr + i);
+                       smp_cmd.smp_req16[i] = *(payload + i);
                /* exclude top 4 bytes for SMP req header */
                smp_cmd.long_smp_req.long_req_addr =
                        cpu_to_le64((u64)sg_dma_address
@@ -4320,20 +4324,20 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
                pm8001_dbg(pm8001_ha, IO, "SMP REQUEST DIRECT MODE\n");
                for (i = 0; i < length; i++)
                        if (i < 16) {
-                               smp_cmd.smp_req16[i] = *(preq_dma_addr+i);
+                               smp_cmd.smp_req16[i] = *(payload + i);
                                pm8001_dbg(pm8001_ha, IO,
                                           "Byte[%d]:%x (DMA data:%x)\n",
                                           i, smp_cmd.smp_req16[i],
-                                          *(preq_dma_addr));
+                                          *(payload));
                        } else {
-                               smp_cmd.smp_req[i] = *(preq_dma_addr+i);
+                               smp_cmd.smp_req[i] = *(payload + i);
                                pm8001_dbg(pm8001_ha, IO,
                                           "Byte[%d]:%x (DMA data:%x)\n",
                                           i, smp_cmd.smp_req[i],
-                                          *(preq_dma_addr));
+                                          *(payload));
                        }
        }
-
+       kunmap_atomic(to);
        build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag,
                                &smp_cmd, pm8001_ha->smp_exp_mode, length);
        rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &smp_cmd,
index 84a4204..5916ed7 100644 (file)
@@ -732,7 +732,6 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 {
        struct qedi_work_map *work, *work_tmp;
        u32 proto_itt = cqe->itid;
-       itt_t protoitt = 0;
        int found = 0;
        struct qedi_cmd *qedi_cmd = NULL;
        u32 iscsi_cid;
@@ -812,16 +811,12 @@ unlock:
        return;
 
 check_cleanup_reqs:
-       if (qedi_conn->cmd_cleanup_req > 0) {
-               QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
+       if (atomic_inc_return(&qedi_conn->cmd_cleanup_cmpl) ==
+           qedi_conn->cmd_cleanup_req) {
+               QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
                          "Freeing tid=0x%x for cid=0x%x\n",
                          cqe->itid, qedi_conn->iscsi_conn_id);
-               qedi_conn->cmd_cleanup_cmpl++;
                wake_up(&qedi_conn->wait_queue);
-       } else {
-               QEDI_ERR(&qedi->dbg_ctx,
-                        "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x\n",
-                        protoitt, cqe->itid, qedi_conn->iscsi_conn_id);
        }
 }
 
@@ -1163,7 +1158,7 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
        }
 
        qedi_conn->cmd_cleanup_req = 0;
-       qedi_conn->cmd_cleanup_cmpl = 0;
+       atomic_set(&qedi_conn->cmd_cleanup_cmpl, 0);
 
        QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
                  "active_cmd_count=%d, cid=0x%x, in_recovery=%d, lun_reset=%d\n",
@@ -1215,16 +1210,15 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
                  qedi_conn->iscsi_conn_id);
 
        rval  = wait_event_interruptible_timeout(qedi_conn->wait_queue,
-                                                ((qedi_conn->cmd_cleanup_req ==
-                                                qedi_conn->cmd_cleanup_cmpl) ||
-                                                test_bit(QEDI_IN_RECOVERY,
-                                                         &qedi->flags)),
-                                                5 * HZ);
+                               (qedi_conn->cmd_cleanup_req ==
+                                atomic_read(&qedi_conn->cmd_cleanup_cmpl)) ||
+                               test_bit(QEDI_IN_RECOVERY, &qedi->flags),
+                               5 * HZ);
        if (rval) {
                QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
                          "i/o cmd_cleanup_req=%d, equal to cmd_cleanup_cmpl=%d, cid=0x%x\n",
                          qedi_conn->cmd_cleanup_req,
-                         qedi_conn->cmd_cleanup_cmpl,
+                         atomic_read(&qedi_conn->cmd_cleanup_cmpl),
                          qedi_conn->iscsi_conn_id);
 
                return 0;
@@ -1233,7 +1227,7 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
        QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
                  "i/o cmd_cleanup_req=%d, not equal to cmd_cleanup_cmpl=%d, cid=0x%x\n",
                  qedi_conn->cmd_cleanup_req,
-                 qedi_conn->cmd_cleanup_cmpl,
+                 atomic_read(&qedi_conn->cmd_cleanup_cmpl),
                  qedi_conn->iscsi_conn_id);
 
        iscsi_host_for_each_session(qedi->shost,
@@ -1242,11 +1236,10 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
 
        /* Enable IOs for all other sessions except current.*/
        if (!wait_event_interruptible_timeout(qedi_conn->wait_queue,
-                                             (qedi_conn->cmd_cleanup_req ==
-                                              qedi_conn->cmd_cleanup_cmpl) ||
-                                              test_bit(QEDI_IN_RECOVERY,
-                                                       &qedi->flags),
-                                             5 * HZ)) {
+                               (qedi_conn->cmd_cleanup_req ==
+                                atomic_read(&qedi_conn->cmd_cleanup_cmpl)) ||
+                               test_bit(QEDI_IN_RECOVERY, &qedi->flags),
+                               5 * HZ)) {
                iscsi_host_for_each_session(qedi->shost,
                                            qedi_mark_device_available);
                return -1;
@@ -1266,7 +1259,7 @@ void qedi_clearsq(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
 
        qedi_ep = qedi_conn->ep;
        qedi_conn->cmd_cleanup_req = 0;
-       qedi_conn->cmd_cleanup_cmpl = 0;
+       atomic_set(&qedi_conn->cmd_cleanup_cmpl, 0);
 
        if (!qedi_ep) {
                QEDI_WARN(&qedi->dbg_ctx,
index 88aa7d8..282ecb4 100644 (file)
@@ -412,7 +412,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
        qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid;
        qedi_conn->fw_cid = qedi_ep->fw_cid;
        qedi_conn->cmd_cleanup_req = 0;
-       qedi_conn->cmd_cleanup_cmpl = 0;
+       atomic_set(&qedi_conn->cmd_cleanup_cmpl, 0);
 
        if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) {
                rc = -EINVAL;
index a282860..9b9f2e4 100644 (file)
@@ -155,7 +155,7 @@ struct qedi_conn {
        spinlock_t list_lock;           /* internal conn lock */
        u32 active_cmd_count;
        u32 cmd_cleanup_req;
-       u32 cmd_cleanup_cmpl;
+       atomic_t cmd_cleanup_cmpl;
 
        u32 iscsi_conn_id;
        int itt;
index 25549a8..7cf1f78 100644 (file)
@@ -2491,6 +2491,9 @@ ql_dbg(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...)
        struct va_format vaf;
        char pbuf[64];
 
+       if (!ql_mask_match(level) && !trace_ql_dbg_log_enabled())
+               return;
+
        va_start(va, fmt);
 
        vaf.fmt = fmt;
index 3c0da37..2104973 100644 (file)
@@ -4342,7 +4342,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
        rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
                            max_zones);
 
-       arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
+       arr = kzalloc(alloc_len, GFP_ATOMIC);
        if (!arr) {
                mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
                                INSUFF_RES_ASCQ);
index 519b365..c2f076b 100644 (file)
@@ -17,6 +17,7 @@
 
 #define BLK_SFT_RSTN   0x0
 #define BLK_CLK_EN     0x4
+#define BLK_MIPI_RESET_DIV     0x8 /* Mini/Nano DISPLAY_BLK_CTRL only */
 
 struct imx8m_blk_ctrl_domain;
 
@@ -36,6 +37,15 @@ struct imx8m_blk_ctrl_domain_data {
        const char *gpc_name;
        u32 rst_mask;
        u32 clk_mask;
+
+       /*
+        * i.MX8M Mini and Nano have a third DISPLAY_BLK_CTRL register
+        * which is used to control the reset for the MIPI Phy.
+        * Since it's only present in certain circumstances,
+        * an if-statement should be used before setting and clearing this
+        * register.
+        */
+       u32 mipi_phy_rst_mask;
 };
 
 #define DOMAIN_MAX_CLKS 3
@@ -78,6 +88,8 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
 
        /* put devices into reset */
        regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
+       if (data->mipi_phy_rst_mask)
+               regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
 
        /* enable upstream and blk-ctrl clocks to allow reset to propagate */
        ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
@@ -99,6 +111,8 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
 
        /* release reset */
        regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
+       if (data->mipi_phy_rst_mask)
+               regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
 
        /* disable upstream clocks */
        clk_bulk_disable_unprepare(data->num_clks, domain->clks);
@@ -120,6 +134,9 @@ static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
        struct imx8m_blk_ctrl *bc = domain->bc;
 
        /* put devices into reset and disable clocks */
+       if (data->mipi_phy_rst_mask)
+               regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
+
        regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
        regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
 
@@ -480,6 +497,7 @@ static const struct imx8m_blk_ctrl_domain_data imx8mm_disp_blk_ctl_domain_data[]
                .gpc_name = "mipi-dsi",
                .rst_mask = BIT(5),
                .clk_mask = BIT(8) | BIT(9),
+               .mipi_phy_rst_mask = BIT(17),
        },
        [IMX8MM_DISPBLK_PD_MIPI_CSI] = {
                .name = "dispblk-mipi-csi",
@@ -488,6 +506,7 @@ static const struct imx8m_blk_ctrl_domain_data imx8mm_disp_blk_ctl_domain_data[]
                .gpc_name = "mipi-csi",
                .rst_mask = BIT(3) | BIT(4),
                .clk_mask = BIT(10) | BIT(11),
+               .mipi_phy_rst_mask = BIT(16),
        },
 };
 
index ac6d856..77bc120 100644 (file)
@@ -36,6 +36,10 @@ static int __init imx_soc_device_init(void)
        int ret;
        int i;
 
+       /* Return early if this is running on devices with different SoCs */
+       if (!__mxc_cpu_type)
+               return 0;
+
        if (of_machine_is_compatible("fsl,ls1021a"))
                return 0;
 
index f215181..e714ed3 100644 (file)
@@ -320,7 +320,7 @@ static struct platform_driver tegra_fuse_driver = {
 };
 builtin_platform_driver(tegra_fuse_driver);
 
-bool __init tegra_fuse_read_spare(unsigned int spare)
+u32 __init tegra_fuse_read_spare(unsigned int spare)
 {
        unsigned int offset = fuse->soc->info->spare + spare * 4;
 
index de58feb..ecff0c0 100644 (file)
@@ -65,7 +65,7 @@ struct tegra_fuse {
 void tegra_init_revision(void);
 void tegra_init_apbmisc(void);
 
-bool __init tegra_fuse_read_spare(unsigned int spare);
+u32 __init tegra_fuse_read_spare(unsigned int spare);
 u32 __init tegra_fuse_read_early(unsigned int offset);
 
 u8 tegra_get_major_rev(void);
index da6b88e..297dc62 100644 (file)
@@ -203,9 +203,8 @@ static int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta,
 
        *ta_size = roundup(fw->size, PAGE_SIZE);
        *ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size));
-       if (IS_ERR(*ta)) {
-               pr_err("%s: get_free_pages failed 0x%llx\n", __func__,
-                      (u64)*ta);
+       if (!*ta) {
+               pr_err("%s: get_free_pages failed\n", __func__);
                rc = -ENOMEM;
                goto rel_fw;
        }
index b25b54d..e693ec8 100644 (file)
@@ -29,7 +29,7 @@ static const char * const fivr_strings[] = {
 };
 
 static const struct mmio_reg tgl_fivr_mmio_regs[] = {
-       { 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
+       { 0, 0x5A18, 3, 0x7, 11}, /* vco_ref_code_lo */
        { 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
        { 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
        { 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
index 7e0884e..23ba1fc 100644 (file)
@@ -140,6 +140,8 @@ struct n_hdlc {
        struct n_hdlc_buf_list  rx_buf_list;
        struct n_hdlc_buf_list  tx_free_buf_list;
        struct n_hdlc_buf_list  rx_free_buf_list;
+       struct work_struct      write_work;
+       struct tty_struct       *tty_for_write_work;
 };
 
 /*
@@ -154,6 +156,7 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
 /* Local functions */
 
 static struct n_hdlc *n_hdlc_alloc(void);
+static void n_hdlc_tty_write_work(struct work_struct *work);
 
 /* max frame size for memory allocations */
 static int maxframe = 4096;
@@ -210,6 +213,8 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
        wake_up_interruptible(&tty->read_wait);
        wake_up_interruptible(&tty->write_wait);
 
+       cancel_work_sync(&n_hdlc->write_work);
+
        n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
        n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
        n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
@@ -241,6 +246,8 @@ static int n_hdlc_tty_open(struct tty_struct *tty)
                return -ENFILE;
        }
 
+       INIT_WORK(&n_hdlc->write_work, n_hdlc_tty_write_work);
+       n_hdlc->tty_for_write_work = tty;
        tty->disc_data = n_hdlc;
        tty->receive_room = 65536;
 
@@ -335,6 +342,20 @@ check_again:
 }      /* end of n_hdlc_send_frames() */
 
 /**
+ * n_hdlc_tty_write_work - Asynchronous callback for transmit wakeup
+ * @work: pointer to work_struct
+ *
+ * Called when low level device driver can accept more send data.
+ */
+static void n_hdlc_tty_write_work(struct work_struct *work)
+{
+       struct n_hdlc *n_hdlc = container_of(work, struct n_hdlc, write_work);
+       struct tty_struct *tty = n_hdlc->tty_for_write_work;
+
+       n_hdlc_send_frames(n_hdlc, tty);
+}      /* end of n_hdlc_tty_write_work() */
+
+/**
  * n_hdlc_tty_wakeup - Callback for transmit wakeup
  * @tty: pointer to associated tty instance data
  *
@@ -344,7 +365,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
 {
        struct n_hdlc *n_hdlc = tty->disc_data;
 
-       n_hdlc_send_frames(n_hdlc, tty);
+       schedule_work(&n_hdlc->write_work);
 }      /* end of n_hdlc_tty_wakeup() */
 
 /**
index 31c9e83..251f001 100644 (file)
@@ -290,25 +290,6 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
        }
 }
 
-static void fintek_8250_goto_highspeed(struct uart_8250_port *uart,
-                             struct fintek_8250 *pdata)
-{
-       sio_write_reg(pdata, LDN, pdata->index);
-
-       switch (pdata->pid) {
-       case CHIP_ID_F81966:
-       case CHIP_ID_F81866: /* set uart clock for high speed serial mode */
-               sio_write_mask_reg(pdata, F81866_UART_CLK,
-                       F81866_UART_CLK_MASK,
-                       F81866_UART_CLK_14_769MHZ);
-
-               uart->port.uartclk = 921600 * 16;
-               break;
-       default: /* leave clock speed untouched */
-               break;
-       }
-}
-
 static void fintek_8250_set_termios(struct uart_port *port,
                                    struct ktermios *termios,
                                    struct ktermios *old)
@@ -430,7 +411,6 @@ static int probe_setup_port(struct fintek_8250 *pdata,
 
                                fintek_8250_set_irq_mode(pdata, level_mode);
                                fintek_8250_set_max_fifo(pdata);
-                               fintek_8250_goto_highspeed(uart, pdata);
 
                                fintek_8250_exit_key(addr[i]);
 
index 27df0c6..e85bf76 100644 (file)
@@ -1541,15 +1541,27 @@ static int cdnsp_gadget_pullup(struct usb_gadget *gadget, int is_on)
 {
        struct cdnsp_device *pdev = gadget_to_cdnsp(gadget);
        struct cdns *cdns = dev_get_drvdata(pdev->dev);
+       unsigned long flags;
 
        trace_cdnsp_pullup(is_on);
 
+       /*
+        * Disable events handling while controller is being
+        * enabled/disabled.
+        */
+       disable_irq(cdns->dev_irq);
+       spin_lock_irqsave(&pdev->lock, flags);
+
        if (!is_on) {
                cdnsp_reset_device(pdev);
                cdns_clear_vbus(cdns);
        } else {
                cdns_set_vbus(cdns);
        }
+
+       spin_unlock_irqrestore(&pdev->lock, flags);
+       enable_irq(cdns->dev_irq);
+
        return 0;
 }
 
index 1b14384..e45c3d6 100644 (file)
@@ -1029,6 +1029,8 @@ static void cdnsp_process_ctrl_td(struct cdnsp_device *pdev,
                return;
        }
 
+       *status = 0;
+
        cdnsp_finish_td(pdev, td, event, pep, status);
 }
 
@@ -1523,7 +1525,14 @@ irqreturn_t cdnsp_thread_irq_handler(int irq, void *data)
        spin_lock_irqsave(&pdev->lock, flags);
 
        if (pdev->cdnsp_state & (CDNSP_STATE_HALTED | CDNSP_STATE_DYING)) {
-               cdnsp_died(pdev);
+               /*
+                * While removing or stopping driver there may still be deferred
+                * not handled interrupt which should not be treated as error.
+                * Driver should simply ignore it.
+                */
+               if (pdev->gadget_driver)
+                       cdnsp_died(pdev);
+
                spin_unlock_irqrestore(&pdev->lock, flags);
                return IRQ_HANDLED;
        }
index 6a2571c..5983dfb 100644 (file)
@@ -57,9 +57,9 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep,
                __entry->first_prime_det = pep->stream_info.first_prime_det;
                __entry->drbls_count = pep->stream_info.drbls_count;
        ),
-       TP_printk("%s: SID: %08x ep state: %x stream: enabled: %d num  %d "
+       TP_printk("%s: SID: %08x, ep state: %x, stream: enabled: %d num %d "
                  "tds %d, first prime: %d drbls %d",
-                 __get_str(name), __entry->state, __entry->stream_id,
+                 __get_str(name), __entry->stream_id, __entry->state,
                  __entry->enabled, __entry->num_streams, __entry->td_count,
                  __entry->first_prime_det, __entry->drbls_count)
 );
index 84dadfa..9643b90 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include "core.h"
 #include "drd.h"
 #include "host-export.h"
index 16b1fd9..48bc8a4 100644 (file)
@@ -406,7 +406,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
         * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0
         * (see the end of section 5.6.3), so don't warn about them.
         */
-       maxp = usb_endpoint_maxp(&endpoint->desc);
+       maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize);
        if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
                dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
                    cfgno, inum, asnum, d->bEndpointAddress);
@@ -422,9 +422,9 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
                maxpacket_maxes = full_speed_maxpacket_maxes;
                break;
        case USB_SPEED_HIGH:
-               /* Bits 12..11 are allowed only for HS periodic endpoints */
+               /* Multiple-transactions bits are allowed only for HS periodic endpoints */
                if (usb_endpoint_xfer_int(d) || usb_endpoint_xfer_isoc(d)) {
-                       i = maxp & (BIT(12) | BIT(11));
+                       i = maxp & USB_EP_MAXP_MULT_MASK;
                        maxp &= ~i;
                }
                fallthrough;
index 019351c..d3c14b5 100644 (file)
@@ -434,6 +434,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x1532, 0x0116), .driver_info =
                        USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+       /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */
+       { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM },
+
        /* Lenovo Powered USB-C Travel Hub (4X90S92381, RTL8153 GigE) */
        { USB_DEVICE(0x17ef, 0x721e), .driver_info = USB_QUIRK_NO_LPM },
 
index c8f18f3..c331a51 100644 (file)
@@ -575,6 +575,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
                ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
                ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
                dwc2_writel(hsotg, ggpio, GGPIO);
+
+               /* ID/VBUS detection startup time */
+               usleep_range(5000, 7000);
        }
 
        retval = dwc2_drd_init(hsotg);
index 9abbd01..3cb01cd 100644 (file)
@@ -649,7 +649,6 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
        struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
        struct device_node      *np = pdev->dev.of_node, *dwc3_np;
        struct device           *dev = &pdev->dev;
-       struct property         *prop;
        int                     ret;
 
        dwc3_np = of_get_compatible_child(np, "snps,dwc3");
@@ -658,20 +657,6 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
-       if (!prop) {
-               ret = -ENOMEM;
-               dev_err(dev, "unable to allocate memory for property\n");
-               goto node_put;
-       }
-
-       prop->name = "tx-fifo-resize";
-       ret = of_add_property(dwc3_np, prop);
-       if (ret) {
-               dev_err(dev, "unable to add property\n");
-               goto node_put;
-       }
-
        ret = of_platform_populate(np, NULL, NULL, dev);
        if (ret) {
                dev_err(dev, "failed to register dwc3 core - %d\n", ret);
index 933d77a..4502108 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/pci_ids.h>
 #include <linux/memblock.h>
 #include <linux/io.h>
-#include <linux/iopoll.h>
 #include <asm/pci-direct.h>
 #include <asm/fixmap.h>
 #include <linux/bcd.h>
@@ -136,9 +135,17 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, int wait, int delay)
 {
        u32 result;
 
-       return readl_poll_timeout_atomic(ptr, result,
-                                        ((result & mask) == done),
-                                        delay, wait);
+       /* Can not use readl_poll_timeout_atomic() for early boot things */
+       do {
+               result = readl(ptr);
+               result &= mask;
+               if (result == done)
+                       return 0;
+               udelay(delay);
+               wait -= delay;
+       } while (wait > 0);
+
+       return -ETIMEDOUT;
 }
 
 static void __init xdbc_bios_handoff(void)
index 504c1cb..3789c32 100644 (file)
@@ -1679,6 +1679,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct usb_function             *f = NULL;
        u8                              endp;
 
+       if (w_length > USB_COMP_EP0_BUFSIZ) {
+               if (ctrl->bRequestType & USB_DIR_IN) {
+                       /* Cast away the const, we are going to overwrite on purpose. */
+                       __le16 *temp = (__le16 *)&ctrl->wLength;
+
+                       *temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ);
+                       w_length = USB_COMP_EP0_BUFSIZ;
+               } else {
+                       goto done;
+               }
+       }
+
        /* partial re-init of the response message; the function or the
         * gadget might need to intercept e.g. a control-OUT completion
         * when we delegate to it.
@@ -2209,7 +2221,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite,
        if (!cdev->req)
                return -ENOMEM;
 
-       cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
+       cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
        if (!cdev->req->buf)
                goto fail;
 
index e0ad5ae..6f5d45e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/etherdevice.h>
 
 #include "u_ether.h"
 
@@ -863,19 +864,23 @@ int gether_register_netdev(struct net_device *net)
 {
        struct eth_dev *dev;
        struct usb_gadget *g;
-       struct sockaddr sa;
        int status;
 
        if (!net->dev.parent)
                return -EINVAL;
        dev = netdev_priv(net);
        g = dev->gadget;
+
+       net->addr_assign_type = NET_ADDR_RANDOM;
+       eth_hw_addr_set(net, dev->dev_mac);
+
        status = register_netdev(net);
        if (status < 0) {
                dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
                return status;
        } else {
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
+               INFO(dev, "MAC %pM\n", dev->dev_mac);
 
                /* two kinds of host-initiated state changes:
                 *  - iff DATA transfer is active, carrier is "on"
@@ -883,15 +888,6 @@ int gether_register_netdev(struct net_device *net)
                 */
                netif_carrier_off(net);
        }
-       sa.sa_family = net->type;
-       memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN);
-       rtnl_lock();
-       status = dev_set_mac_address(net, &sa, NULL);
-       rtnl_unlock();
-       if (status)
-               pr_warn("cannot set self ethernet address: %d\n", status);
-       else
-               INFO(dev, "MAC %pM\n", dev->dev_mac);
 
        return status;
 }
index e1d566c..6bcbad3 100644 (file)
@@ -137,7 +137,7 @@ static int dbgp_enable_ep_req(struct usb_ep *ep)
                goto fail_1;
        }
 
-       req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
+       req->buf = kzalloc(DBGP_REQ_LEN, GFP_KERNEL);
        if (!req->buf) {
                err = -ENOMEM;
                stp = 2;
@@ -345,6 +345,19 @@ static int dbgp_setup(struct usb_gadget *gadget,
        void *data = NULL;
        u16 len = 0;
 
+       if (length > DBGP_REQ_LEN) {
+               if (ctrl->bRequestType & USB_DIR_IN) {
+                       /* Cast away the const, we are going to overwrite on purpose. */
+                       __le16 *temp = (__le16 *)&ctrl->wLength;
+
+                       *temp = cpu_to_le16(DBGP_REQ_LEN);
+                       length = DBGP_REQ_LEN;
+               } else {
+                       return err;
+               }
+       }
+
+
        if (request == USB_REQ_GET_DESCRIPTOR) {
                switch (value>>8) {
                case USB_DT_DEVICE:
index 78be947..3b58f4f 100644 (file)
@@ -110,6 +110,8 @@ enum ep0_state {
 /* enough for the whole queue: most events invalidate others */
 #define        N_EVENT                 5
 
+#define RBUF_SIZE              256
+
 struct dev_data {
        spinlock_t                      lock;
        refcount_t                      count;
@@ -144,7 +146,7 @@ struct dev_data {
        struct dentry                   *dentry;
 
        /* except this scratch i/o buffer for ep0 */
-       u8                              rbuf [256];
+       u8                              rbuf[RBUF_SIZE];
 };
 
 static inline void get_dev (struct dev_data *data)
@@ -1331,6 +1333,18 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        u16                             w_value = le16_to_cpu(ctrl->wValue);
        u16                             w_length = le16_to_cpu(ctrl->wLength);
 
+       if (w_length > RBUF_SIZE) {
+               if (ctrl->bRequestType & USB_DIR_IN) {
+                       /* Cast away the const, we are going to overwrite on purpose. */
+                       __le16 *temp = (__le16 *)&ctrl->wLength;
+
+                       *temp = cpu_to_le16(RBUF_SIZE);
+                       w_length = RBUF_SIZE;
+               } else {
+                       return value;
+               }
+       }
+
        spin_lock (&dev->lock);
        dev->setup_abort = 0;
        if (dev->state == STATE_DEV_UNCONNECTED) {
index af946c4..df3522d 100644 (file)
@@ -717,6 +717,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
                        continue;
 
                retval = xhci_disable_slot(xhci, i);
+               xhci_free_virt_device(xhci, i);
                if (retval)
                        xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
                                 i, retval);
index 1edef75..edbfa82 100644 (file)
@@ -781,7 +781,7 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 
        ret = xhci_check_bandwidth(hcd, udev);
        if (!ret)
-               INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
+               list_del_init(&mtk->bw_ep_chk_list);
 
        return ret;
 }
index 92adf61..3af0178 100644 (file)
@@ -71,6 +71,8 @@
 #define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_4           0x161e
 #define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_5           0x15d6
 #define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_6           0x15d7
+#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_7           0x161c
+#define PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_8           0x161f
 
 #define PCI_DEVICE_ID_ASMEDIA_1042_XHCI                        0x1042
 #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI               0x1142
@@ -330,7 +332,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
            pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_3 ||
            pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_4 ||
            pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_5 ||
-           pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_6))
+           pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_6 ||
+           pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_7 ||
+           pdev->device == PCI_DEVICE_ID_AMD_YELLOW_CARP_XHCI_8))
                xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
 
        if (xhci->quirks & XHCI_RESET_ON_RESUME)
index eaa49ae..d0b6806 100644 (file)
@@ -1525,7 +1525,6 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
        if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)
                /* Delete default control endpoint resources */
                xhci_free_device_endpoint_resources(xhci, virt_dev, true);
-       xhci_free_virt_device(xhci, slot_id);
 }
 
 static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
index 902f410..f5b1bcc 100644 (file)
@@ -3934,7 +3934,6 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        struct xhci_slot_ctx *slot_ctx;
        int i, ret;
 
-#ifndef CONFIG_USB_DEFAULT_PERSIST
        /*
         * We called pm_runtime_get_noresume when the device was attached.
         * Decrement the counter here to allow controller to runtime suspend
@@ -3942,7 +3941,6 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
         */
        if (xhci->quirks & XHCI_RESET_ON_RESUME)
                pm_runtime_put_noidle(hcd->self.controller);
-#endif
 
        ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
        /* If the host is halted due to driver unload, we still need to free the
@@ -3961,9 +3959,8 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
                del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
        }
        virt_dev->udev = NULL;
-       ret = xhci_disable_slot(xhci, udev->slot_id);
-       if (ret)
-               xhci_free_virt_device(xhci, udev->slot_id);
+       xhci_disable_slot(xhci, udev->slot_id);
+       xhci_free_virt_device(xhci, udev->slot_id);
 }
 
 int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
@@ -3973,7 +3970,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
        u32 state;
        int ret = 0;
 
-       command = xhci_alloc_command(xhci, false, GFP_KERNEL);
+       command = xhci_alloc_command(xhci, true, GFP_KERNEL);
        if (!command)
                return -ENOMEM;
 
@@ -3998,6 +3995,15 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
        }
        xhci_ring_cmd_db(xhci);
        spin_unlock_irqrestore(&xhci->lock, flags);
+
+       wait_for_completion(command->completion);
+
+       if (command->status != COMP_SUCCESS)
+               xhci_warn(xhci, "Unsuccessful disable slot %u command, status %d\n",
+                         slot_id, command->status);
+
+       xhci_free_command(xhci, command);
+
        return ret;
 }
 
@@ -4094,23 +4100,20 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
 
        xhci_debugfs_create_slot(xhci, slot_id);
 
-#ifndef CONFIG_USB_DEFAULT_PERSIST
        /*
         * If resetting upon resume, we can't put the controller into runtime
         * suspend if there is a device attached.
         */
        if (xhci->quirks & XHCI_RESET_ON_RESUME)
                pm_runtime_get_noresume(hcd->self.controller);
-#endif
 
        /* Is this a LS or FS device under a HS hub? */
        /* Hub or peripherial? */
        return 1;
 
 disable_slot:
-       ret = xhci_disable_slot(xhci, udev->slot_id);
-       if (ret)
-               xhci_free_virt_device(xhci, udev->slot_id);
+       xhci_disable_slot(xhci, udev->slot_id);
+       xhci_free_virt_device(xhci, udev->slot_id);
 
        return 0;
 }
@@ -4240,6 +4243,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
 
                mutex_unlock(&xhci->mutex);
                ret = xhci_disable_slot(xhci, udev->slot_id);
+               xhci_free_virt_device(xhci, udev->slot_id);
                if (!ret)
                        xhci_alloc_dev(hcd, udev);
                kfree(command->completion);
index 7705328..8a60c0d 100644 (file)
@@ -1635,6 +1635,8 @@ static int cp2105_gpioconf_init(struct usb_serial *serial)
 
        /*  2 banks of GPIO - One for the pins taken from each serial port */
        if (intf_num == 0) {
+               priv->gc.ngpio = 2;
+
                if (mode.eci == CP210X_PIN_MODE_MODEM) {
                        /* mark all GPIOs of this interface as reserved */
                        priv->gpio_altfunc = 0xff;
@@ -1645,8 +1647,9 @@ static int cp2105_gpioconf_init(struct usb_serial *serial)
                priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
                                                CP210X_ECI_GPIO_MODE_MASK) >>
                                                CP210X_ECI_GPIO_MODE_OFFSET);
-               priv->gc.ngpio = 2;
        } else if (intf_num == 1) {
+               priv->gc.ngpio = 3;
+
                if (mode.sci == CP210X_PIN_MODE_MODEM) {
                        /* mark all GPIOs of this interface as reserved */
                        priv->gpio_altfunc = 0xff;
@@ -1657,7 +1660,6 @@ static int cp2105_gpioconf_init(struct usb_serial *serial)
                priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
                                                CP210X_SCI_GPIO_MODE_MASK) >>
                                                CP210X_SCI_GPIO_MODE_OFFSET);
-               priv->gc.ngpio = 3;
        } else {
                return -ENODEV;
        }
index 546fce4..42420bf 100644 (file)
@@ -1219,6 +1219,14 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = NCTRL(2) | RSVD(3) },
        { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1063, 0xff),    /* Telit LN920 (ECM) */
          .driver_info = NCTRL(0) | RSVD(1) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1070, 0xff),    /* Telit FN990 (rmnet) */
+         .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1071, 0xff),    /* Telit FN990 (MBIM) */
+         .driver_info = NCTRL(0) | RSVD(1) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1072, 0xff),    /* Telit FN990 (RNDIS) */
+         .driver_info = NCTRL(2) | RSVD(3) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff),    /* Telit FN990 (ECM) */
+         .driver_info = NCTRL(0) | RSVD(1) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
          .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
index 6010b99..59d4fa2 100644 (file)
@@ -324,6 +324,7 @@ struct tcpm_port {
 
        bool attached;
        bool connected;
+       bool registered;
        bool pd_supported;
        enum typec_port_type port_type;
 
@@ -6291,7 +6292,8 @@ static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer)
 {
        struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer);
 
-       kthread_queue_work(port->wq, &port->state_machine);
+       if (port->registered)
+               kthread_queue_work(port->wq, &port->state_machine);
        return HRTIMER_NORESTART;
 }
 
@@ -6299,7 +6301,8 @@ static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *time
 {
        struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_state_machine_timer);
 
-       kthread_queue_work(port->wq, &port->vdm_state_machine);
+       if (port->registered)
+               kthread_queue_work(port->wq, &port->vdm_state_machine);
        return HRTIMER_NORESTART;
 }
 
@@ -6307,7 +6310,8 @@ static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer)
 {
        struct tcpm_port *port = container_of(timer, struct tcpm_port, enable_frs_timer);
 
-       kthread_queue_work(port->wq, &port->enable_frs);
+       if (port->registered)
+               kthread_queue_work(port->wq, &port->enable_frs);
        return HRTIMER_NORESTART;
 }
 
@@ -6315,7 +6319,8 @@ static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer)
 {
        struct tcpm_port *port = container_of(timer, struct tcpm_port, send_discover_timer);
 
-       kthread_queue_work(port->wq, &port->send_discover_work);
+       if (port->registered)
+               kthread_queue_work(port->wq, &port->send_discover_work);
        return HRTIMER_NORESTART;
 }
 
@@ -6403,6 +6408,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
        typec_port_register_altmodes(port->typec_port,
                                     &tcpm_altmode_ops, port,
                                     port->port_altmode, ALTMODE_DISCOVERY_MAX);
+       port->registered = true;
 
        mutex_lock(&port->lock);
        tcpm_init(port);
@@ -6424,6 +6430,9 @@ void tcpm_unregister_port(struct tcpm_port *port)
 {
        int i;
 
+       port->registered = false;
+       kthread_destroy_worker(port->wq);
+
        hrtimer_cancel(&port->send_discover_timer);
        hrtimer_cancel(&port->enable_frs_timer);
        hrtimer_cancel(&port->vdm_state_machine_timer);
@@ -6435,7 +6444,6 @@ void tcpm_unregister_port(struct tcpm_port *port)
        typec_unregister_port(port->typec_port);
        usb_role_switch_put(port->role_sw);
        tcpm_debugfs_exit(port);
-       kthread_destroy_worker(port->wq);
 }
 EXPORT_SYMBOL_GPL(tcpm_unregister_port);
 
index 7332a74..09bbe53 100644 (file)
@@ -404,7 +404,8 @@ static int vdpa_mgmtdev_fill(const struct vdpa_mgmt_dev *mdev, struct sk_buff *m
                goto msg_err;
 
        while (mdev->id_table[i].device) {
-               supported_classes |= BIT(mdev->id_table[i].device);
+               if (mdev->id_table[i].device <= 63)
+                       supported_classes |= BIT_ULL(mdev->id_table[i].device);
                i++;
        }
 
index c9204c6..eddcb64 100644 (file)
@@ -655,7 +655,8 @@ static void vduse_vdpa_get_config(struct vdpa_device *vdpa, unsigned int offset,
 {
        struct vduse_dev *dev = vdpa_to_vduse(vdpa);
 
-       if (len > dev->config_size - offset)
+       if (offset > dev->config_size ||
+           len > dev->config_size - offset)
                return;
 
        memcpy(buf, dev->config + offset, len);
@@ -975,7 +976,8 @@ static long vduse_dev_ioctl(struct file *file, unsigned int cmd,
                        break;
 
                ret = -EINVAL;
-               if (config.length == 0 ||
+               if (config.offset > dev->config_size ||
+                   config.length == 0 ||
                    config.length > dev->config_size - config.offset)
                        break;
 
index 29cced1..e3c4f05 100644 (file)
@@ -197,7 +197,7 @@ static int vhost_vdpa_config_validate(struct vhost_vdpa *v,
        struct vdpa_device *vdpa = v->vdpa;
        long size = vdpa->config->get_config_size(vdpa);
 
-       if (c->len == 0)
+       if (c->len == 0 || c->off > size)
                return -EINVAL;
 
        if (c->len > size - c->off)
index 6d2614e..028b05d 100644 (file)
@@ -268,7 +268,7 @@ size_t virtio_max_dma_size(struct virtio_device *vdev)
        size_t max_segment_size = SIZE_MAX;
 
        if (vring_use_dma_api(vdev))
-               max_segment_size = dma_max_mapping_size(&vdev->dev);
+               max_segment_size = dma_max_mapping_size(vdev->dev.parent);
 
        return max_segment_size;
 }
index cb6ad61..afe4b80 100644 (file)
@@ -514,8 +514,9 @@ static void afs_add_open_mmap(struct afs_vnode *vnode)
        if (atomic_inc_return(&vnode->cb_nr_mmap) == 1) {
                down_write(&vnode->volume->cell->fs_open_mmaps_lock);
 
-               list_add_tail(&vnode->cb_mmap_link,
-                             &vnode->volume->cell->fs_open_mmaps);
+               if (list_empty(&vnode->cb_mmap_link))
+                       list_add_tail(&vnode->cb_mmap_link,
+                                     &vnode->volume->cell->fs_open_mmaps);
 
                up_write(&vnode->volume->cell->fs_open_mmaps_lock);
        }
index d110def..34c6872 100644 (file)
@@ -667,6 +667,7 @@ static void afs_i_init_once(void *_vnode)
        INIT_LIST_HEAD(&vnode->pending_locks);
        INIT_LIST_HEAD(&vnode->granted_locks);
        INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
+       INIT_LIST_HEAD(&vnode->cb_mmap_link);
        seqlock_init(&vnode->cb_lock);
 }
 
index 9c81cf6..f6f1cbf 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -181,8 +181,9 @@ struct poll_iocb {
        struct file             *file;
        struct wait_queue_head  *head;
        __poll_t                events;
-       bool                    done;
        bool                    cancelled;
+       bool                    work_scheduled;
+       bool                    work_need_resched;
        struct wait_queue_entry wait;
        struct work_struct      work;
 };
@@ -1619,6 +1620,51 @@ static void aio_poll_put_work(struct work_struct *work)
        iocb_put(iocb);
 }
 
+/*
+ * Safely lock the waitqueue which the request is on, synchronizing with the
+ * case where the ->poll() provider decides to free its waitqueue early.
+ *
+ * Returns true on success, meaning that req->head->lock was locked, req->wait
+ * is on req->head, and an RCU read lock was taken.  Returns false if the
+ * request was already removed from its waitqueue (which might no longer exist).
+ */
+static bool poll_iocb_lock_wq(struct poll_iocb *req)
+{
+       wait_queue_head_t *head;
+
+       /*
+        * While we hold the waitqueue lock and the waitqueue is nonempty,
+        * wake_up_pollfree() will wait for us.  However, taking the waitqueue
+        * lock in the first place can race with the waitqueue being freed.
+        *
+        * We solve this as eventpoll does: by taking advantage of the fact that
+        * all users of wake_up_pollfree() will RCU-delay the actual free.  If
+        * we enter rcu_read_lock() and see that the pointer to the queue is
+        * non-NULL, we can then lock it without the memory being freed out from
+        * under us, then check whether the request is still on the queue.
+        *
+        * Keep holding rcu_read_lock() as long as we hold the queue lock, in
+        * case the caller deletes the entry from the queue, leaving it empty.
+        * In that case, only RCU prevents the queue memory from being freed.
+        */
+       rcu_read_lock();
+       head = smp_load_acquire(&req->head);
+       if (head) {
+               spin_lock(&head->lock);
+               if (!list_empty(&req->wait.entry))
+                       return true;
+               spin_unlock(&head->lock);
+       }
+       rcu_read_unlock();
+       return false;
+}
+
+static void poll_iocb_unlock_wq(struct poll_iocb *req)
+{
+       spin_unlock(&req->head->lock);
+       rcu_read_unlock();
+}
+
 static void aio_poll_complete_work(struct work_struct *work)
 {
        struct poll_iocb *req = container_of(work, struct poll_iocb, work);
@@ -1638,14 +1684,27 @@ static void aio_poll_complete_work(struct work_struct *work)
         * avoid further branches in the fast path.
         */
        spin_lock_irq(&ctx->ctx_lock);
-       if (!mask && !READ_ONCE(req->cancelled)) {
-               add_wait_queue(req->head, &req->wait);
-               spin_unlock_irq(&ctx->ctx_lock);
-               return;
-       }
+       if (poll_iocb_lock_wq(req)) {
+               if (!mask && !READ_ONCE(req->cancelled)) {
+                       /*
+                        * The request isn't actually ready to be completed yet.
+                        * Reschedule completion if another wakeup came in.
+                        */
+                       if (req->work_need_resched) {
+                               schedule_work(&req->work);
+                               req->work_need_resched = false;
+                       } else {
+                               req->work_scheduled = false;
+                       }
+                       poll_iocb_unlock_wq(req);
+                       spin_unlock_irq(&ctx->ctx_lock);
+                       return;
+               }
+               list_del_init(&req->wait.entry);
+               poll_iocb_unlock_wq(req);
+       } /* else, POLLFREE has freed the waitqueue, so we must complete */
        list_del_init(&iocb->ki_list);
        iocb->ki_res.res = mangle_poll(mask);
-       req->done = true;
        spin_unlock_irq(&ctx->ctx_lock);
 
        iocb_put(iocb);
@@ -1657,13 +1716,14 @@ static int aio_poll_cancel(struct kiocb *iocb)
        struct aio_kiocb *aiocb = container_of(iocb, struct aio_kiocb, rw);
        struct poll_iocb *req = &aiocb->poll;
 
-       spin_lock(&req->head->lock);
-       WRITE_ONCE(req->cancelled, true);
-       if (!list_empty(&req->wait.entry)) {
-               list_del_init(&req->wait.entry);
-               schedule_work(&aiocb->poll.work);
-       }
-       spin_unlock(&req->head->lock);
+       if (poll_iocb_lock_wq(req)) {
+               WRITE_ONCE(req->cancelled, true);
+               if (!req->work_scheduled) {
+                       schedule_work(&aiocb->poll.work);
+                       req->work_scheduled = true;
+               }
+               poll_iocb_unlock_wq(req);
+       } /* else, the request was force-cancelled by POLLFREE already */
 
        return 0;
 }
@@ -1680,21 +1740,27 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
        if (mask && !(mask & req->events))
                return 0;
 
-       list_del_init(&req->wait.entry);
-
-       if (mask && spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) {
+       /*
+        * Complete the request inline if possible.  This requires that three
+        * conditions be met:
+        *   1. An event mask must have been passed.  If a plain wakeup was done
+        *      instead, then mask == 0 and we have to call vfs_poll() to get
+        *      the events, so inline completion isn't possible.
+        *   2. The completion work must not have already been scheduled.
+        *   3. ctx_lock must not be busy.  We have to use trylock because we
+        *      already hold the waitqueue lock, so this inverts the normal
+        *      locking order.  Use irqsave/irqrestore because not all
+        *      filesystems (e.g. fuse) call this function with IRQs disabled,
+        *      yet IRQs have to be disabled before ctx_lock is obtained.
+        */
+       if (mask && !req->work_scheduled &&
+           spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) {
                struct kioctx *ctx = iocb->ki_ctx;
 
-               /*
-                * Try to complete the iocb inline if we can. Use
-                * irqsave/irqrestore because not all filesystems (e.g. fuse)
-                * call this function with IRQs disabled and because IRQs
-                * have to be disabled before ctx_lock is obtained.
-                */
+               list_del_init(&req->wait.entry);
                list_del(&iocb->ki_list);
                iocb->ki_res.res = mangle_poll(mask);
-               req->done = true;
-               if (iocb->ki_eventfd && eventfd_signal_allowed()) {
+               if (iocb->ki_eventfd && !eventfd_signal_allowed()) {
                        iocb = NULL;
                        INIT_WORK(&req->work, aio_poll_put_work);
                        schedule_work(&req->work);
@@ -1703,7 +1769,43 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
                if (iocb)
                        iocb_put(iocb);
        } else {
-               schedule_work(&req->work);
+               /*
+                * Schedule the completion work if needed.  If it was already
+                * scheduled, record that another wakeup came in.
+                *
+                * Don't remove the request from the waitqueue here, as it might
+                * not actually be complete yet (we won't know until vfs_poll()
+                * is called), and we must not miss any wakeups.  POLLFREE is an
+                * exception to this; see below.
+                */
+               if (req->work_scheduled) {
+                       req->work_need_resched = true;
+               } else {
+                       schedule_work(&req->work);
+                       req->work_scheduled = true;
+               }
+
+               /*
+                * If the waitqueue is being freed early but we can't complete
+                * the request inline, we have to tear down the request as best
+                * we can.  That means immediately removing the request from its
+                * waitqueue and preventing all further accesses to the
+                * waitqueue via the request.  We also need to schedule the
+                * completion work (done above).  Also mark the request as
+                * cancelled, to potentially skip an unneeded call to ->poll().
+                */
+               if (mask & POLLFREE) {
+                       WRITE_ONCE(req->cancelled, true);
+                       list_del_init(&req->wait.entry);
+
+                       /*
+                        * Careful: this *must* be the last step, since as soon
+                        * as req->head is NULL'ed out, the request can be
+                        * completed and freed, since aio_poll_complete_work()
+                        * will no longer need to take the waitqueue lock.
+                        */
+                       smp_store_release(&req->head, NULL);
+               }
        }
        return 1;
 }
@@ -1711,6 +1813,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
 struct aio_poll_table {
        struct poll_table_struct        pt;
        struct aio_kiocb                *iocb;
+       bool                            queued;
        int                             error;
 };
 
@@ -1721,11 +1824,12 @@ aio_poll_queue_proc(struct file *file, struct wait_queue_head *head,
        struct aio_poll_table *pt = container_of(p, struct aio_poll_table, pt);
 
        /* multiple wait queues per file are not supported */
-       if (unlikely(pt->iocb->poll.head)) {
+       if (unlikely(pt->queued)) {
                pt->error = -EINVAL;
                return;
        }
 
+       pt->queued = true;
        pt->error = 0;
        pt->iocb->poll.head = head;
        add_wait_queue(head, &pt->iocb->poll.wait);
@@ -1750,12 +1854,14 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
        req->events = demangle_poll(iocb->aio_buf) | EPOLLERR | EPOLLHUP;
 
        req->head = NULL;
-       req->done = false;
        req->cancelled = false;
+       req->work_scheduled = false;
+       req->work_need_resched = false;
 
        apt.pt._qproc = aio_poll_queue_proc;
        apt.pt._key = req->events;
        apt.iocb = aiocb;
+       apt.queued = false;
        apt.error = -EINVAL; /* same as no support for IOCB_CMD_POLL */
 
        /* initialized the list so that we can do list_empty checks */
@@ -1764,23 +1870,35 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
 
        mask = vfs_poll(req->file, &apt.pt) & req->events;
        spin_lock_irq(&ctx->ctx_lock);
-       if (likely(req->head)) {
-               spin_lock(&req->head->lock);
-               if (unlikely(list_empty(&req->wait.entry))) {
-                       if (apt.error)
+       if (likely(apt.queued)) {
+               bool on_queue = poll_iocb_lock_wq(req);
+
+               if (!on_queue || req->work_scheduled) {
+                       /*
+                        * aio_poll_wake() already either scheduled the async
+                        * completion work, or completed the request inline.
+                        */
+                       if (apt.error) /* unsupported case: multiple queues */
                                cancel = true;
                        apt.error = 0;
                        mask = 0;
                }
                if (mask || apt.error) {
+                       /* Steal to complete synchronously. */
                        list_del_init(&req->wait.entry);
                } else if (cancel) {
+                       /* Cancel if possible (may be too late though). */
                        WRITE_ONCE(req->cancelled, true);
-               } else if (!req->done) { /* actually waiting for an event */
+               } else if (on_queue) {
+                       /*
+                        * Actually waiting for an event, so add the request to
+                        * active_reqs so that it can be cancelled if needed.
+                        */
                        list_add_tail(&aiocb->ki_list, &ctx->active_reqs);
                        aiocb->ki_cancel = aio_poll_cancel;
                }
-               spin_unlock(&req->head->lock);
+               if (on_queue)
+                       poll_iocb_unlock_wq(req);
        }
        if (mask) { /* no async, we'd stolen it */
                aiocb->ki_res.res = mangle_poll(mask);
index c3983bd..f704339 100644 (file)
@@ -463,8 +463,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                BUG_ON(ret < 0);
                rcu_assign_pointer(root->node, cow);
 
-               btrfs_free_tree_block(trans, root, buf, parent_start,
-                                     last_ref);
+               btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
+                                     parent_start, last_ref);
                free_extent_buffer(buf);
                add_root_to_dirty_list(root);
        } else {
@@ -485,8 +485,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                                return ret;
                        }
                }
-               btrfs_free_tree_block(trans, root, buf, parent_start,
-                                     last_ref);
+               btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
+                                     parent_start, last_ref);
        }
        if (unlock_orig)
                btrfs_tree_unlock(buf);
@@ -927,7 +927,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                free_extent_buffer(mid);
 
                root_sub_used(root, mid->len);
-               btrfs_free_tree_block(trans, root, mid, 0, 1);
+               btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
                /* once for the root ptr */
                free_extent_buffer_stale(mid);
                return 0;
@@ -986,7 +986,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                        btrfs_tree_unlock(right);
                        del_ptr(root, path, level + 1, pslot + 1);
                        root_sub_used(root, right->len);
-                       btrfs_free_tree_block(trans, root, right, 0, 1);
+                       btrfs_free_tree_block(trans, btrfs_root_id(root), right,
+                                             0, 1);
                        free_extent_buffer_stale(right);
                        right = NULL;
                } else {
@@ -1031,7 +1032,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                btrfs_tree_unlock(mid);
                del_ptr(root, path, level + 1, pslot);
                root_sub_used(root, mid->len);
-               btrfs_free_tree_block(trans, root, mid, 0, 1);
+               btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
                free_extent_buffer_stale(mid);
                mid = NULL;
        } else {
@@ -4032,7 +4033,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
        root_sub_used(root, leaf->len);
 
        atomic_inc(&leaf->refs);
-       btrfs_free_tree_block(trans, root, leaf, 0, 1);
+       btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
        free_extent_buffer_stale(leaf);
 }
 /*
index 7553e9d..5fe5ecc 100644 (file)
@@ -2257,6 +2257,11 @@ static inline bool btrfs_root_dead(const struct btrfs_root *root)
        return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
 }
 
+static inline u64 btrfs_root_id(const struct btrfs_root *root)
+{
+       return root->root_key.objectid;
+}
+
 /* struct btrfs_root_backup */
 BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
                   tree_root, 64);
@@ -2719,7 +2724,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
                                             u64 empty_size,
                                             enum btrfs_lock_nesting nest);
 void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
-                          struct btrfs_root *root,
+                          u64 root_id,
                           struct extent_buffer *buf,
                           u64 parent, int last_ref);
 int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
index 2059d15..40c4d6b 100644 (file)
@@ -143,10 +143,13 @@ int btrfs_check_data_free_space(struct btrfs_inode *inode,
 
        /* Use new btrfs_qgroup_reserve_data to reserve precious data space. */
        ret = btrfs_qgroup_reserve_data(inode, reserved, start, len);
-       if (ret < 0)
+       if (ret < 0) {
                btrfs_free_reserved_data_space_noquota(fs_info, len);
-       else
+               extent_changeset_free(*reserved);
+               *reserved = NULL;
+       } else {
                ret = 0;
+       }
        return ret;
 }
 
@@ -452,8 +455,11 @@ int btrfs_delalloc_reserve_space(struct btrfs_inode *inode,
        if (ret < 0)
                return ret;
        ret = btrfs_delalloc_reserve_metadata(inode, len);
-       if (ret < 0)
+       if (ret < 0) {
                btrfs_free_reserved_data_space(inode, *reserved, start, len);
+               extent_changeset_free(*reserved);
+               *reserved = NULL;
+       }
        return ret;
 }
 
index 514ead6..b3f2e22 100644 (file)
@@ -1732,6 +1732,14 @@ again:
        }
        return root;
 fail:
+       /*
+        * If our caller provided us an anonymous device, then it's his
+        * responsability to free it in case we fail. So we have to set our
+        * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
+        * and once again by our caller.
+        */
+       if (anon_dev)
+               root->anon_dev = 0;
        btrfs_put_root(root);
        return ERR_PTR(ret);
 }
index 3fd736a..25ef6e3 100644 (file)
@@ -3275,20 +3275,20 @@ out_delayed_unlock:
 }
 
 void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
-                          struct btrfs_root *root,
+                          u64 root_id,
                           struct extent_buffer *buf,
                           u64 parent, int last_ref)
 {
-       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_fs_info *fs_info = trans->fs_info;
        struct btrfs_ref generic_ref = { 0 };
        int ret;
 
        btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
                               buf->start, buf->len, parent);
        btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
-                           root->root_key.objectid, 0, false);
+                           root_id, 0, false);
 
-       if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
+       if (root_id != BTRFS_TREE_LOG_OBJECTID) {
                btrfs_ref_tree_mod(fs_info, &generic_ref);
                ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL);
                BUG_ON(ret); /* -ENOMEM */
@@ -3298,7 +3298,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                struct btrfs_block_group *cache;
                bool must_pin = false;
 
-               if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
+               if (root_id != BTRFS_TREE_LOG_OBJECTID) {
                        ret = check_ref_cleanup(trans, buf->start);
                        if (!ret) {
                                btrfs_redirty_list_add(trans->transaction, buf);
@@ -5472,7 +5472,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                        goto owner_mismatch;
        }
 
-       btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
+       btrfs_free_tree_block(trans, btrfs_root_id(root), eb, parent,
+                             wc->refs[level] == 1);
 out:
        wc->refs[level] = 0;
        wc->flags[level] = 0;
@@ -6051,6 +6052,9 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
        int dev_ret = 0;
        int ret = 0;
 
+       if (range->start == U64_MAX)
+               return -EINVAL;
+
        /*
         * Check range overflow if range->len is set.
         * The default range->len is U64_MAX.
index 4e03a6d..9234d96 100644 (file)
@@ -4314,6 +4314,20 @@ static void set_btree_ioerr(struct page *page, struct extent_buffer *eb)
                return;
 
        /*
+        * A read may stumble upon this buffer later, make sure that it gets an
+        * error and knows there was an error.
+        */
+       clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
+
+       /*
+        * We need to set the mapping with the io error as well because a write
+        * error will flip the file system readonly, and then syncfs() will
+        * return a 0 because we are readonly if we don't modify the err seq for
+        * the superblock.
+        */
+       mapping_set_error(page->mapping, -EIO);
+
+       /*
         * If we error out, we should add back the dirty_metadata_bytes
         * to make it consistent.
         */
@@ -6597,6 +6611,14 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
        if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
                return 0;
 
+       /*
+        * We could have had EXTENT_BUFFER_UPTODATE cleared by the write
+        * operation, which could potentially still be in flight.  In this case
+        * we simply want to return an error.
+        */
+       if (unlikely(test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)))
+               return -EIO;
+
        if (eb->fs_info->sectorsize < PAGE_SIZE)
                return read_extent_buffer_subpage(eb, wait, mirror_num);
 
index a33bca9..3abec44 100644 (file)
@@ -1256,8 +1256,8 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
        btrfs_tree_lock(free_space_root->node);
        btrfs_clean_tree_block(free_space_root->node);
        btrfs_tree_unlock(free_space_root->node);
-       btrfs_free_tree_block(trans, free_space_root, free_space_root->node,
-                             0, 1);
+       btrfs_free_tree_block(trans, btrfs_root_id(free_space_root),
+                             free_space_root->node, 0, 1);
 
        btrfs_put_root(free_space_root);
 
index 92138ac..edfecfe 100644 (file)
@@ -617,11 +617,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
                 * Since we don't abort the transaction in this case, free the
                 * tree block so that we don't leak space and leave the
                 * filesystem in an inconsistent state (an extent item in the
-                * extent tree without backreferences). Also no need to have
-                * the tree block locked since it is not in any tree at this
-                * point, so no other task can find it and use it.
+                * extent tree with a backreference for a root that does not
+                * exists).
                 */
-               btrfs_free_tree_block(trans, root, leaf, 0, 1);
+               btrfs_tree_lock(leaf);
+               btrfs_clean_tree_block(leaf);
+               btrfs_tree_unlock(leaf);
+               btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
                free_extent_buffer(leaf);
                goto fail;
        }
@@ -3187,10 +3189,8 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
                return -EPERM;
 
        vol_args = memdup_user(arg, sizeof(*vol_args));
-       if (IS_ERR(vol_args)) {
-               ret = PTR_ERR(vol_args);
-               goto out;
-       }
+       if (IS_ERR(vol_args))
+               return PTR_ERR(vol_args);
 
        if (vol_args->flags & ~BTRFS_DEVICE_REMOVE_ARGS_MASK) {
                ret = -EOPNOTSUPP;
index db680f5..6c037f1 100644 (file)
@@ -1219,7 +1219,8 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        btrfs_tree_lock(quota_root->node);
        btrfs_clean_tree_block(quota_root->node);
        btrfs_tree_unlock(quota_root->node);
-       btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1);
+       btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
+                             quota_root->node, 0, 1);
 
        btrfs_put_root(quota_root);
 
index 12ceb14..d201663 100644 (file)
@@ -334,7 +334,8 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
        key.offset = ref_id;
 again:
        ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
-       BUG_ON(ret < 0);
+       if (ret < 0)
+               goto out;
        if (ret == 0) {
                leaf = path->nodes[0];
                ref = btrfs_item_ptr(leaf, path->slots[0],
index 8ab33ca..6993dcd 100644 (file)
@@ -1181,6 +1181,7 @@ again:
                                             parent_objectid, victim_name,
                                             victim_name_len);
                        if (ret < 0) {
+                               kfree(victim_name);
                                return ret;
                        } else if (!ret) {
                                ret = -ENOENT;
@@ -2908,6 +2909,8 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                                     path->nodes[*level]->len);
                                        if (ret)
                                                return ret;
+                                       btrfs_redirty_list_add(trans->transaction,
+                                                              next);
                                } else {
                                        if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
                                                clear_extent_buffer_dirty(next);
@@ -2988,6 +2991,7 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                                                next->start, next->len);
                                if (ret)
                                        goto out;
+                               btrfs_redirty_list_add(trans->transaction, next);
                        } else {
                                if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
                                        clear_extent_buffer_dirty(next);
@@ -3438,8 +3442,6 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
                          EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
        extent_io_tree_release(&log->log_csum_range);
 
-       if (trans && log->node)
-               btrfs_redirty_list_add(trans->transaction, log->node);
        btrfs_put_root(log);
 }
 
@@ -3976,6 +3978,7 @@ search:
                        goto done;
                }
                if (btrfs_header_generation(path->nodes[0]) != trans->transid) {
+                       ctx->last_dir_item_offset = min_key.offset;
                        ret = overwrite_item(trans, log, dst_path,
                                             path->nodes[0], path->slots[0],
                                             &min_key);
index 0997e3c..fd0ced8 100644 (file)
@@ -1370,8 +1370,10 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, fmode_t flags,
 
        bytenr_orig = btrfs_sb_offset(0);
        ret = btrfs_sb_log_location_bdev(bdev, 0, READ, &bytenr);
-       if (ret)
-               return ERR_PTR(ret);
+       if (ret) {
+               device = ERR_PTR(ret);
+               goto error_bdev_put;
+       }
 
        disk_super = btrfs_read_disk_super(bdev, bytenr, bytenr_orig);
        if (IS_ERR(disk_super)) {
index 67d932d..678a294 100644 (file)
@@ -1860,6 +1860,7 @@ int btrfs_zone_finish(struct btrfs_block_group *block_group)
        block_group->alloc_offset = block_group->zone_capacity;
        block_group->free_space_ctl->free_space = 0;
        btrfs_clear_treelog_bg(block_group);
+       btrfs_clear_data_reloc_bg(block_group);
        spin_unlock(&block_group->lock);
 
        ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
@@ -1942,6 +1943,7 @@ void btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 len
        ASSERT(block_group->alloc_offset == block_group->zone_capacity);
        ASSERT(block_group->free_space_ctl->free_space == 0);
        btrfs_clear_treelog_bg(block_group);
+       btrfs_clear_data_reloc_bg(block_group);
        spin_unlock(&block_group->lock);
 
        map = block_group->physical_map;
index b9460b6..c447fa2 100644 (file)
@@ -4350,7 +4350,7 @@ void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count)
 {
        struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(ci->vfs_inode.i_sb);
        int bits = (fmode << 1) | 1;
-       bool is_opened = false;
+       bool already_opened = false;
        int i;
 
        if (count == 1)
@@ -4358,19 +4358,19 @@ void ceph_get_fmode(struct ceph_inode_info *ci, int fmode, int count)
 
        spin_lock(&ci->i_ceph_lock);
        for (i = 0; i < CEPH_FILE_MODE_BITS; i++) {
-               if (bits & (1 << i))
-                       ci->i_nr_by_mode[i] += count;
-
                /*
-                * If any of the mode ref is larger than 1,
+                * If any of the mode ref is larger than 0,
                 * that means it has been already opened by
                 * others. Just skip checking the PIN ref.
                 */
-               if (i && ci->i_nr_by_mode[i] > 1)
-                       is_opened = true;
+               if (i && ci->i_nr_by_mode[i])
+                       already_opened = true;
+
+               if (bits & (1 << i))
+                       ci->i_nr_by_mode[i] += count;
        }
 
-       if (!is_opened)
+       if (!already_opened)
                percpu_counter_inc(&mdsc->metric.opened_inodes);
        spin_unlock(&ci->i_ceph_lock);
 }
index 02a0a0f..c138e81 100644 (file)
@@ -605,13 +605,25 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        in.cap.realm = cpu_to_le64(ci->i_snap_realm->ino);
        in.cap.flags = CEPH_CAP_FLAG_AUTH;
        in.ctime = in.mtime = in.atime = iinfo.btime;
-       in.mode = cpu_to_le32((u32)mode);
        in.truncate_seq = cpu_to_le32(1);
        in.truncate_size = cpu_to_le64(-1ULL);
        in.xattr_version = cpu_to_le64(1);
        in.uid = cpu_to_le32(from_kuid(&init_user_ns, current_fsuid()));
-       in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_mode & S_ISGID ?
-                               dir->i_gid : current_fsgid()));
+       if (dir->i_mode & S_ISGID) {
+               in.gid = cpu_to_le32(from_kgid(&init_user_ns, dir->i_gid));
+
+               /* Directories always inherit the setgid bit. */
+               if (S_ISDIR(mode))
+                       mode |= S_ISGID;
+               else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
+                        !in_group_p(dir->i_gid) &&
+                        !capable_wrt_inode_uidgid(&init_user_ns, dir, CAP_FSETID))
+                       mode &= ~S_ISGID;
+       } else {
+               in.gid = cpu_to_le32(from_kgid(&init_user_ns, current_fsgid()));
+       }
+       in.mode = cpu_to_le32((u32)mode);
+
        in.nlink = cpu_to_le32(1);
        in.max_size = cpu_to_le64(lo->stripe_unit);
 
@@ -847,7 +859,7 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,
        ssize_t ret;
        u64 off = iocb->ki_pos;
        u64 len = iov_iter_count(to);
-       u64 i_size;
+       u64 i_size = i_size_read(inode);
 
        dout("sync_read on file %p %llu~%u %s\n", file, off, (unsigned)len,
             (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
index 250aad3..c30eefc 100644 (file)
@@ -3683,7 +3683,7 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap,
        struct ceph_pagelist *pagelist = recon_state->pagelist;
        struct dentry *dentry;
        char *path;
-       int pathlen, err;
+       int pathlen = 0, err;
        u64 pathbase;
        u64 snap_follows;
 
@@ -3703,7 +3703,6 @@ static int reconnect_caps_cb(struct inode *inode, struct ceph_cap *cap,
                }
        } else {
                path = NULL;
-               pathlen = 0;
                pathbase = 0;
        }
 
index 18448db..1060164 100644 (file)
@@ -3064,6 +3064,13 @@ static int mount_get_conns(struct mount_ctx *mnt_ctx)
            (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
                cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
 
+       /*
+        * The cookie is initialized from volume info returned above.
+        * Inside cifs_fscache_get_super_cookie it checks
+        * that we do not get super cookie twice.
+        */
+       cifs_fscache_get_super_cookie(tcon);
+
 out:
        mnt_ctx->server = server;
        mnt_ctx->ses = ses;
index 6a179ae..e3ed25d 100644 (file)
@@ -435,6 +435,42 @@ out:
 }
 
 /*
+ * Remove duplicate path delimiters. Windows is supposed to do that
+ * but there are some bugs that prevent rename from working if there are
+ * multiple delimiters.
+ *
+ * Returns a sanitized duplicate of @path. The caller is responsible for
+ * cleaning up the original.
+ */
+#define IS_DELIM(c) ((c) == '/' || (c) == '\\')
+static char *sanitize_path(char *path)
+{
+       char *cursor1 = path, *cursor2 = path;
+
+       /* skip all prepended delimiters */
+       while (IS_DELIM(*cursor1))
+               cursor1++;
+
+       /* copy the first letter */
+       *cursor2 = *cursor1;
+
+       /* copy the remainder... */
+       while (*(cursor1++)) {
+               /* ... skipping all duplicated delimiters */
+               if (IS_DELIM(*cursor1) && IS_DELIM(*cursor2))
+                       continue;
+               *(++cursor2) = *cursor1;
+       }
+
+       /* if the last character is a delimiter, skip it */
+       if (IS_DELIM(*(cursor2 - 1)))
+               cursor2--;
+
+       *(cursor2) = '\0';
+       return kstrdup(path, GFP_KERNEL);
+}
+
+/*
  * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
  * fields with the result. Returns 0 on success and an error otherwise
  * (e.g. ENOMEM or EINVAL)
@@ -493,7 +529,7 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
        if (!*pos)
                return 0;
 
-       ctx->prepath = kstrdup(pos, GFP_KERNEL);
+       ctx->prepath = sanitize_path(pos);
        if (!ctx->prepath)
                return -ENOMEM;
 
index 96d083d..279622e 100644 (file)
@@ -1356,11 +1356,6 @@ iget_no_retry:
                goto out;
        }
 
-#ifdef CONFIG_CIFS_FSCACHE
-       /* populate tcon->resource_id */
-       tcon->resource_id = CIFS_I(inode)->uniqueid;
-#endif
-
        if (rc && tcon->pipe) {
                cifs_dbg(FYI, "ipc connection - fake read inode\n");
                spin_lock(&inode->i_lock);
@@ -1375,14 +1370,6 @@ iget_no_retry:
                iget_failed(inode);
                inode = ERR_PTR(rc);
        }
-
-       /*
-        * The cookie is initialized from volume info returned above.
-        * Inside cifs_fscache_get_super_cookie it checks
-        * that we do not get super cookie twice.
-        */
-       cifs_fscache_get_super_cookie(tcon);
-
 out:
        kfree(path);
        free_xid(xid);
index af63548..035dc3e 100644 (file)
@@ -590,8 +590,8 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
 {
        unsigned int tioffset; /* challenge message target info area */
        unsigned int tilen; /* challenge message target info area length  */
-
        CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
+       __u32 server_flags;
 
        if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
                cifs_dbg(VFS, "challenge blob len %d too small\n", blob_len);
@@ -609,12 +609,37 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
                return -EINVAL;
        }
 
+       server_flags = le32_to_cpu(pblob->NegotiateFlags);
+       cifs_dbg(FYI, "%s: negotiate=0x%08x challenge=0x%08x\n", __func__,
+                ses->ntlmssp->client_flags, server_flags);
+
+       if ((ses->ntlmssp->client_flags & (NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN)) &&
+           (!(server_flags & NTLMSSP_NEGOTIATE_56) && !(server_flags & NTLMSSP_NEGOTIATE_128))) {
+               cifs_dbg(VFS, "%s: requested signing/encryption but server did not return either 56-bit or 128-bit session key size\n",
+                        __func__);
+               return -EINVAL;
+       }
+       if (!(server_flags & NTLMSSP_NEGOTIATE_NTLM) && !(server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) {
+               cifs_dbg(VFS, "%s: server does not seem to support either NTLMv1 or NTLMv2\n", __func__);
+               return -EINVAL;
+       }
+       if (ses->server->sign && !(server_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+               cifs_dbg(VFS, "%s: forced packet signing but server does not seem to support it\n",
+                        __func__);
+               return -EOPNOTSUPP;
+       }
+       if ((ses->ntlmssp->client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
+           !(server_flags & NTLMSSP_NEGOTIATE_KEY_XCH))
+               pr_warn_once("%s: authentication has been weakened as server does not support key exchange\n",
+                            __func__);
+
+       ses->ntlmssp->server_flags = server_flags;
+
        memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
-       /* BB we could decode pblob->NegotiateFlags; some may be useful */
        /* In particular we can examine sign flags */
        /* BB spec says that if AvId field of MsvAvTimestamp is populated then
                we must set the MIC field of the AUTHENTICATE_MESSAGE */
-       ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags);
+
        tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset);
        tilen = le16_to_cpu(pblob->TargetInfoArray.Length);
        if (tioffset > blob_len || tioffset + tilen > blob_len) {
@@ -721,13 +746,13 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
        flags = NTLMSSP_NEGOTIATE_56 |  NTLMSSP_REQUEST_TARGET |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
-               NTLMSSP_NEGOTIATE_SEAL;
-       if (server->sign)
-               flags |= NTLMSSP_NEGOTIATE_SIGN;
+               NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL |
+               NTLMSSP_NEGOTIATE_SIGN;
        if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
                flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 
        tmp = *pbuffer + sizeof(NEGOTIATE_MESSAGE);
+       ses->ntlmssp->client_flags = flags;
        sec_blob->NegotiateFlags = cpu_to_le32(flags);
 
        /* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
@@ -779,15 +804,8 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
        memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
        sec_blob->MessageType = NtLmAuthenticate;
 
-       flags = NTLMSSP_NEGOTIATE_56 |
-               NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
-               NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
-               NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
-       if (ses->server->sign)
-               flags |= NTLMSSP_NEGOTIATE_SIGN;
-       if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
-               flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
+       flags = ses->ntlmssp->server_flags | NTLMSSP_REQUEST_TARGET |
+               NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
 
        tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
        sec_blob->NegotiateFlags = cpu_to_le32(flags);
@@ -834,9 +852,9 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
                                      *pbuffer, &tmp,
                                      nls_cp);
 
-       if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) ||
-               (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
-                       && !calc_seckey(ses)) {
+       if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
+           (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) &&
+           !calc_seckey(ses)) {
                memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
                sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
                sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
index ad4a8bf..97d212a 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -841,28 +841,68 @@ void do_close_on_exec(struct files_struct *files)
        spin_unlock(&files->file_lock);
 }
 
-static struct file *__fget_files(struct files_struct *files, unsigned int fd,
-                                fmode_t mask, unsigned int refs)
+static inline struct file *__fget_files_rcu(struct files_struct *files,
+       unsigned int fd, fmode_t mask, unsigned int refs)
 {
-       struct file *file;
+       for (;;) {
+               struct file *file;
+               struct fdtable *fdt = rcu_dereference_raw(files->fdt);
+               struct file __rcu **fdentry;
 
-       rcu_read_lock();
-loop:
-       file = files_lookup_fd_rcu(files, fd);
-       if (file) {
-               /* File object ref couldn't be taken.
-                * dup2() atomicity guarantee is the reason
-                * we loop to catch the new file (or NULL pointer)
+               if (unlikely(fd >= fdt->max_fds))
+                       return NULL;
+
+               fdentry = fdt->fd + array_index_nospec(fd, fdt->max_fds);
+               file = rcu_dereference_raw(*fdentry);
+               if (unlikely(!file))
+                       return NULL;
+
+               if (unlikely(file->f_mode & mask))
+                       return NULL;
+
+               /*
+                * Ok, we have a file pointer. However, because we do
+                * this all locklessly under RCU, we may be racing with
+                * that file being closed.
+                *
+                * Such a race can take two forms:
+                *
+                *  (a) the file ref already went down to zero,
+                *      and get_file_rcu_many() fails. Just try
+                *      again:
                 */
-               if (file->f_mode & mask)
-                       file = NULL;
-               else if (!get_file_rcu_many(file, refs))
-                       goto loop;
-               else if (files_lookup_fd_raw(files, fd) != file) {
+               if (unlikely(!get_file_rcu_many(file, refs)))
+                       continue;
+
+               /*
+                *  (b) the file table entry has changed under us.
+                *       Note that we don't need to re-check the 'fdt->fd'
+                *       pointer having changed, because it always goes
+                *       hand-in-hand with 'fdt'.
+                *
+                * If so, we need to put our refs and try again.
+                */
+               if (unlikely(rcu_dereference_raw(files->fdt) != fdt) ||
+                   unlikely(rcu_dereference_raw(*fdentry) != file)) {
                        fput_many(file, refs);
-                       goto loop;
+                       continue;
                }
+
+               /*
+                * Ok, we have a ref to the file, and checked that it
+                * still exists.
+                */
+               return file;
        }
+}
+
+static struct file *__fget_files(struct files_struct *files, unsigned int fd,
+                                fmode_t mask, unsigned int refs)
+{
+       struct file *file;
+
+       rcu_read_lock();
+       file = __fget_files_rcu(files, fd, mask, refs);
        rcu_read_unlock();
 
        return file;
index 50cf9f9..5c4f582 100644 (file)
@@ -142,6 +142,7 @@ static bool io_acct_cancel_pending_work(struct io_wqe *wqe,
                                        struct io_wqe_acct *acct,
                                        struct io_cb_cancel_data *match);
 static void create_worker_cb(struct callback_head *cb);
+static void io_wq_cancel_tw_create(struct io_wq *wq);
 
 static bool io_worker_get(struct io_worker *worker)
 {
@@ -357,12 +358,22 @@ static bool io_queue_worker_create(struct io_worker *worker,
            test_and_set_bit_lock(0, &worker->create_state))
                goto fail_release;
 
+       atomic_inc(&wq->worker_refs);
        init_task_work(&worker->create_work, func);
        worker->create_index = acct->index;
        if (!task_work_add(wq->task, &worker->create_work, TWA_SIGNAL)) {
-               clear_bit_unlock(0, &worker->create_state);
+               /*
+                * EXIT may have been set after checking it above, check after
+                * adding the task_work and remove any creation item if it is
+                * now set. wq exit does that too, but we can have added this
+                * work item after we canceled in io_wq_exit_workers().
+                */
+               if (test_bit(IO_WQ_BIT_EXIT, &wq->state))
+                       io_wq_cancel_tw_create(wq);
+               io_worker_ref_put(wq);
                return true;
        }
+       io_worker_ref_put(wq);
        clear_bit_unlock(0, &worker->create_state);
 fail_release:
        io_worker_release(worker);
@@ -384,7 +395,9 @@ static void io_wqe_dec_running(struct io_worker *worker)
        if (atomic_dec_and_test(&acct->nr_running) && io_acct_run_queue(acct)) {
                atomic_inc(&acct->nr_running);
                atomic_inc(&wqe->wq->worker_refs);
+               raw_spin_unlock(&wqe->lock);
                io_queue_worker_create(worker, acct, create_worker_cb);
+               raw_spin_lock(&wqe->lock);
        }
 }
 
@@ -1198,13 +1211,9 @@ void io_wq_exit_start(struct io_wq *wq)
        set_bit(IO_WQ_BIT_EXIT, &wq->state);
 }
 
-static void io_wq_exit_workers(struct io_wq *wq)
+static void io_wq_cancel_tw_create(struct io_wq *wq)
 {
        struct callback_head *cb;
-       int node;
-
-       if (!wq->task)
-               return;
 
        while ((cb = task_work_cancel_match(wq->task, io_task_work_match, wq)) != NULL) {
                struct io_worker *worker;
@@ -1212,6 +1221,16 @@ static void io_wq_exit_workers(struct io_wq *wq)
                worker = container_of(cb, struct io_worker, create_work);
                io_worker_cancel_cb(worker);
        }
+}
+
+static void io_wq_exit_workers(struct io_wq *wq)
+{
+       int node;
+
+       if (!wq->task)
+               return;
+
+       io_wq_cancel_tw_create(wq);
 
        rcu_read_lock();
        for_each_node(node) {
index c4f2176..d5ab0e9 100644 (file)
@@ -9824,7 +9824,7 @@ static __cold void io_uring_drop_tctx_refs(struct task_struct *task)
 
 /*
  * Find any io_uring ctx that this task has registered or done IO on, and cancel
- * requests. @sqd should be not-null IIF it's an SQPOLL thread cancellation.
+ * requests. @sqd should be not-null IFF it's an SQPOLL thread cancellation.
  */
 static __cold void io_uring_cancel_generic(bool cancel_all,
                                           struct io_sq_data *sqd)
@@ -9866,8 +9866,10 @@ static __cold void io_uring_cancel_generic(bool cancel_all,
                                                             cancel_all);
                }
 
-               prepare_to_wait(&tctx->wait, &wait, TASK_UNINTERRUPTIBLE);
+               prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE);
+               io_run_task_work();
                io_uring_drop_tctx_refs(current);
+
                /*
                 * If we've seen completions, retry without waiting. This
                 * avoids a race where a completion comes in before we did
index 7046f9b..75c76cb 100644 (file)
@@ -354,16 +354,11 @@ static void netfs_rreq_write_to_cache_work(struct work_struct *work)
        netfs_rreq_do_write_to_cache(rreq);
 }
 
-static void netfs_rreq_write_to_cache(struct netfs_read_request *rreq,
-                                     bool was_async)
+static void netfs_rreq_write_to_cache(struct netfs_read_request *rreq)
 {
-       if (was_async) {
-               rreq->work.func = netfs_rreq_write_to_cache_work;
-               if (!queue_work(system_unbound_wq, &rreq->work))
-                       BUG();
-       } else {
-               netfs_rreq_do_write_to_cache(rreq);
-       }
+       rreq->work.func = netfs_rreq_write_to_cache_work;
+       if (!queue_work(system_unbound_wq, &rreq->work))
+               BUG();
 }
 
 /*
@@ -558,7 +553,7 @@ again:
        wake_up_bit(&rreq->flags, NETFS_RREQ_IN_PROGRESS);
 
        if (test_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags))
-               return netfs_rreq_write_to_cache(rreq, was_async);
+               return netfs_rreq_write_to_cache(rreq);
 
        netfs_rreq_completed(rreq, was_async);
 }
@@ -960,7 +955,7 @@ int netfs_readpage(struct file *file,
        rreq = netfs_alloc_read_request(ops, netfs_priv, file);
        if (!rreq) {
                if (netfs_priv)
-                       ops->cleanup(netfs_priv, folio_file_mapping(folio));
+                       ops->cleanup(folio_file_mapping(folio), netfs_priv);
                folio_unlock(folio);
                return -ENOMEM;
        }
@@ -1191,7 +1186,7 @@ have_folio:
                goto error;
 have_folio_no_wait:
        if (netfs_priv)
-               ops->cleanup(netfs_priv, mapping);
+               ops->cleanup(mapping, netfs_priv);
        *_folio = folio;
        _leave(" = 0");
        return 0;
@@ -1202,7 +1197,7 @@ error:
        folio_unlock(folio);
        folio_put(folio);
        if (netfs_priv)
-               ops->cleanup(netfs_priv, mapping);
+               ops->cleanup(mapping, netfs_priv);
        _leave(" = %d", ret);
        return ret;
 }
index 6fedc49..c634483 100644 (file)
@@ -2156,6 +2156,7 @@ static struct notifier_block nfsd4_cld_block = {
 int
 register_cld_notifier(void)
 {
+       WARN_ON(!nfsd_net_id);
        return rpc_pipefs_notifier_register(&nfsd4_cld_block);
 }
 
index bfad94c..1956d37 100644 (file)
@@ -1207,6 +1207,11 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
        return 0;
 }
 
+static bool delegation_hashed(struct nfs4_delegation *dp)
+{
+       return !(list_empty(&dp->dl_perfile));
+}
+
 static bool
 unhash_delegation_locked(struct nfs4_delegation *dp)
 {
@@ -1214,7 +1219,7 @@ unhash_delegation_locked(struct nfs4_delegation *dp)
 
        lockdep_assert_held(&state_lock);
 
-       if (list_empty(&dp->dl_perfile))
+       if (!delegation_hashed(dp))
                return false;
 
        dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
@@ -4598,7 +4603,7 @@ static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb)
         * queued for a lease break. Don't queue it again.
         */
        spin_lock(&state_lock);
-       if (dp->dl_time == 0) {
+       if (delegation_hashed(dp) && dp->dl_time == 0) {
                dp->dl_time = ktime_get_boottime_seconds();
                list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
        }
index af8531c..51a49e0 100644 (file)
@@ -1521,12 +1521,9 @@ static int __init init_nfsd(void)
        int retval;
        printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
-       retval = register_cld_notifier();
-       if (retval)
-               return retval;
        retval = nfsd4_init_slabs();
        if (retval)
-               goto out_unregister_notifier;
+               return retval;
        retval = nfsd4_init_pnfs();
        if (retval)
                goto out_free_slabs;
@@ -1545,9 +1542,14 @@ static int __init init_nfsd(void)
                goto out_free_exports;
        retval = register_pernet_subsys(&nfsd_net_ops);
        if (retval < 0)
+               goto out_free_filesystem;
+       retval = register_cld_notifier();
+       if (retval)
                goto out_free_all;
        return 0;
 out_free_all:
+       unregister_pernet_subsys(&nfsd_net_ops);
+out_free_filesystem:
        unregister_filesystem(&nfsd_fs_type);
 out_free_exports:
        remove_proc_entry("fs/nfs/exports", NULL);
@@ -1561,13 +1563,12 @@ out_free_pnfs:
        nfsd4_exit_pnfs();
 out_free_slabs:
        nfsd4_free_slabs();
-out_unregister_notifier:
-       unregister_cld_notifier();
        return retval;
 }
 
 static void __exit exit_nfsd(void)
 {
+       unregister_cld_notifier();
        unregister_pernet_subsys(&nfsd_net_ops);
        nfsd_drc_slab_free();
        remove_proc_entry("fs/nfs/exports", NULL);
@@ -1577,7 +1578,6 @@ static void __exit exit_nfsd(void)
        nfsd4_free_slabs();
        nfsd4_exit_pnfs();
        unregister_filesystem(&nfsd_fs_type);
-       unregister_cld_notifier();
 }
 
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
index 040e1cf..65ce0e7 100644 (file)
 
 void signalfd_cleanup(struct sighand_struct *sighand)
 {
-       wait_queue_head_t *wqh = &sighand->signalfd_wqh;
-       /*
-        * The lockless check can race with remove_wait_queue() in progress,
-        * but in this case its caller should run under rcu_read_lock() and
-        * sighand_cachep is SLAB_TYPESAFE_BY_RCU, we can safely return.
-        */
-       if (likely(!waitqueue_active(wqh)))
-               return;
-
-       /* wait_queue_entry_t->func(POLLFREE) should do remove_wait_queue() */
-       wake_up_poll(wqh, EPOLLHUP | POLLFREE);
+       wake_up_pollfree(&sighand->signalfd_wqh);
 }
 
 struct signalfd_ctx {
index 85ba15a..043e4cb 100644 (file)
@@ -72,16 +72,3 @@ void cifs_arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in, unsigned int l
        ctx->y = y;
 }
 EXPORT_SYMBOL_GPL(cifs_arc4_crypt);
-
-static int __init
-init_smbfs_common(void)
-{
-       return 0;
-}
-static void __init
-exit_smbfs_common(void)
-{
-}
-
-module_init(init_smbfs_common)
-module_exit(exit_smbfs_common)
index 925a621..3616839 100644 (file)
@@ -161,6 +161,77 @@ struct tracefs_fs_info {
        struct tracefs_mount_opts mount_opts;
 };
 
+static void change_gid(struct dentry *dentry, kgid_t gid)
+{
+       if (!dentry->d_inode)
+               return;
+       dentry->d_inode->i_gid = gid;
+}
+
+/*
+ * Taken from d_walk, but without he need for handling renames.
+ * Nothing can be renamed while walking the list, as tracefs
+ * does not support renames. This is only called when mounting
+ * or remounting the file system, to set all the files to
+ * the given gid.
+ */
+static void set_gid(struct dentry *parent, kgid_t gid)
+{
+       struct dentry *this_parent;
+       struct list_head *next;
+
+       this_parent = parent;
+       spin_lock(&this_parent->d_lock);
+
+       change_gid(this_parent, gid);
+repeat:
+       next = this_parent->d_subdirs.next;
+resume:
+       while (next != &this_parent->d_subdirs) {
+               struct list_head *tmp = next;
+               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+               next = tmp->next;
+
+               spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+
+               change_gid(dentry, gid);
+
+               if (!list_empty(&dentry->d_subdirs)) {
+                       spin_unlock(&this_parent->d_lock);
+                       spin_release(&dentry->d_lock.dep_map, _RET_IP_);
+                       this_parent = dentry;
+                       spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
+                       goto repeat;
+               }
+               spin_unlock(&dentry->d_lock);
+       }
+       /*
+        * All done at this level ... ascend and resume the search.
+        */
+       rcu_read_lock();
+ascend:
+       if (this_parent != parent) {
+               struct dentry *child = this_parent;
+               this_parent = child->d_parent;
+
+               spin_unlock(&child->d_lock);
+               spin_lock(&this_parent->d_lock);
+
+               /* go into the first sibling still alive */
+               do {
+                       next = child->d_child.next;
+                       if (next == &this_parent->d_subdirs)
+                               goto ascend;
+                       child = list_entry(next, struct dentry, d_child);
+               } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED));
+               rcu_read_unlock();
+               goto resume;
+       }
+       rcu_read_unlock();
+       spin_unlock(&this_parent->d_lock);
+       return;
+}
+
 static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
 {
        substring_t args[MAX_OPT_ARGS];
@@ -193,6 +264,7 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
                        if (!gid_valid(gid))
                                return -EINVAL;
                        opts->gid = gid;
+                       set_gid(tracefs_mount->mnt_root, gid);
                        break;
                case Opt_mode:
                        if (match_octal(&args[0], &option))
@@ -414,6 +486,8 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
        inode->i_mode = mode;
        inode->i_fop = fops ? fops : &tracefs_file_operations;
        inode->i_private = data;
+       inode->i_uid = d_inode(dentry->d_parent)->i_uid;
+       inode->i_gid = d_inode(dentry->d_parent)->i_gid;
        d_instantiate(dentry, inode);
        fsnotify_create(dentry->d_parent->d_inode, dentry);
        return end_creating(dentry);
@@ -436,6 +510,8 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent,
        inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;
        inode->i_op = ops;
        inode->i_fop = &simple_dir_operations;
+       inode->i_uid = d_inode(dentry->d_parent)->i_uid;
+       inode->i_gid = d_inode(dentry->d_parent)->i_gid;
 
        /* directory inodes start off with i_nlink == 2 (for "." entry) */
        inc_nlink(inode);
index e21459f..778b57b 100644 (file)
@@ -1765,7 +1765,10 @@ static int
 xfs_remount_ro(
        struct xfs_mount        *mp)
 {
-       int error;
+       struct xfs_icwalk       icw = {
+               .icw_flags      = XFS_ICWALK_FLAG_SYNC,
+       };
+       int                     error;
 
        /*
         * Cancel background eofb scanning so it cannot race with the final
@@ -1773,8 +1776,13 @@ xfs_remount_ro(
         */
        xfs_blockgc_stop(mp);
 
-       /* Get rid of any leftover CoW reservations... */
-       error = xfs_blockgc_free_space(mp, NULL);
+       /*
+        * Clear out all remaining COW staging extents and speculative post-EOF
+        * preallocations so that we don't leave inodes requiring inactivation
+        * cleanups during reclaim on a read-only mount.  We must process every
+        * cached inode, so this requires a synchronous cache scan.
+        */
+       error = xfs_blockgc_free_space(mp, &icw);
        if (error) {
                xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
                return error;
index 259ee2b..b76dfb3 100644 (file)
@@ -1787,5 +1787,6 @@ static void __exit zonefs_exit(void)
 MODULE_AUTHOR("Damien Le Moal");
 MODULE_DESCRIPTION("Zone file system for zoned block devices");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_FS("zonefs");
 module_init(zonefs_init);
 module_exit(zonefs_exit);
index 2bc8b1f..cc35d01 100644 (file)
@@ -30,7 +30,7 @@ void put_page_bootmem(struct page *page);
  */
 static inline void free_bootmem_page(struct page *page)
 {
-       unsigned long magic = (unsigned long)page->freelist;
+       unsigned long magic = page->index;
 
        /*
         * The reserve_bootmem_region sets the reserved flag on bootmem
index e7a163a..755f38e 100644 (file)
@@ -732,6 +732,7 @@ int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr)
 struct bpf_trampoline *bpf_trampoline_get(u64 key,
                                          struct bpf_attach_target_info *tgt_info);
 void bpf_trampoline_put(struct bpf_trampoline *tr);
+int arch_prepare_bpf_dispatcher(void *image, s64 *funcs, int num_funcs);
 #define BPF_DISPATCHER_INIT(_name) {                           \
        .mutex = __MUTEX_INITIALIZER(_name.mutex),              \
        .func = &_name##_func,                                  \
@@ -1352,28 +1353,16 @@ extern struct mutex bpf_stats_enabled_mutex;
  * kprobes, tracepoints) to prevent deadlocks on map operations as any of
  * these events can happen inside a region which holds a map bucket lock
  * and can deadlock on it.
- *
- * Use the preemption safe inc/dec variants on RT because migrate disable
- * is preemptible on RT and preemption in the middle of the RMW operation
- * might lead to inconsistent state. Use the raw variants for non RT
- * kernels as migrate_disable() maps to preempt_disable() so the slightly
- * more expensive save operation can be avoided.
  */
 static inline void bpf_disable_instrumentation(void)
 {
        migrate_disable();
-       if (IS_ENABLED(CONFIG_PREEMPT_RT))
-               this_cpu_inc(bpf_prog_active);
-       else
-               __this_cpu_inc(bpf_prog_active);
+       this_cpu_inc(bpf_prog_active);
 }
 
 static inline void bpf_enable_instrumentation(void)
 {
-       if (IS_ENABLED(CONFIG_PREEMPT_RT))
-               this_cpu_dec(bpf_prog_active);
-       else
-               __this_cpu_dec(bpf_prog_active);
+       this_cpu_dec(bpf_prog_active);
        migrate_enable();
 }
 
index 203eef9..0e1b628 100644 (file)
@@ -245,7 +245,10 @@ struct kfunc_btf_id_set {
        struct module *owner;
 };
 
-struct kfunc_btf_id_list;
+struct kfunc_btf_id_list {
+       struct list_head list;
+       struct mutex mutex;
+};
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 void register_kfunc_btf_id_set(struct kfunc_btf_id_list *l,
@@ -254,6 +257,9 @@ void unregister_kfunc_btf_id_set(struct kfunc_btf_id_list *l,
                                 struct kfunc_btf_id_set *s);
 bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist, u32 kfunc_id,
                              struct module *owner);
+
+extern struct kfunc_btf_id_list bpf_tcp_ca_kfunc_list;
+extern struct kfunc_btf_id_list prog_test_kfunc_list;
 #else
 static inline void register_kfunc_btf_id_set(struct kfunc_btf_id_list *l,
                                             struct kfunc_btf_id_set *s)
@@ -268,13 +274,13 @@ static inline bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist,
 {
        return false;
 }
+
+static struct kfunc_btf_id_list bpf_tcp_ca_kfunc_list __maybe_unused;
+static struct kfunc_btf_id_list prog_test_kfunc_list __maybe_unused;
 #endif
 
 #define DEFINE_KFUNC_BTF_ID_SET(set, name)                                     \
        struct kfunc_btf_id_set name = { LIST_HEAD_INIT(name.list), (set),     \
                                         THIS_MODULE }
 
-extern struct kfunc_btf_id_list bpf_tcp_ca_kfunc_list;
-extern struct kfunc_btf_id_list prog_test_kfunc_list;
-
 #endif
index 2f909ed..4ff37cb 100644 (file)
@@ -3,7 +3,6 @@
 #define _LINUX_CACHEINFO_H
 
 #include <linux/bitops.h>
-#include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 
index 8eacf67..039e7e0 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/math.h>
+#include <linux/sched.h>
 
 extern unsigned long loops_per_jiffy;
 
@@ -58,7 +59,18 @@ void calibrate_delay(void);
 void __attribute__((weak)) calibration_delay_done(void);
 void msleep(unsigned int msecs);
 unsigned long msleep_interruptible(unsigned int msecs);
-void usleep_range(unsigned long min, unsigned long max);
+void usleep_range_state(unsigned long min, unsigned long max,
+                       unsigned int state);
+
+static inline void usleep_range(unsigned long min, unsigned long max)
+{
+       usleep_range_state(min, max, TASK_UNINTERRUPTIBLE);
+}
+
+static inline void usleep_idle_range(unsigned long min, unsigned long max)
+{
+       usleep_range_state(min, max, TASK_IDLE);
+}
 
 static inline void ssleep(unsigned int seconds)
 {
index a498ebc..15e7c5e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/klist.h>
 #include <linux/pm.h>
 #include <linux/device/bus.h>
+#include <linux/module.h>
 
 /**
  * enum probe_type - device driver probe type to try
index 24b7ed2..7f1e88e 100644 (file)
@@ -6,6 +6,7 @@
 #define __LINUX_FILTER_H__
 
 #include <linux/atomic.h>
+#include <linux/bpf.h>
 #include <linux/refcount.h>
 #include <linux/compat.h>
 #include <linux/skbuff.h>
@@ -26,7 +27,6 @@
 
 #include <asm/byteorder.h>
 #include <uapi/linux/filter.h>
-#include <uapi/linux/bpf.h>
 
 struct sk_buff;
 struct sock;
@@ -640,9 +640,6 @@ static __always_inline u32 bpf_prog_run(const struct bpf_prog *prog, const void
  * This uses migrate_disable/enable() explicitly to document that the
  * invocation of a BPF program does not require reentrancy protection
  * against a BPF program which is invoked from a preempting task.
- *
- * For non RT enabled kernels migrate_disable/enable() maps to
- * preempt_disable/enable(), i.e. it disables also preemption.
  */
 static inline u32 bpf_prog_run_pin_on_cpu(const struct bpf_prog *prog,
                                          const void *ctx)
index 9e067f9..f453be3 100644 (file)
@@ -840,6 +840,11 @@ static inline bool hid_is_using_ll_driver(struct hid_device *hdev,
        return hdev->ll_driver == driver;
 }
 
+static inline bool hid_is_usb(struct hid_device *hdev)
+{
+       return hid_is_using_ll_driver(hdev, &usb_hid_driver);
+}
+
 #define        PM_HINT_FULLON  1<<5
 #define PM_HINT_NORMAL 1<<1
 
index d8783b6..fb78108 100644 (file)
@@ -9,6 +9,7 @@
 
 struct kmem_cache;
 struct page;
+struct slab;
 struct vm_struct;
 struct task_struct;
 
@@ -193,11 +194,11 @@ static __always_inline size_t kasan_metadata_size(struct kmem_cache *cache)
        return 0;
 }
 
-void __kasan_poison_slab(struct page *page);
-static __always_inline void kasan_poison_slab(struct page *page)
+void __kasan_poison_slab(struct slab *slab);
+static __always_inline void kasan_poison_slab(struct slab *slab)
 {
        if (kasan_enabled())
-               __kasan_poison_slab(page);
+               __kasan_poison_slab(slab);
 }
 
 void __kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
@@ -322,7 +323,7 @@ static inline void kasan_cache_create(struct kmem_cache *cache,
                                      slab_flags_t *flags) {}
 static inline void kasan_cache_create_kmalloc(struct kmem_cache *cache) {}
 static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; }
-static inline void kasan_poison_slab(struct page *page) {}
+static inline void kasan_poison_slab(struct slab *slab) {}
 static inline void kasan_unpoison_object_data(struct kmem_cache *cache,
                                        void *object) {}
 static inline void kasan_poison_object_data(struct kmem_cache *cache,
index 0c5c403..e34112f 100644 (file)
@@ -536,45 +536,6 @@ static inline bool folio_memcg_kmem(struct folio *folio)
        return folio->memcg_data & MEMCG_DATA_KMEM;
 }
 
-/*
- * page_objcgs - get the object cgroups vector associated with a page
- * @page: a pointer to the page struct
- *
- * Returns a pointer to the object cgroups vector associated with the page,
- * or NULL. This function assumes that the page is known to have an
- * associated object cgroups vector. It's not safe to call this function
- * against pages, which might have an associated memory cgroup: e.g.
- * kernel stack pages.
- */
-static inline struct obj_cgroup **page_objcgs(struct page *page)
-{
-       unsigned long memcg_data = READ_ONCE(page->memcg_data);
-
-       VM_BUG_ON_PAGE(memcg_data && !(memcg_data & MEMCG_DATA_OBJCGS), page);
-       VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
-
-       return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
-}
-
-/*
- * page_objcgs_check - get the object cgroups vector associated with a page
- * @page: a pointer to the page struct
- *
- * Returns a pointer to the object cgroups vector associated with the page,
- * or NULL. This function is safe to use if the page can be directly associated
- * with a memory cgroup.
- */
-static inline struct obj_cgroup **page_objcgs_check(struct page *page)
-{
-       unsigned long memcg_data = READ_ONCE(page->memcg_data);
-
-       if (!memcg_data || !(memcg_data & MEMCG_DATA_OBJCGS))
-               return NULL;
-
-       VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
-
-       return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
-}
 
 #else
 static inline bool folio_memcg_kmem(struct folio *folio)
@@ -582,15 +543,6 @@ static inline bool folio_memcg_kmem(struct folio *folio)
        return false;
 }
 
-static inline struct obj_cgroup **page_objcgs(struct page *page)
-{
-       return NULL;
-}
-
-static inline struct obj_cgroup **page_objcgs_check(struct page *page)
-{
-       return NULL;
-}
 #endif
 
 static inline bool PageMemcgKmem(struct page *page)
index 7239858..a5cc4cd 100644 (file)
@@ -664,6 +664,19 @@ int mhi_pm_suspend(struct mhi_controller *mhi_cntrl);
 int mhi_pm_resume(struct mhi_controller *mhi_cntrl);
 
 /**
+ * mhi_pm_resume_force - Force resume MHI from suspended state
+ * @mhi_cntrl: MHI controller
+ *
+ * Resume the device irrespective of its MHI state. As per the MHI spec, devices
+ * has to be in M3 state during resume. But some devices seem to be in a
+ * different MHI state other than M3 but they continue working fine if allowed.
+ * This API is intented to be used for such devices.
+ *
+ * Return: 0 if the resume succeeds, a negative error code otherwise
+ */
+int mhi_pm_resume_force(struct mhi_controller *mhi_cntrl);
+
+/**
  * mhi_download_rddm_image - Download ramdump image from device for
  *                           debugging purpose.
  * @mhi_cntrl: MHI controller
index a7e4a9e..4a6cf22 100644 (file)
@@ -863,6 +863,13 @@ static inline struct page *virt_to_head_page(const void *x)
        return compound_head(page);
 }
 
+static inline struct folio *virt_to_folio(const void *x)
+{
+       struct page *page = virt_to_page(x);
+
+       return page_folio(page);
+}
+
 void __put_page(struct page *page);
 
 void put_pages_list(struct list_head *pages);
@@ -1753,6 +1760,11 @@ void page_address_init(void);
 #define page_address_init()  do { } while(0)
 #endif
 
+static inline void *folio_address(const struct folio *folio)
+{
+       return page_address(&folio->page);
+}
+
 extern void *page_rmapping(struct page *page);
 extern struct anon_vma *page_anon_vma(struct page *page);
 extern pgoff_t __page_file_index(struct page *page);
index c3a6e62..1ae3537 100644 (file)
@@ -56,11 +56,11 @@ struct mem_cgroup;
  * in each subpage, but you may need to restore some of their values
  * afterwards.
  *
- * SLUB uses cmpxchg_double() to atomically update its freelist and
- * counters.  That requires that freelist & counters be adjacent and
- * double-word aligned.  We align all struct pages to double-word
- * boundaries, and ensure that 'freelist' is aligned within the
- * struct.
+ * SLUB uses cmpxchg_double() to atomically update its freelist and counters.
+ * That requires that freelist & counters in struct slab be adjacent and
+ * double-word aligned. Because struct slab currently just reinterprets the
+ * bits of struct page, we align all struct pages to double-word boundaries,
+ * and ensure that 'freelist' is aligned within struct slab.
  */
 #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
 #define _struct_page_alignment __aligned(2 * sizeof(unsigned long))
index b31d3f3..d73a1c0 100644 (file)
@@ -51,9 +51,9 @@
 #define _LINUX_PERCPU_REFCOUNT_H
 
 #include <linux/atomic.h>
-#include <linux/kernel.h>
 #include <linux/percpu.h>
 #include <linux/rcupdate.h>
+#include <linux/types.h>
 #include <linux/gfp.h>
 
 struct percpu_ref;
index 96e43fb..cbf03a5 100644 (file)
@@ -538,11 +538,12 @@ struct macsec_ops;
  * @mac_managed_pm: Set true if MAC driver takes of suspending/resuming PHY
  * @state: State of the PHY for management purposes
  * @dev_flags: Device-specific flags used by the PHY driver.
- *             Bits [15:0] are free to use by the PHY driver to communicate
- *                         driver specific behavior.
- *             Bits [23:16] are currently reserved for future use.
- *             Bits [31:24] are reserved for defining generic
- *                          PHY driver behavior.
+ *
+ *      - Bits [15:0] are free to use by the PHY driver to communicate
+ *        driver specific behavior.
+ *      - Bits [23:16] are currently reserved for future use.
+ *      - Bits [31:24] are reserved for defining generic
+ *        PHY driver behavior.
  * @irq: IRQ number of the PHY's interrupt (-1 if none)
  * @phy_timer: The timer for handling the state machine
  * @phylink: Pointer to phylink instance for this PHY
index 222da43..eddd66d 100644 (file)
@@ -129,7 +129,7 @@ static inline bool pm_runtime_suspended(struct device *dev)
  * pm_runtime_active - Check whether or not a device is runtime-active.
  * @dev: Target device.
  *
- * Return %true if runtime PM is enabled for @dev and its runtime PM status is
+ * Return %true if runtime PM is disabled for @dev or its runtime PM status is
  * %RPM_ACTIVE, or %false otherwise.
  *
  * Note that the return value of this function can only be trusted if it is
index bd7a73d..54cf566 100644 (file)
@@ -499,7 +499,8 @@ struct regulator_irq_data {
  *             best to shut-down regulator(s) or reboot the SOC if error
  *             handling is repeatedly failing. If fatal_cnt is given the IRQ
  *             handling is aborted if it fails for fatal_cnt times and die()
- *             callback (if populated) or BUG() is called to try to prevent
+ *             callback (if populated) is called. If die() is not populated
+ *             poweroff for the system is attempted in order to prevent any
  *             further damage.
  * @reread_ms: The time which is waited before attempting to re-read status
  *             at the worker if IC reading fails. Immediate re-read is done
@@ -516,11 +517,12 @@ struct regulator_irq_data {
  * @data:      Driver private data pointer which will be passed as such to
  *             the renable, map_event and die callbacks in regulator_irq_data.
  * @die:       Protection callback. If IC status reading or recovery actions
- *             fail fatal_cnt times this callback or BUG() is called. This
- *             callback should implement a final protection attempt like
- *             disabling the regulator. If protection succeeded this may
- *             return 0. If anything else is returned the core assumes final
- *             protection failed and calls BUG() as a last resort.
+ *             fail fatal_cnt times this callback is called or system is
+ *             powered off. This callback should implement a final protection
+ *             attempt like disabling the regulator. If protection succeeded
+ *             die() may return 0. If anything else is returned the core
+ *             assumes final protection failed and attempts to perform a
+ *             poweroff as a last resort.
  * @map_event: Driver callback to map IRQ status into regulator devices with
  *             events / errors. NOTE: callback MUST initialize both the
  *             errors and notifs for all rdevs which it signals having
index 1810451..367366f 100644 (file)
@@ -189,14 +189,6 @@ bool kmem_valid_obj(void *object);
 void kmem_dump_obj(void *object);
 #endif
 
-#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR
-void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
-                       bool to_user);
-#else
-static inline void __check_heap_object(const void *ptr, unsigned long n,
-                                      struct page *page, bool to_user) { }
-#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 3aa5e1e..e24c9af 100644 (file)
@@ -87,11 +87,11 @@ struct kmem_cache {
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
 
-static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
+static inline void *nearest_obj(struct kmem_cache *cache, const struct slab *slab,
                                void *x)
 {
-       void *object = x - (x - page->s_mem) % cache->size;
-       void *last_object = page->s_mem + (cache->num - 1) * cache->size;
+       void *object = x - (x - slab->s_mem) % cache->size;
+       void *last_object = slab->s_mem + (cache->num - 1) * cache->size;
 
        if (unlikely(object > last_object))
                return last_object;
@@ -106,16 +106,16 @@ static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
  *   reciprocal_divide(offset, cache->reciprocal_buffer_size)
  */
 static inline unsigned int obj_to_index(const struct kmem_cache *cache,
-                                       const struct page *page, void *obj)
+                                       const struct slab *slab, void *obj)
 {
-       u32 offset = (obj - page->s_mem);
+       u32 offset = (obj - slab->s_mem);
        return reciprocal_divide(offset, cache->reciprocal_buffer_size);
 }
 
-static inline int objs_per_slab_page(const struct kmem_cache *cache,
-                                    const struct page *page)
+static inline int objs_per_slab(const struct kmem_cache *cache,
+                                    const struct slab *slab)
 {
-       if (is_kfence_address(page_address(page)))
+       if (is_kfence_address(slab_address(slab)))
                return 1;
        return cache->num;
 }
index 0fa751b..33c5c0e 100644 (file)
@@ -48,9 +48,9 @@ enum stat_item {
 struct kmem_cache_cpu {
        void **freelist;        /* Pointer to next available object */
        unsigned long tid;      /* Globally unique transaction id */
-       struct page *page;      /* The slab from which we are allocating */
+       struct slab *slab;      /* The slab from which we are allocating */
 #ifdef CONFIG_SLUB_CPU_PARTIAL
-       struct page *partial;   /* Partially allocated frozen slabs */
+       struct slab *partial;   /* Partially allocated frozen slabs */
 #endif
        local_lock_t lock;      /* Protects the fields above */
 #ifdef CONFIG_SLUB_STATS
@@ -99,8 +99,8 @@ struct kmem_cache {
 #ifdef CONFIG_SLUB_CPU_PARTIAL
        /* Number of per cpu partial objects to keep around */
        unsigned int cpu_partial;
-       /* Number of per cpu partial pages to keep around */
-       unsigned int cpu_partial_pages;
+       /* Number of per cpu partial slabs to keep around */
+       unsigned int cpu_partial_slabs;
 #endif
        struct kmem_cache_order_objects oo;
 
@@ -156,16 +156,13 @@ static inline void sysfs_slab_release(struct kmem_cache *s)
 }
 #endif
 
-void object_err(struct kmem_cache *s, struct page *page,
-               u8 *object, char *reason);
-
 void *fixup_red_left(struct kmem_cache *s, void *p);
 
-static inline void *nearest_obj(struct kmem_cache *cache, struct page *page,
+static inline void *nearest_obj(struct kmem_cache *cache, const struct slab *slab,
                                void *x) {
-       void *object = x - (x - page_address(page)) % cache->size;
-       void *last_object = page_address(page) +
-               (page->objects - 1) * cache->size;
+       void *object = x - (x - slab_address(slab)) % cache->size;
+       void *last_object = slab_address(slab) +
+               (slab->objects - 1) * cache->size;
        void *result = (unlikely(object > last_object)) ? last_object : object;
 
        result = fixup_red_left(cache, result);
@@ -181,16 +178,16 @@ static inline unsigned int __obj_to_index(const struct kmem_cache *cache,
 }
 
 static inline unsigned int obj_to_index(const struct kmem_cache *cache,
-                                       const struct page *page, void *obj)
+                                       const struct slab *slab, void *obj)
 {
        if (is_kfence_address(obj))
                return 0;
-       return __obj_to_index(cache, page_address(page), obj);
+       return __obj_to_index(cache, slab_address(slab), obj);
 }
 
-static inline int objs_per_slab_page(const struct kmem_cache *cache,
-                                    const struct page *page)
+static inline int objs_per_slab(const struct kmem_cache *cache,
+                                    const struct slab *slab)
 {
-       return page->objects;
+       return slab->objects;
 }
 #endif /* _LINUX_SLUB_DEF_H */
index 2d0df57..851e07d 100644 (file)
@@ -217,6 +217,7 @@ void __wake_up_sync_key(struct wait_queue_head *wq_head, unsigned int mode, void
 void __wake_up_locked_sync_key(struct wait_queue_head *wq_head, unsigned int mode, void *key);
 void __wake_up_locked(struct wait_queue_head *wq_head, unsigned int mode, int nr);
 void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode);
+void __wake_up_pollfree(struct wait_queue_head *wq_head);
 
 #define wake_up(x)                     __wake_up(x, TASK_NORMAL, 1, NULL)
 #define wake_up_nr(x, nr)              __wake_up(x, TASK_NORMAL, nr, NULL)
@@ -245,6 +246,31 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode);
 #define wake_up_interruptible_sync_poll_locked(x, m)                           \
        __wake_up_locked_sync_key((x), TASK_INTERRUPTIBLE, poll_to_key(m))
 
+/**
+ * wake_up_pollfree - signal that a polled waitqueue is going away
+ * @wq_head: the wait queue head
+ *
+ * In the very rare cases where a ->poll() implementation uses a waitqueue whose
+ * lifetime is tied to a task rather than to the 'struct file' being polled,
+ * this function must be called before the waitqueue is freed so that
+ * non-blocking polls (e.g. epoll) are notified that the queue is going away.
+ *
+ * The caller must also RCU-delay the freeing of the wait_queue_head, e.g. via
+ * an explicit synchronize_rcu() or call_rcu(), or via SLAB_TYPESAFE_BY_RCU.
+ */
+static inline void wake_up_pollfree(struct wait_queue_head *wq_head)
+{
+       /*
+        * For performance reasons, we don't always take the queue lock here.
+        * Therefore, we might race with someone removing the last entry from
+        * the queue, and proceed while they still hold the queue lock.
+        * However, rcu_read_lock() is required to be held in such cases, so we
+        * can safely proceed with an RCU-delayed free.
+        */
+       if (waitqueue_active(wq_head))
+               __wake_up_pollfree(wq_head);
+}
+
 #define ___wait_cond_timeout(condition)                                                \
 ({                                                                             \
        bool __cond = (condition);                                              \
index f6af76c..191c36a 100644 (file)
@@ -126,7 +126,7 @@ struct tlb_slave_info {
 struct alb_bond_info {
        struct tlb_client_info  *tx_hashtbl; /* Dynamically allocated */
        u32                     unbalanced_load;
-       int                     tx_rebalance_counter;
+       atomic_t                tx_rebalance_counter;
        int                     lp_counter;
        /* -------- rlb parameters -------- */
        int rlb_enabled;
index 7994455..c4898fc 100644 (file)
@@ -136,6 +136,19 @@ static inline void sk_mark_napi_id(struct sock *sk, const struct sk_buff *skb)
        sk_rx_queue_update(sk, skb);
 }
 
+/* Variant of sk_mark_napi_id() for passive flow setup,
+ * as sk->sk_napi_id and sk->sk_rx_queue_mapping content
+ * needs to be set.
+ */
+static inline void sk_mark_napi_id_set(struct sock *sk,
+                                      const struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_RX_BUSY_POLL
+       WRITE_ONCE(sk->sk_napi_id, skb->napi_id);
+#endif
+       sk_rx_queue_set(sk, skb);
+}
+
 static inline void __sk_mark_napi_id_once(struct sock *sk, unsigned int napi_id)
 {
 #ifdef CONFIG_NET_RX_BUSY_POLL
index cc663c6..d24b0a3 100644 (file)
@@ -276,14 +276,14 @@ static inline bool nf_is_loopback_packet(const struct sk_buff *skb)
 /* jiffies until ct expires, 0 if already expired */
 static inline unsigned long nf_ct_expires(const struct nf_conn *ct)
 {
-       s32 timeout = ct->timeout - nfct_time_stamp;
+       s32 timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
 
        return timeout > 0 ? timeout : 0;
 }
 
 static inline bool nf_ct_is_expired(const struct nf_conn *ct)
 {
-       return (__s32)(ct->timeout - nfct_time_stamp) <= 0;
+       return (__s32)(READ_ONCE(ct->timeout) - nfct_time_stamp) <= 0;
 }
 
 /* use after obtaining a reference count */
@@ -302,7 +302,7 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
 static inline void nf_ct_offload_timeout(struct nf_conn *ct)
 {
        if (nf_ct_expires(ct) < NF_CT_DAY / 2)
-               ct->timeout = nfct_time_stamp + NF_CT_DAY;
+               WRITE_ONCE(ct->timeout, nfct_time_stamp + NF_CT_DAY);
 }
 
 struct kernel_param;
index 41b509f..f9c520c 100644 (file)
@@ -29,7 +29,7 @@
 #define POLLRDHUP       0x2000
 #endif
 
-#define POLLFREE       (__force __poll_t)0x4000        /* currently only for epoll */
+#define POLLFREE       (__force __poll_t)0x4000
 
 #define POLL_BUSY_LOOP (__force __poll_t)0x8000
 
index c8cc46f..f106a39 100644 (file)
@@ -136,19 +136,21 @@ struct mptcp_info {
  * MPTCP_EVENT_REMOVED: token, rem_id
  * An address has been lost by the peer.
  *
- * MPTCP_EVENT_SUB_ESTABLISHED: token, family, saddr4 | saddr6,
- *                              daddr4 | daddr6, sport, dport, backup,
- *                              if_idx [, error]
+ * MPTCP_EVENT_SUB_ESTABLISHED: token, family, loc_id, rem_id,
+ *                              saddr4 | saddr6, daddr4 | daddr6, sport,
+ *                              dport, backup, if_idx [, error]
  * A new subflow has been established. 'error' should not be set.
  *
- * MPTCP_EVENT_SUB_CLOSED: token, family, saddr4 | saddr6, daddr4 | daddr6,
- *                         sport, dport, backup, if_idx [, error]
+ * MPTCP_EVENT_SUB_CLOSED: token, family, loc_id, rem_id, saddr4 | saddr6,
+ *                         daddr4 | daddr6, sport, dport, backup, if_idx
+ *                         [, error]
  * A subflow has been closed. An error (copy of sk_err) could be set if an
  * error has been detected for this subflow.
  *
- * MPTCP_EVENT_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6,
- *                           sport, dport, backup, if_idx [, error]
- *       The priority of a subflow has changed. 'error' should not be set.
+ * MPTCP_EVENT_SUB_PRIORITY: token, family, loc_id, rem_id, saddr4 | saddr6,
+ *                           daddr4 | daddr6, sport, dport, backup, if_idx
+ *                           [, error]
+ * The priority of a subflow has changed. 'error' should not be set.
  */
 enum mptcp_event_type {
        MPTCP_EVENT_UNSPEC = 0,
index 74ef57b..ac5d6a3 100644 (file)
@@ -66,10 +66,17 @@ struct rlimit64 {
 #define _STK_LIM       (8*1024*1024)
 
 /*
- * GPG2 wants 64kB of mlocked memory, to make sure pass phrases
- * and other sensitive information are never written to disk.
+ * Limit the amount of locked memory by some sane default:
+ * root can always increase this limit if needed.
+ *
+ * The main use-cases are (1) preventing sensitive memory
+ * from being swapped; (2) real-time operations; (3) via
+ * IOURING_REGISTER_BUFFERS.
+ *
+ * The first two don't need much. The latter will take as
+ * much as it can get. 8MB is a reasonably sane default.
  */
-#define MLOCK_LIMIT    ((PAGE_SIZE > 64*1024) ? PAGE_SIZE : 64*1024)
+#define MLOCK_LIMIT    (8*1024*1024)
 
 /*
  * Due to binary compatibility, the actual resource numbers
index 121d37e..4cebadb 100644 (file)
@@ -718,7 +718,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
 {
        int rc = 0;
        struct sk_buff *skb;
-       static unsigned int failed = 0;
+       unsigned int failed = 0;
 
        /* NOTE: kauditd_thread takes care of all our locking, we just use
         *       the netlink info passed to us (e.g. sk and portid) */
@@ -735,32 +735,30 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                        continue;
                }
 
+retry:
                /* grab an extra skb reference in case of error */
                skb_get(skb);
                rc = netlink_unicast(sk, skb, portid, 0);
                if (rc < 0) {
-                       /* fatal failure for our queue flush attempt? */
+                       /* send failed - try a few times unless fatal error */
                        if (++failed >= retry_limit ||
                            rc == -ECONNREFUSED || rc == -EPERM) {
-                               /* yes - error processing for the queue */
                                sk = NULL;
                                if (err_hook)
                                        (*err_hook)(skb);
-                               if (!skb_hook)
-                                       goto out;
-                               /* keep processing with the skb_hook */
+                               if (rc == -EAGAIN)
+                                       rc = 0;
+                               /* continue to drain the queue */
                                continue;
                        } else
-                               /* no - requeue to preserve ordering */
-                               skb_queue_head(queue, skb);
+                               goto retry;
                } else {
-                       /* it worked - drop the extra reference and continue */
+                       /* skb sent - drop the extra reference and continue */
                        consume_skb(skb);
                        failed = 0;
                }
        }
 
-out:
        return (rc >= 0 ? 0 : rc);
 }
 
@@ -1609,7 +1607,8 @@ static int __net_init audit_net_init(struct net *net)
                audit_panic("cannot initialize netlink socket in namespace");
                return -ENOMEM;
        }
-       aunet->sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
+       /* limit the timeout in case auditd is blocked/stopped */
+       aunet->sk->sk_sndtimeo = HZ / 10;
 
        return 0;
 }
index dbc3ad0..9bdb037 100644 (file)
@@ -6346,11 +6346,6 @@ BTF_ID_LIST_GLOBAL_SINGLE(btf_task_struct_ids, struct, task_struct)
 
 /* BTF ID set registration API for modules */
 
-struct kfunc_btf_id_list {
-       struct list_head list;
-       struct mutex mutex;
-};
-
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 
 void register_kfunc_btf_id_set(struct kfunc_btf_id_list *l,
@@ -6376,8 +6371,6 @@ bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist, u32 kfunc_id,
 {
        struct kfunc_btf_id_set *s;
 
-       if (!owner)
-               return false;
        mutex_lock(&klist->mutex);
        list_for_each_entry(s, &klist->list, list) {
                if (s->owner == owner && btf_id_set_contains(s->set, kfunc_id)) {
@@ -6389,8 +6382,6 @@ bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist, u32 kfunc_id,
        return false;
 }
 
-#endif
-
 #define DEFINE_KFUNC_BTF_ID_LIST(name)                                         \
        struct kfunc_btf_id_list name = { LIST_HEAD_INIT(name.list),           \
                                          __MUTEX_INITIALIZER(name.mutex) };   \
@@ -6398,3 +6389,5 @@ bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist, u32 kfunc_id,
 
 DEFINE_KFUNC_BTF_ID_LIST(bpf_tcp_ca_kfunc_list);
 DEFINE_KFUNC_BTF_ID_LIST(prog_test_kfunc_list);
+
+#endif
index 50efda5..b532f10 100644 (file)
@@ -1366,22 +1366,28 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
        reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
 }
 
+static bool __reg32_bound_s64(s32 a)
+{
+       return a >= 0 && a <= S32_MAX;
+}
+
 static void __reg_assign_32_into_64(struct bpf_reg_state *reg)
 {
        reg->umin_value = reg->u32_min_value;
        reg->umax_value = reg->u32_max_value;
-       /* Attempt to pull 32-bit signed bounds into 64-bit bounds
-        * but must be positive otherwise set to worse case bounds
-        * and refine later from tnum.
+
+       /* Attempt to pull 32-bit signed bounds into 64-bit bounds but must
+        * be positive otherwise set to worse case bounds and refine later
+        * from tnum.
         */
-       if (reg->s32_min_value >= 0 && reg->s32_max_value >= 0)
-               reg->smax_value = reg->s32_max_value;
-       else
-               reg->smax_value = U32_MAX;
-       if (reg->s32_min_value >= 0)
+       if (__reg32_bound_s64(reg->s32_min_value) &&
+           __reg32_bound_s64(reg->s32_max_value)) {
                reg->smin_value = reg->s32_min_value;
-       else
+               reg->smax_value = reg->s32_max_value;
+       } else {
                reg->smin_value = 0;
+               reg->smax_value = U32_MAX;
+       }
 }
 
 static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
@@ -2379,8 +2385,6 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
                 */
                if (insn->src_reg != BPF_REG_FP)
                        return 0;
-               if (BPF_SIZE(insn->code) != BPF_DW)
-                       return 0;
 
                /* dreg = *(u64 *)[fp - off] was a fill from the stack.
                 * that [fp - off] slot contains scalar that needs to be
@@ -2403,8 +2407,6 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
                /* scalars can only be spilled into stack */
                if (insn->dst_reg != BPF_REG_FP)
                        return 0;
-               if (BPF_SIZE(insn->code) != BPF_DW)
-                       return 0;
                spi = (-insn->off - 1) / BPF_REG_SIZE;
                if (spi >= 64) {
                        verbose(env, "BUG spi %d\n", spi);
@@ -4551,9 +4553,16 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
 
        if (insn->imm == BPF_CMPXCHG) {
                /* Check comparison of R0 with memory location */
-               err = check_reg_arg(env, BPF_REG_0, SRC_OP);
+               const u32 aux_reg = BPF_REG_0;
+
+               err = check_reg_arg(env, aux_reg, SRC_OP);
                if (err)
                        return err;
+
+               if (is_pointer_value(env, aux_reg)) {
+                       verbose(env, "R%d leaks addr into mem\n", aux_reg);
+                       return -EACCES;
+               }
        }
 
        if (is_pointer_value(env, insn->src_reg)) {
@@ -4588,13 +4597,19 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
                load_reg = -1;
        }
 
-       /* check whether we can read the memory */
+       /* Check whether we can read the memory, with second call for fetch
+        * case to simulate the register fill.
+        */
        err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
-                              BPF_SIZE(insn->code), BPF_READ, load_reg, true);
+                              BPF_SIZE(insn->code), BPF_READ, -1, true);
+       if (!err && load_reg >= 0)
+               err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
+                                      BPF_SIZE(insn->code), BPF_READ, load_reg,
+                                      true);
        if (err)
                return err;
 
-       /* check whether we can write into the same memory */
+       /* Check whether we can write into the same memory. */
        err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                               BPF_SIZE(insn->code), BPF_WRITE, -1, true);
        if (err)
@@ -8308,6 +8323,10 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                                                         insn->dst_reg);
                                }
                                zext_32_to_64(dst_reg);
+
+                               __update_reg_bounds(dst_reg);
+                               __reg_deduce_bounds(dst_reg);
+                               __reg_bound_offset(dst_reg);
                        }
                } else {
                        /* case: R = imm
@@ -8422,7 +8441,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate,
 
        new_range = dst_reg->off;
        if (range_right_open)
-               new_range--;
+               new_range++;
 
        /* Examples for register markings:
         *
index 0c6a48d..1f25a4d 100644 (file)
@@ -1380,7 +1380,7 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
                 *  - the VCPU on which owner runs is preempted
                 */
                if (!owner->on_cpu || need_resched() ||
-                   rt_mutex_waiter_is_top_waiter(lock, waiter) ||
+                   !rt_mutex_waiter_is_top_waiter(lock, waiter) ||
                    vcpu_is_preempted(task_cpu(owner))) {
                        res = false;
                        break;
index 76577d1..eca3810 100644 (file)
@@ -238,6 +238,13 @@ void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode)
 }
 EXPORT_SYMBOL_GPL(__wake_up_sync);     /* For internal use only */
 
+void __wake_up_pollfree(struct wait_queue_head *wq_head)
+{
+       __wake_up(wq_head, TASK_NORMAL, 0, poll_to_key(EPOLLHUP | POLLFREE));
+       /* POLLFREE must have cleared the queue. */
+       WARN_ON_ONCE(waitqueue_active(wq_head));
+}
+
 /*
  * Note: we use "set_current_state()" _after_ the wait-queue add,
  * because we need a memory barrier there on SMP, so that any
index a629b11..dfcee38 100644 (file)
@@ -4185,6 +4185,15 @@ do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp,
                                ss_mode != 0))
                        return -EINVAL;
 
+               /*
+                * Return before taking any locks if no actual
+                * sigaltstack changes were requested.
+                */
+               if (t->sas_ss_sp == (unsigned long)ss_sp &&
+                   t->sas_ss_size == ss_size &&
+                   t->sas_ss_flags == ss_flags)
+                       return 0;
+
                sigaltstack_lock();
                if (ss_mode == SS_DISABLE) {
                        ss_size = 0;
index b348749..dcdcb85 100644 (file)
@@ -1306,8 +1306,7 @@ int do_settimeofday64(const struct timespec64 *ts)
        timekeeping_forward_now(tk);
 
        xt = tk_xtime(tk);
-       ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
-       ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
+       ts_delta = timespec64_sub(*ts, xt);
 
        if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
                ret = -EINVAL;
index e3d2c23..85f1021 100644 (file)
@@ -2054,26 +2054,28 @@ unsigned long msleep_interruptible(unsigned int msecs)
 EXPORT_SYMBOL(msleep_interruptible);
 
 /**
- * usleep_range - Sleep for an approximate time
- * @min: Minimum time in usecs to sleep
- * @max: Maximum time in usecs to sleep
+ * usleep_range_state - Sleep for an approximate time in a given state
+ * @min:       Minimum time in usecs to sleep
+ * @max:       Maximum time in usecs to sleep
+ * @state:     State of the current task that will be while sleeping
  *
  * In non-atomic context where the exact wakeup time is flexible, use
- * usleep_range() instead of udelay().  The sleep improves responsiveness
+ * usleep_range_state() instead of udelay().  The sleep improves responsiveness
  * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces
  * power usage by allowing hrtimers to take advantage of an already-
  * scheduled interrupt instead of scheduling a new one just for this sleep.
  */
-void __sched usleep_range(unsigned long min, unsigned long max)
+void __sched usleep_range_state(unsigned long min, unsigned long max,
+                               unsigned int state)
 {
        ktime_t exp = ktime_add_us(ktime_get(), min);
        u64 delta = (u64)(max - min) * NSEC_PER_USEC;
 
        for (;;) {
-               __set_current_state(TASK_UNINTERRUPTIBLE);
+               __set_current_state(state);
                /* Do not return before the requested sleep time has elapsed */
                if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS))
                        break;
        }
 }
-EXPORT_SYMBOL(usleep_range);
+EXPORT_SYMBOL(usleep_range_state);
index 30bc880..be5f6b3 100644 (file)
@@ -5217,6 +5217,7 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
 {
        struct ftrace_direct_func *direct;
        struct ftrace_func_entry *entry;
+       struct ftrace_hash *hash;
        int ret = -ENODEV;
 
        mutex_lock(&direct_mutex);
@@ -5225,7 +5226,8 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
        if (!entry)
                goto out_unlock;
 
-       if (direct_functions->count == 1)
+       hash = direct_ops.func_hash->filter_hash;
+       if (hash->count == 1)
                unregister_ftrace_function(&direct_ops);
 
        ret = ftrace_set_filter_ip(&direct_ops, ip, 1, 0);
@@ -5540,6 +5542,10 @@ int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr)
        err = unregister_ftrace_function(ops);
        remove_direct_functions_hash(hash, addr);
        mutex_unlock(&direct_mutex);
+
+       /* cleanup for possible another register call */
+       ops->func = NULL;
+       ops->trampoline = 0;
        return err;
 }
 EXPORT_SYMBOL_GPL(unregister_ftrace_direct_multi);
index 22db3ce..ca9c13b 100644 (file)
@@ -1237,9 +1237,8 @@ static int __create_synth_event(const char *name, const char *raw_fields)
                                                  argv + consumed, &consumed,
                                                  &field_version);
                        if (IS_ERR(field)) {
-                               argv_free(argv);
                                ret = PTR_ERR(field);
-                               goto err;
+                               goto err_free_arg;
                        }
 
                        /*
@@ -1262,18 +1261,19 @@ static int __create_synth_event(const char *name, const char *raw_fields)
                        if (cmd_version > 1 && n_fields_this_loop >= 1) {
                                synth_err(SYNTH_ERR_INVALID_CMD, errpos(field_str));
                                ret = -EINVAL;
-                               goto err;
+                               goto err_free_arg;
                        }
 
                        fields[n_fields++] = field;
                        if (n_fields == SYNTH_FIELDS_MAX) {
                                synth_err(SYNTH_ERR_TOO_MANY_FIELDS, 0);
                                ret = -EINVAL;
-                               goto err;
+                               goto err_free_arg;
                        }
 
                        n_fields_this_loop++;
                }
+               argv_free(argv);
 
                if (consumed < argc) {
                        synth_err(SYNTH_ERR_INVALID_CMD, 0);
@@ -1281,7 +1281,6 @@ static int __create_synth_event(const char *name, const char *raw_fields)
                        goto err;
                }
 
-               argv_free(argv);
        }
 
        if (n_fields == 0) {
@@ -1307,6 +1306,8 @@ static int __create_synth_event(const char *name, const char *raw_fields)
        kfree(saved_fields);
 
        return ret;
+ err_free_arg:
+       argv_free(argv);
  err:
        for (i = 0; i < n_fields; i++)
                free_synth_field(fields[i]);
index 5c12bde..5e14e32 100644 (file)
@@ -316,6 +316,7 @@ config DEBUG_INFO_BTF
        bool "Generate BTF typeinfo"
        depends on !DEBUG_INFO_SPLIT && !DEBUG_INFO_REDUCED
        depends on !GCC_PLUGIN_RANDSTRUCT || COMPILE_TEST
+       depends on BPF_SYSCALL
        help
          Generate deduplicated BTF type information from DWARF debug info.
          Turning this on expects presence of pahole tool, which will convert
index 28edafc..356f4f2 100644 (file)
@@ -428,7 +428,7 @@ config THP_SWAP
 # UP and nommu archs use km based percpu allocator
 #
 config NEED_PER_CPU_KM
-       depends on !SMP
+       depends on !SMP || !MMU
        bool
        default y
 
index 1eead47..eae96df 100644 (file)
@@ -945,6 +945,13 @@ void bdi_unregister(struct backing_dev_info *bdi)
        wb_shutdown(&bdi->wb);
        cgwb_bdi_unregister(bdi);
 
+       /*
+        * If this BDI's min ratio has been set, use bdi_set_min_ratio() to
+        * update the global bdi_min_ratio.
+        */
+       if (bdi->min_ratio)
+               bdi_set_min_ratio(bdi, 0);
+
        if (bdi->dev) {
                bdi_debug_unregister(bdi);
                device_unregister(bdi->dev);
index f03f42f..f18a631 100644 (file)
@@ -15,7 +15,7 @@
 
 void get_page_bootmem(unsigned long info, struct page *page, unsigned long type)
 {
-       page->freelist = (void *)type;
+       page->index = type;
        SetPagePrivate(page);
        set_page_private(page, info);
        page_ref_inc(page);
@@ -23,14 +23,13 @@ void get_page_bootmem(unsigned long info, struct page *page, unsigned long type)
 
 void put_page_bootmem(struct page *page)
 {
-       unsigned long type;
+       unsigned long type = page->index;
 
-       type = (unsigned long) page->freelist;
        BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
               type > MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE);
 
        if (page_ref_dec_return(page) == 1) {
-               page->freelist = NULL;
+               page->index = 0;
                ClearPagePrivate(page);
                set_page_private(page, 0);
                INIT_LIST_HEAD(&page->lru);
index c381b3c..e924978 100644 (file)
@@ -282,7 +282,6 @@ int damon_set_targets(struct damon_ctx *ctx,
        for (i = 0; i < nr_ids; i++) {
                t = damon_new_target(ids[i]);
                if (!t) {
-                       pr_err("Failed to alloc damon_target\n");
                        /* The caller should do cleanup of the ids itself */
                        damon_for_each_target_safe(t, next, ctx)
                                damon_destroy_target(t);
@@ -312,16 +311,10 @@ int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int,
                    unsigned long aggr_int, unsigned long primitive_upd_int,
                    unsigned long min_nr_reg, unsigned long max_nr_reg)
 {
-       if (min_nr_reg < 3) {
-               pr_err("min_nr_regions (%lu) must be at least 3\n",
-                               min_nr_reg);
+       if (min_nr_reg < 3)
                return -EINVAL;
-       }
-       if (min_nr_reg > max_nr_reg) {
-               pr_err("invalid nr_regions.  min (%lu) > max (%lu)\n",
-                               min_nr_reg, max_nr_reg);
+       if (min_nr_reg > max_nr_reg)
                return -EINVAL;
-       }
 
        ctx->sample_interval = sample_int;
        ctx->aggr_interval = aggr_int;
@@ -980,10 +973,11 @@ static unsigned long damos_wmark_wait_us(struct damos *scheme)
 
 static void kdamond_usleep(unsigned long usecs)
 {
-       if (usecs > 100 * 1000)
-               schedule_timeout_interruptible(usecs_to_jiffies(usecs));
+       /* See Documentation/timers/timers-howto.rst for the thresholds */
+       if (usecs > 20 * USEC_PER_MSEC)
+               schedule_timeout_idle(usecs_to_jiffies(usecs));
        else
-               usleep_range(usecs, usecs + 1);
+               usleep_idle_range(usecs, usecs + 1);
 }
 
 /* Returns negative error code if it's not activated but should return */
@@ -1038,7 +1032,7 @@ static int kdamond_fn(void *data)
                                ctx->callback.after_sampling(ctx))
                        done = true;
 
-               usleep_range(ctx->sample_interval, ctx->sample_interval + 1);
+               kdamond_usleep(ctx->sample_interval);
 
                if (ctx->primitive.check_accesses)
                        max_nr_accesses = ctx->primitive.check_accesses(ctx);
index 9b520bb..1efac00 100644 (file)
@@ -210,10 +210,8 @@ static struct damos **str_to_schemes(const char *str, ssize_t len,
                                &wmarks.low, &parsed);
                if (ret != 18)
                        break;
-               if (!damos_action_valid(action)) {
-                       pr_err("wrong action %d\n", action);
+               if (!damos_action_valid(action))
                        goto fail;
-               }
 
                pos += parsed;
                scheme = damon_new_scheme(min_sz, max_sz, min_nr_a, max_nr_a,
index ecfd0b2..6a1b927 100644 (file)
@@ -135,7 +135,6 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
                                struct damon_addr_range *three_regions,
                                unsigned long *expected, int nr_expected)
 {
-       struct damon_ctx *ctx = damon_new_ctx();
        struct damon_target *t;
        struct damon_region *r;
        int i;
@@ -145,7 +144,6 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
                r = damon_new_region(regions[i * 2], regions[i * 2 + 1]);
                damon_add_region(r, t);
        }
-       damon_add_target(ctx, t);
 
        damon_va_apply_three_regions(t, three_regions);
 
@@ -154,8 +152,6 @@ static void damon_do_test_apply_three_regions(struct kunit *test,
                KUNIT_EXPECT_EQ(test, r->ar.start, expected[i * 2]);
                KUNIT_EXPECT_EQ(test, r->ar.end, expected[i * 2 + 1]);
        }
-
-       damon_destroy_ctx(ctx);
 }
 
 /*
@@ -252,60 +248,59 @@ static void damon_test_apply_three_regions4(struct kunit *test)
                        new_three_regions, expected, ARRAY_SIZE(expected));
 }
 
-static void damon_test_split_evenly(struct kunit *test)
+static void damon_test_split_evenly_fail(struct kunit *test,
+               unsigned long start, unsigned long end, unsigned int nr_pieces)
 {
-       struct damon_ctx *c = damon_new_ctx();
-       struct damon_target *t;
-       struct damon_region *r;
-       unsigned long i;
-
-       KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5),
-                       -EINVAL);
-
-       t = damon_new_target(42);
-       r = damon_new_region(0, 100);
-       KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 0), -EINVAL);
+       struct damon_target *t = damon_new_target(42);
+       struct damon_region *r = damon_new_region(start, end);
 
        damon_add_region(r, t);
-       KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 10), 0);
-       KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 10u);
+       KUNIT_EXPECT_EQ(test,
+                       damon_va_evenly_split_region(t, r, nr_pieces), -EINVAL);
+       KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u);
 
-       i = 0;
        damon_for_each_region(r, t) {
-               KUNIT_EXPECT_EQ(test, r->ar.start, i++ * 10);
-               KUNIT_EXPECT_EQ(test, r->ar.end, i * 10);
+               KUNIT_EXPECT_EQ(test, r->ar.start, start);
+               KUNIT_EXPECT_EQ(test, r->ar.end, end);
        }
+
        damon_free_target(t);
+}
+
+static void damon_test_split_evenly_succ(struct kunit *test,
+       unsigned long start, unsigned long end, unsigned int nr_pieces)
+{
+       struct damon_target *t = damon_new_target(42);
+       struct damon_region *r = damon_new_region(start, end);
+       unsigned long expected_width = (end - start) / nr_pieces;
+       unsigned long i = 0;
 
-       t = damon_new_target(42);
-       r = damon_new_region(5, 59);
        damon_add_region(r, t);
-       KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 5), 0);
-       KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 5u);
+       KUNIT_EXPECT_EQ(test,
+                       damon_va_evenly_split_region(t, r, nr_pieces), 0);
+       KUNIT_EXPECT_EQ(test, damon_nr_regions(t), nr_pieces);
 
-       i = 0;
        damon_for_each_region(r, t) {
-               if (i == 4)
+               if (i == nr_pieces - 1)
                        break;
-               KUNIT_EXPECT_EQ(test, r->ar.start, 5 + 10 * i++);
-               KUNIT_EXPECT_EQ(test, r->ar.end, 5 + 10 * i);
+               KUNIT_EXPECT_EQ(test,
+                               r->ar.start, start + i++ * expected_width);
+               KUNIT_EXPECT_EQ(test, r->ar.end, start + i * expected_width);
        }
-       KUNIT_EXPECT_EQ(test, r->ar.start, 5 + 10 * i);
-       KUNIT_EXPECT_EQ(test, r->ar.end, 59ul);
+       KUNIT_EXPECT_EQ(test, r->ar.start, start + i * expected_width);
+       KUNIT_EXPECT_EQ(test, r->ar.end, end);
        damon_free_target(t);
+}
 
-       t = damon_new_target(42);
-       r = damon_new_region(5, 6);
-       damon_add_region(r, t);
-       KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(t, r, 2), -EINVAL);
-       KUNIT_EXPECT_EQ(test, damon_nr_regions(t), 1u);
+static void damon_test_split_evenly(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, damon_va_evenly_split_region(NULL, NULL, 5),
+                       -EINVAL);
 
-       damon_for_each_region(r, t) {
-               KUNIT_EXPECT_EQ(test, r->ar.start, 5ul);
-               KUNIT_EXPECT_EQ(test, r->ar.end, 6ul);
-       }
-       damon_free_target(t);
-       damon_destroy_ctx(c);
+       damon_test_split_evenly_fail(test, 0, 100, 0);
+       damon_test_split_evenly_succ(test, 0, 100, 10);
+       damon_test_split_evenly_succ(test, 5, 59, 5);
+       damon_test_split_evenly_fail(test, 5, 6, 2);
 }
 
 static struct kunit_case damon_test_cases[] = {
index 35fe490..20a9a9d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mmu_notifier.h>
 #include <linux/page_idle.h>
 #include <linux/pagewalk.h>
+#include <linux/sched/mm.h>
 
 #include "prmtv-common.h"
 
@@ -626,7 +627,6 @@ int damon_va_apply_scheme(struct damon_ctx *ctx, struct damon_target *t,
        case DAMOS_STAT:
                return 0;
        default:
-               pr_warn("Wrong action %d\n", scheme->action);
                return -EINVAL;
        }
 
index daa0e23..39c4c46 100644 (file)
@@ -3253,8 +3253,6 @@ static struct page *next_uptodate_page(struct page *page,
                        goto skip;
                if (!PageUptodate(page) || PageReadahead(page))
                        goto skip;
-               if (PageHWPoison(page))
-                       goto skip;
                if (!trylock_page(page))
                        goto skip;
                if (page->mapping != mapping)
index abcd178..a1baa19 100644 (file)
@@ -2973,7 +2973,7 @@ int __alloc_bootmem_huge_page(struct hstate *h, int nid)
        struct huge_bootmem_page *m = NULL; /* initialize for clang */
        int nr_nodes, node;
 
-       if (nid >= nr_online_nodes)
+       if (nid != NUMA_NO_NODE && nid >= nr_online_nodes)
                return 0;
        /* do node specific alloc */
        if (nid != NUMA_NO_NODE) {
index 8428da2..7c06db7 100644 (file)
@@ -247,8 +247,9 @@ struct kasan_free_meta *kasan_get_free_meta(struct kmem_cache *cache,
 }
 #endif
 
-void __kasan_poison_slab(struct page *page)
+void __kasan_poison_slab(struct slab *slab)
 {
+       struct page *page = slab_page(slab);
        unsigned long i;
 
        for (i = 0; i < compound_nr(page); i++)
@@ -298,7 +299,7 @@ static inline u8 assign_tag(struct kmem_cache *cache,
        /* For caches that either have a constructor or SLAB_TYPESAFE_BY_RCU: */
 #ifdef CONFIG_SLAB
        /* For SLAB assign tags based on the object index in the freelist. */
-       return (u8)obj_to_index(cache, virt_to_head_page(object), (void *)object);
+       return (u8)obj_to_index(cache, virt_to_slab(object), (void *)object);
 #else
        /*
         * For SLUB assign a random tag during slab creation, otherwise reuse
@@ -341,7 +342,7 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, void *object,
        if (is_kfence_address(object))
                return false;
 
-       if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) !=
+       if (unlikely(nearest_obj(cache, virt_to_slab(object), object) !=
            object)) {
                kasan_report_invalid_free(tagged_object, ip);
                return true;
@@ -401,9 +402,9 @@ void __kasan_kfree_large(void *ptr, unsigned long ip)
 
 void __kasan_slab_free_mempool(void *ptr, unsigned long ip)
 {
-       struct page *page;
+       struct folio *folio;
 
-       page = virt_to_head_page(ptr);
+       folio = virt_to_folio(ptr);
 
        /*
         * Even though this function is only called for kmem_cache_alloc and
@@ -411,12 +412,14 @@ void __kasan_slab_free_mempool(void *ptr, unsigned long ip)
         * !PageSlab() when the size provided to kmalloc is larger than
         * KMALLOC_MAX_SIZE, and kmalloc falls back onto page_alloc.
         */
-       if (unlikely(!PageSlab(page))) {
+       if (unlikely(!folio_test_slab(folio))) {
                if (____kasan_kfree_large(ptr, ip))
                        return;
-               kasan_poison(ptr, page_size(page), KASAN_FREE_PAGE, false);
+               kasan_poison(ptr, folio_size(folio), KASAN_FREE_PAGE, false);
        } else {
-               ____kasan_slab_free(page->slab_cache, ptr, ip, false, false);
+               struct slab *slab = folio_slab(folio);
+
+               ____kasan_slab_free(slab->slab_cache, ptr, ip, false, false);
        }
 }
 
@@ -560,7 +563,7 @@ void * __must_check __kasan_kmalloc_large(const void *ptr, size_t size,
 
 void * __must_check __kasan_krealloc(const void *object, size_t size, gfp_t flags)
 {
-       struct page *page;
+       struct slab *slab;
 
        if (unlikely(object == ZERO_SIZE_PTR))
                return (void *)object;
@@ -572,13 +575,13 @@ void * __must_check __kasan_krealloc(const void *object, size_t size, gfp_t flag
         */
        kasan_unpoison(object, size, false);
 
-       page = virt_to_head_page(object);
+       slab = virt_to_slab(object);
 
        /* Piggy-back on kmalloc() instrumentation to poison the redzone. */
-       if (unlikely(!PageSlab(page)))
+       if (unlikely(!slab))
                return __kasan_kmalloc_large(object, size, flags);
        else
-               return ____kasan_kmalloc(page->slab_cache, object, size, flags);
+               return ____kasan_kmalloc(slab->slab_cache, object, size, flags);
 }
 
 bool __kasan_check_byte(const void *address, unsigned long ip)
index 84a038b..a25ad40 100644 (file)
@@ -330,16 +330,16 @@ DEFINE_ASAN_SET_SHADOW(f8);
 
 static void __kasan_record_aux_stack(void *addr, bool can_alloc)
 {
-       struct page *page = kasan_addr_to_page(addr);
+       struct slab *slab = kasan_addr_to_slab(addr);
        struct kmem_cache *cache;
        struct kasan_alloc_meta *alloc_meta;
        void *object;
 
-       if (is_kfence_address(addr) || !(page && PageSlab(page)))
+       if (is_kfence_address(addr) || !slab)
                return;
 
-       cache = page->slab_cache;
-       object = nearest_obj(cache, page, addr);
+       cache = slab->slab_cache;
+       object = nearest_obj(cache, slab, addr);
        alloc_meta = kasan_get_alloc_meta(cache, object);
        if (!alloc_meta)
                return;
index aebd8df..c17fa8d 100644 (file)
@@ -265,6 +265,7 @@ bool kasan_report(unsigned long addr, size_t size,
 void kasan_report_invalid_free(void *object, unsigned long ip);
 
 struct page *kasan_addr_to_page(const void *addr);
+struct slab *kasan_addr_to_slab(const void *addr);
 
 depot_stack_handle_t kasan_save_stack(gfp_t flags, bool can_alloc);
 void kasan_set_track(struct kasan_track *track, gfp_t flags);
index d8ccff4..587da89 100644 (file)
@@ -117,7 +117,7 @@ static unsigned long quarantine_batch_size;
 
 static struct kmem_cache *qlink_to_cache(struct qlist_node *qlink)
 {
-       return virt_to_head_page(qlink)->slab_cache;
+       return virt_to_slab(qlink)->slab_cache;
 }
 
 static void *qlink_to_object(struct qlist_node *qlink, struct kmem_cache *cache)
index 0bc10f4..3ad9624 100644 (file)
@@ -150,6 +150,14 @@ struct page *kasan_addr_to_page(const void *addr)
        return NULL;
 }
 
+struct slab *kasan_addr_to_slab(const void *addr)
+{
+       if ((addr >= (void *)PAGE_OFFSET) &&
+                       (addr < high_memory))
+               return virt_to_slab(addr);
+       return NULL;
+}
+
 static void describe_object_addr(struct kmem_cache *cache, void *object,
                                const void *addr)
 {
@@ -248,8 +256,9 @@ static void print_address_description(void *addr, u8 tag)
        pr_err("\n");
 
        if (page && PageSlab(page)) {
-               struct kmem_cache *cache = page->slab_cache;
-               void *object = nearest_obj(cache, page, addr);
+               struct slab *slab = page_slab(page);
+               struct kmem_cache *cache = slab->slab_cache;
+               void *object = nearest_obj(cache, slab, addr);
 
                describe_object(cache, object, addr, tag);
        }
index 8a319fc..1b41de8 100644 (file)
@@ -12,7 +12,7 @@ const char *kasan_get_bug_type(struct kasan_access_info *info)
 #ifdef CONFIG_KASAN_TAGS_IDENTIFY
        struct kasan_alloc_meta *alloc_meta;
        struct kmem_cache *cache;
-       struct page *page;
+       struct slab *slab;
        const void *addr;
        void *object;
        u8 tag;
@@ -20,10 +20,10 @@ const char *kasan_get_bug_type(struct kasan_access_info *info)
 
        tag = get_tag(info->access_addr);
        addr = kasan_reset_tag(info->access_addr);
-       page = kasan_addr_to_page(addr);
-       if (page && PageSlab(page)) {
-               cache = page->slab_cache;
-               object = nearest_obj(cache, page, (void *)addr);
+       slab = kasan_addr_to_slab(addr);
+       if (slab) {
+               cache = slab->slab_cache;
+               object = nearest_obj(cache, slab, (void *)addr);
                alloc_meta = kasan_get_alloc_meta(cache, object);
 
                if (alloc_meta) {
index 0994578..267dfde 100644 (file)
@@ -360,7 +360,7 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g
 {
        struct kfence_metadata *meta = NULL;
        unsigned long flags;
-       struct page *page;
+       struct slab *slab;
        void *addr;
 
        /* Try to obtain a free object. */
@@ -424,13 +424,14 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g
 
        alloc_covered_add(alloc_stack_hash, 1);
 
-       /* Set required struct page fields. */
-       page = virt_to_page(meta->addr);
-       page->slab_cache = cache;
-       if (IS_ENABLED(CONFIG_SLUB))
-               page->objects = 1;
-       if (IS_ENABLED(CONFIG_SLAB))
-               page->s_mem = addr;
+       /* Set required slab fields. */
+       slab = virt_to_slab((void *)meta->addr);
+       slab->slab_cache = cache;
+#if defined(CONFIG_SLUB)
+       slab->objects = 1;
+#elif defined(CONFIG_SLAB)
+       slab->s_mem = addr;
+#endif
 
        /* Memory initialization. */
        for_each_canary(meta, set_canary_byte);
index 695030c..a22b1af 100644 (file)
@@ -282,7 +282,7 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat
                        alloc = kmalloc(size, gfp);
 
                if (is_kfence_address(alloc)) {
-                       struct page *page = virt_to_head_page(alloc);
+                       struct slab *slab = virt_to_slab(alloc);
                        struct kmem_cache *s = test_cache ?:
                                        kmalloc_caches[kmalloc_type(GFP_KERNEL)][__kmalloc_index(size, false)];
 
@@ -291,8 +291,8 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat
                         * even for KFENCE objects; these are required so that
                         * memcg accounting works correctly.
                         */
-                       KUNIT_EXPECT_EQ(test, obj_to_index(s, page, alloc), 0U);
-                       KUNIT_EXPECT_EQ(test, objs_per_slab_page(s, page), 1);
+                       KUNIT_EXPECT_EQ(test, obj_to_index(s, slab, alloc), 0U);
+                       KUNIT_EXPECT_EQ(test, objs_per_slab(s, slab), 1);
 
                        if (policy == ALLOCATE_ANY)
                                return alloc;
index 6863a83..4a7b3eb 100644 (file)
@@ -776,24 +776,6 @@ void __mod_lruvec_kmem_state(void *p, enum node_stat_item idx, int val)
        rcu_read_unlock();
 }
 
-/*
- * mod_objcg_mlstate() may be called with irq enabled, so
- * mod_memcg_lruvec_state() should be used.
- */
-static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
-                                    struct pglist_data *pgdat,
-                                    enum node_stat_item idx, int nr)
-{
-       struct mem_cgroup *memcg;
-       struct lruvec *lruvec;
-
-       rcu_read_lock();
-       memcg = obj_cgroup_memcg(objcg);
-       lruvec = mem_cgroup_lruvec(memcg, pgdat);
-       mod_memcg_lruvec_state(lruvec, idx, nr);
-       rcu_read_unlock();
-}
-
 /**
  * __count_memcg_events - account VM events in a cgroup
  * @memcg: the memory cgroup
@@ -2137,41 +2119,6 @@ static bool obj_stock_flush_required(struct memcg_stock_pcp *stock,
 }
 #endif
 
-/*
- * Most kmem_cache_alloc() calls are from user context. The irq disable/enable
- * sequence used in this case to access content from object stock is slow.
- * To optimize for user context access, there are now two object stocks for
- * task context and interrupt context access respectively.
- *
- * The task context object stock can be accessed by disabling preemption only
- * which is cheap in non-preempt kernel. The interrupt context object stock
- * can only be accessed after disabling interrupt. User context code can
- * access interrupt object stock, but not vice versa.
- */
-static inline struct obj_stock *get_obj_stock(unsigned long *pflags)
-{
-       struct memcg_stock_pcp *stock;
-
-       if (likely(in_task())) {
-               *pflags = 0UL;
-               preempt_disable();
-               stock = this_cpu_ptr(&memcg_stock);
-               return &stock->task_obj;
-       }
-
-       local_irq_save(*pflags);
-       stock = this_cpu_ptr(&memcg_stock);
-       return &stock->irq_obj;
-}
-
-static inline void put_obj_stock(unsigned long flags)
-{
-       if (likely(in_task()))
-               preempt_enable();
-       else
-               local_irq_restore(flags);
-}
-
 /**
  * consume_stock: Try to consume stocked charge on this cpu.
  * @memcg: memcg to consume from.
@@ -2816,31 +2763,84 @@ retry:
  */
 #define OBJCGS_CLEAR_MASK      (__GFP_DMA | __GFP_RECLAIMABLE | __GFP_ACCOUNT)
 
-int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
-                                gfp_t gfp, bool new_page)
+/*
+ * Most kmem_cache_alloc() calls are from user context. The irq disable/enable
+ * sequence used in this case to access content from object stock is slow.
+ * To optimize for user context access, there are now two object stocks for
+ * task context and interrupt context access respectively.
+ *
+ * The task context object stock can be accessed by disabling preemption only
+ * which is cheap in non-preempt kernel. The interrupt context object stock
+ * can only be accessed after disabling interrupt. User context code can
+ * access interrupt object stock, but not vice versa.
+ */
+static inline struct obj_stock *get_obj_stock(unsigned long *pflags)
+{
+       struct memcg_stock_pcp *stock;
+
+       if (likely(in_task())) {
+               *pflags = 0UL;
+               preempt_disable();
+               stock = this_cpu_ptr(&memcg_stock);
+               return &stock->task_obj;
+       }
+
+       local_irq_save(*pflags);
+       stock = this_cpu_ptr(&memcg_stock);
+       return &stock->irq_obj;
+}
+
+static inline void put_obj_stock(unsigned long flags)
 {
-       unsigned int objects = objs_per_slab_page(s, page);
+       if (likely(in_task()))
+               preempt_enable();
+       else
+               local_irq_restore(flags);
+}
+
+/*
+ * mod_objcg_mlstate() may be called with irq enabled, so
+ * mod_memcg_lruvec_state() should be used.
+ */
+static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
+                                    struct pglist_data *pgdat,
+                                    enum node_stat_item idx, int nr)
+{
+       struct mem_cgroup *memcg;
+       struct lruvec *lruvec;
+
+       rcu_read_lock();
+       memcg = obj_cgroup_memcg(objcg);
+       lruvec = mem_cgroup_lruvec(memcg, pgdat);
+       mod_memcg_lruvec_state(lruvec, idx, nr);
+       rcu_read_unlock();
+}
+
+int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s,
+                                gfp_t gfp, bool new_slab)
+{
+       unsigned int objects = objs_per_slab(s, slab);
        unsigned long memcg_data;
        void *vec;
 
        gfp &= ~OBJCGS_CLEAR_MASK;
        vec = kcalloc_node(objects, sizeof(struct obj_cgroup *), gfp,
-                          page_to_nid(page));
+                          slab_nid(slab));
        if (!vec)
                return -ENOMEM;
 
        memcg_data = (unsigned long) vec | MEMCG_DATA_OBJCGS;
-       if (new_page) {
+       if (new_slab) {
                /*
-                * If the slab page is brand new and nobody can yet access
-                * it's memcg_data, no synchronization is required and
-                * memcg_data can be simply assigned.
+                * If the slab is brand new and nobody can yet access its
+                * memcg_data, no synchronization is required and memcg_data can
+                * be simply assigned.
                 */
-               page->memcg_data = memcg_data;
-       } else if (cmpxchg(&page->memcg_data, 0, memcg_data)) {
+               slab->memcg_data = memcg_data;
+       } else if (cmpxchg(&slab->memcg_data, 0, memcg_data)) {
                /*
-                * If the slab page is already in use, somebody can allocate
-                * and assign obj_cgroups in parallel. In this case the existing
+                * If the slab is already in use, somebody can allocate and
+                * assign obj_cgroups in parallel. In this case the existing
                 * objcg vector should be reused.
                 */
                kfree(vec);
@@ -2865,38 +2865,43 @@ int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
  */
 struct mem_cgroup *mem_cgroup_from_obj(void *p)
 {
-       struct page *page;
+       struct folio *folio;
 
        if (mem_cgroup_disabled())
                return NULL;
 
-       page = virt_to_head_page(p);
+       folio = virt_to_folio(p);
 
        /*
         * Slab objects are accounted individually, not per-page.
         * Memcg membership data for each individual object is saved in
-        * the page->obj_cgroups.
+        * slab->memcg_data.
         */
-       if (page_objcgs_check(page)) {
-               struct obj_cgroup *objcg;
+       if (folio_test_slab(folio)) {
+               struct obj_cgroup **objcgs;
+               struct slab *slab;
                unsigned int off;
 
-               off = obj_to_index(page->slab_cache, page, p);
-               objcg = page_objcgs(page)[off];
-               if (objcg)
-                       return obj_cgroup_memcg(objcg);
+               slab = folio_slab(folio);
+               objcgs = slab_objcgs(slab);
+               if (!objcgs)
+                       return NULL;
+
+               off = obj_to_index(slab->slab_cache, slab, p);
+               if (objcgs[off])
+                       return obj_cgroup_memcg(objcgs[off]);
 
                return NULL;
        }
 
        /*
-        * page_memcg_check() is used here, because page_has_obj_cgroups()
-        * check above could fail because the object cgroups vector wasn't set
-        * at that moment, but it can be set concurrently.
+        * page_memcg_check() is used here, because in theory we can encounter
+        * a folio where the slab flag has been cleared already, but
+        * slab->memcg_data has not been freed yet
         * page_memcg_check(page) will guarantee that a proper memory
         * cgroup pointer or NULL will be returned.
         */
-       return page_memcg_check(page);
+       return page_memcg_check(folio_page(folio, 0));
 }
 
 __always_inline struct obj_cgroup *get_obj_cgroup_from_current(void)
index 852041f..2a9627d 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/memblock.h>
 #include <linux/compaction.h>
 #include <linux/rmap.h>
+#include <linux/module.h>
 
 #include <asm/tlbflush.h>
 
index ca4822f..ddf5737 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -218,7 +218,7 @@ static void cache_reap(struct work_struct *unused);
 static inline void fixup_objfreelist_debug(struct kmem_cache *cachep,
                                                void **list);
 static inline void fixup_slab_list(struct kmem_cache *cachep,
-                               struct kmem_cache_node *n, struct page *page,
+                               struct kmem_cache_node *n, struct slab *slab,
                                void **list);
 static int slab_early_init = 1;
 
@@ -372,10 +372,10 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 static int slab_max_order = SLAB_MAX_ORDER_LO;
 static bool slab_max_order_set __initdata;
 
-static inline void *index_to_obj(struct kmem_cache *cache, struct page *page,
-                                unsigned int idx)
+static inline void *index_to_obj(struct kmem_cache *cache,
+                                const struct slab *slab, unsigned int idx)
 {
-       return page->s_mem + cache->size * idx;
+       return slab->s_mem + cache->size * idx;
 }
 
 #define BOOT_CPUCACHE_ENTRIES  1
@@ -550,17 +550,17 @@ static struct array_cache *alloc_arraycache(int node, int entries,
 }
 
 static noinline void cache_free_pfmemalloc(struct kmem_cache *cachep,
-                                       struct page *page, void *objp)
+                                       struct slab *slab, void *objp)
 {
        struct kmem_cache_node *n;
-       int page_node;
+       int slab_node;
        LIST_HEAD(list);
 
-       page_node = page_to_nid(page);
-       n = get_node(cachep, page_node);
+       slab_node = slab_nid(slab);
+       n = get_node(cachep, slab_node);
 
        spin_lock(&n->list_lock);
-       free_block(cachep, &objp, 1, page_node, &list);
+       free_block(cachep, &objp, 1, slab_node, &list);
        spin_unlock(&n->list_lock);
 
        slabs_destroy(cachep, &list);
@@ -761,7 +761,7 @@ static void drain_alien_cache(struct kmem_cache *cachep,
 }
 
 static int __cache_free_alien(struct kmem_cache *cachep, void *objp,
-                               int node, int page_node)
+                               int node, int slab_node)
 {
        struct kmem_cache_node *n;
        struct alien_cache *alien = NULL;
@@ -770,21 +770,21 @@ static int __cache_free_alien(struct kmem_cache *cachep, void *objp,
 
        n = get_node(cachep, node);
        STATS_INC_NODEFREES(cachep);
-       if (n->alien && n->alien[page_node]) {
-               alien = n->alien[page_node];
+       if (n->alien && n->alien[slab_node]) {
+               alien = n->alien[slab_node];
                ac = &alien->ac;
                spin_lock(&alien->lock);
                if (unlikely(ac->avail == ac->limit)) {
                        STATS_INC_ACOVERFLOW(cachep);
-                       __drain_alien_cache(cachep, ac, page_node, &list);
+                       __drain_alien_cache(cachep, ac, slab_node, &list);
                }
                __free_one(ac, objp);
                spin_unlock(&alien->lock);
                slabs_destroy(cachep, &list);
        } else {
-               n = get_node(cachep, page_node);
+               n = get_node(cachep, slab_node);
                spin_lock(&n->list_lock);
-               free_block(cachep, &objp, 1, page_node, &list);
+               free_block(cachep, &objp, 1, slab_node, &list);
                spin_unlock(&n->list_lock);
                slabs_destroy(cachep, &list);
        }
@@ -793,16 +793,16 @@ static int __cache_free_alien(struct kmem_cache *cachep, void *objp,
 
 static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
 {
-       int page_node = page_to_nid(virt_to_page(objp));
+       int slab_node = slab_nid(virt_to_slab(objp));
        int node = numa_mem_id();
        /*
         * Make sure we are not freeing a object from another node to the array
         * cache on this cpu.
         */
-       if (likely(node == page_node))
+       if (likely(node == slab_node))
                return 0;
 
-       return __cache_free_alien(cachep, objp, node, page_node);
+       return __cache_free_alien(cachep, objp, node, slab_node);
 }
 
 /*
@@ -1367,57 +1367,60 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
  * did not request dmaable memory, we might get it, but that
  * would be relatively rare and ignorable.
  */
-static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
+static struct slab *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
                                                                int nodeid)
 {
-       struct page *page;
+       struct folio *folio;
+       struct slab *slab;
 
        flags |= cachep->allocflags;
 
-       page = __alloc_pages_node(nodeid, flags, cachep->gfporder);
-       if (!page) {
+       folio = (struct folio *) __alloc_pages_node(nodeid, flags, cachep->gfporder);
+       if (!folio) {
                slab_out_of_memory(cachep, flags, nodeid);
                return NULL;
        }
 
-       account_slab_page(page, cachep->gfporder, cachep, flags);
-       __SetPageSlab(page);
+       slab = folio_slab(folio);
+
+       account_slab(slab, cachep->gfporder, cachep, flags);
+       __folio_set_slab(folio);
        /* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */
-       if (sk_memalloc_socks() && page_is_pfmemalloc(page))
-               SetPageSlabPfmemalloc(page);
+       if (sk_memalloc_socks() && page_is_pfmemalloc(folio_page(folio, 0)))
+               slab_set_pfmemalloc(slab);
 
-       return page;
+       return slab;
 }
 
 /*
  * Interface to system's page release.
  */
-static void kmem_freepages(struct kmem_cache *cachep, struct page *page)
+static void kmem_freepages(struct kmem_cache *cachep, struct slab *slab)
 {
        int order = cachep->gfporder;
+       struct folio *folio = slab_folio(slab);
 
-       BUG_ON(!PageSlab(page));
-       __ClearPageSlabPfmemalloc(page);
-       __ClearPageSlab(page);
-       page_mapcount_reset(page);
-       /* In union with page->mapping where page allocator expects NULL */
-       page->slab_cache = NULL;
+       BUG_ON(!folio_test_slab(folio));
+       __slab_clear_pfmemalloc(slab);
+       __folio_clear_slab(folio);
+       page_mapcount_reset(folio_page(folio, 0));
+       folio->mapping = NULL;
 
        if (current->reclaim_state)
                current->reclaim_state->reclaimed_slab += 1 << order;
-       unaccount_slab_page(page, order, cachep);
-       __free_pages(page, order);
+       unaccount_slab(slab, order, cachep);
+       __free_pages(folio_page(folio, 0), order);
 }
 
 static void kmem_rcu_free(struct rcu_head *head)
 {
        struct kmem_cache *cachep;
-       struct page *page;
+       struct slab *slab;
 
-       page = container_of(head, struct page, rcu_head);
-       cachep = page->slab_cache;
+       slab = container_of(head, struct slab, rcu_head);
+       cachep = slab->slab_cache;
 
-       kmem_freepages(cachep, page);
+       kmem_freepages(cachep, slab);
 }
 
 #if DEBUG
@@ -1553,18 +1556,18 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
                /* Print some data about the neighboring objects, if they
                 * exist:
                 */
-               struct page *page = virt_to_head_page(objp);
+               struct slab *slab = virt_to_slab(objp);
                unsigned int objnr;
 
-               objnr = obj_to_index(cachep, page, objp);
+               objnr = obj_to_index(cachep, slab, objp);
                if (objnr) {
-                       objp = index_to_obj(cachep, page, objnr - 1);
+                       objp = index_to_obj(cachep, slab, objnr - 1);
                        realobj = (char *)objp + obj_offset(cachep);
                        pr_err("Prev obj: start=%px, len=%d\n", realobj, size);
                        print_objinfo(cachep, objp, 2);
                }
                if (objnr + 1 < cachep->num) {
-                       objp = index_to_obj(cachep, page, objnr + 1);
+                       objp = index_to_obj(cachep, slab, objnr + 1);
                        realobj = (char *)objp + obj_offset(cachep);
                        pr_err("Next obj: start=%px, len=%d\n", realobj, size);
                        print_objinfo(cachep, objp, 2);
@@ -1575,17 +1578,17 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
 
 #if DEBUG
 static void slab_destroy_debugcheck(struct kmem_cache *cachep,
-                                               struct page *page)
+                                               struct slab *slab)
 {
        int i;
 
        if (OBJFREELIST_SLAB(cachep) && cachep->flags & SLAB_POISON) {
-               poison_obj(cachep, page->freelist - obj_offset(cachep),
+               poison_obj(cachep, slab->freelist - obj_offset(cachep),
                        POISON_FREE);
        }
 
        for (i = 0; i < cachep->num; i++) {
-               void *objp = index_to_obj(cachep, page, i);
+               void *objp = index_to_obj(cachep, slab, i);
 
                if (cachep->flags & SLAB_POISON) {
                        check_poison_obj(cachep, objp);
@@ -1601,7 +1604,7 @@ static void slab_destroy_debugcheck(struct kmem_cache *cachep,
 }
 #else
 static void slab_destroy_debugcheck(struct kmem_cache *cachep,
-                                               struct page *page)
+                                               struct slab *slab)
 {
 }
 #endif
@@ -1609,22 +1612,22 @@ static void slab_destroy_debugcheck(struct kmem_cache *cachep,
 /**
  * slab_destroy - destroy and release all objects in a slab
  * @cachep: cache pointer being destroyed
- * @page: page pointer being destroyed
+ * @slab: slab being destroyed
  *
- * Destroy all the objs in a slab page, and release the mem back to the system.
- * Before calling the slab page must have been unlinked from the cache. The
+ * Destroy all the objs in a slab, and release the mem back to the system.
+ * Before calling the slab must have been unlinked from the cache. The
  * kmem_cache_node ->list_lock is not held/needed.
  */
-static void slab_destroy(struct kmem_cache *cachep, struct page *page)
+static void slab_destroy(struct kmem_cache *cachep, struct slab *slab)
 {
        void *freelist;
 
-       freelist = page->freelist;
-       slab_destroy_debugcheck(cachep, page);
+       freelist = slab->freelist;
+       slab_destroy_debugcheck(cachep, slab);
        if (unlikely(cachep->flags & SLAB_TYPESAFE_BY_RCU))
-               call_rcu(&page->rcu_head, kmem_rcu_free);
+               call_rcu(&slab->rcu_head, kmem_rcu_free);
        else
-               kmem_freepages(cachep, page);
+               kmem_freepages(cachep, slab);
 
        /*
         * From now on, we don't use freelist
@@ -1640,11 +1643,11 @@ static void slab_destroy(struct kmem_cache *cachep, struct page *page)
  */
 static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
 {
-       struct page *page, *n;
+       struct slab *slab, *n;
 
-       list_for_each_entry_safe(page, n, list, slab_list) {
-               list_del(&page->slab_list);
-               slab_destroy(cachep, page);
+       list_for_each_entry_safe(slab, n, list, slab_list) {
+               list_del(&slab->slab_list);
+               slab_destroy(cachep, slab);
        }
 }
 
@@ -2194,7 +2197,7 @@ static int drain_freelist(struct kmem_cache *cache,
 {
        struct list_head *p;
        int nr_freed;
-       struct page *page;
+       struct slab *slab;
 
        nr_freed = 0;
        while (nr_freed < tofree && !list_empty(&n->slabs_free)) {
@@ -2206,8 +2209,8 @@ static int drain_freelist(struct kmem_cache *cache,
                        goto out;
                }
 
-               page = list_entry(p, struct page, slab_list);
-               list_del(&page->slab_list);
+               slab = list_entry(p, struct slab, slab_list);
+               list_del(&slab->slab_list);
                n->free_slabs--;
                n->total_slabs--;
                /*
@@ -2216,7 +2219,7 @@ static int drain_freelist(struct kmem_cache *cache,
                 */
                n->free_objects -= cache->num;
                spin_unlock_irq(&n->list_lock);
-               slab_destroy(cache, page);
+               slab_destroy(cache, slab);
                nr_freed++;
        }
 out:
@@ -2291,14 +2294,14 @@ void __kmem_cache_release(struct kmem_cache *cachep)
  * which are all initialized during kmem_cache_init().
  */
 static void *alloc_slabmgmt(struct kmem_cache *cachep,
-                                  struct page *page, int colour_off,
+                                  struct slab *slab, int colour_off,
                                   gfp_t local_flags, int nodeid)
 {
        void *freelist;
-       void *addr = page_address(page);
+       void *addr = slab_address(slab);
 
-       page->s_mem = addr + colour_off;
-       page->active = 0;
+       slab->s_mem = addr + colour_off;
+       slab->active = 0;
 
        if (OBJFREELIST_SLAB(cachep))
                freelist = NULL;
@@ -2315,24 +2318,24 @@ static void *alloc_slabmgmt(struct kmem_cache *cachep,
        return freelist;
 }
 
-static inline freelist_idx_t get_free_obj(struct page *page, unsigned int idx)
+static inline freelist_idx_t get_free_obj(struct slab *slab, unsigned int idx)
 {
-       return ((freelist_idx_t *)page->freelist)[idx];
+       return ((freelist_idx_t *) slab->freelist)[idx];
 }
 
-static inline void set_free_obj(struct page *page,
+static inline void set_free_obj(struct slab *slab,
                                        unsigned int idx, freelist_idx_t val)
 {
-       ((freelist_idx_t *)(page->freelist))[idx] = val;
+       ((freelist_idx_t *)(slab->freelist))[idx] = val;
 }
 
-static void cache_init_objs_debug(struct kmem_cache *cachep, struct page *page)
+static void cache_init_objs_debug(struct kmem_cache *cachep, struct slab *slab)
 {
 #if DEBUG
        int i;
 
        for (i = 0; i < cachep->num; i++) {
-               void *objp = index_to_obj(cachep, page, i);
+               void *objp = index_to_obj(cachep, slab, i);
 
                if (cachep->flags & SLAB_STORE_USER)
                        *dbg_userword(cachep, objp) = NULL;
@@ -2416,17 +2419,17 @@ static freelist_idx_t next_random_slot(union freelist_init_state *state)
 }
 
 /* Swap two freelist entries */
-static void swap_free_obj(struct page *page, unsigned int a, unsigned int b)
+static void swap_free_obj(struct slab *slab, unsigned int a, unsigned int b)
 {
-       swap(((freelist_idx_t *)page->freelist)[a],
-               ((freelist_idx_t *)page->freelist)[b]);
+       swap(((freelist_idx_t *) slab->freelist)[a],
+               ((freelist_idx_t *) slab->freelist)[b]);
 }
 
 /*
  * Shuffle the freelist initialization state based on pre-computed lists.
  * return true if the list was successfully shuffled, false otherwise.
  */
-static bool shuffle_freelist(struct kmem_cache *cachep, struct page *page)
+static bool shuffle_freelist(struct kmem_cache *cachep, struct slab *slab)
 {
        unsigned int objfreelist = 0, i, rand, count = cachep->num;
        union freelist_init_state state;
@@ -2443,7 +2446,7 @@ static bool shuffle_freelist(struct kmem_cache *cachep, struct page *page)
                        objfreelist = count - 1;
                else
                        objfreelist = next_random_slot(&state);
-               page->freelist = index_to_obj(cachep, page, objfreelist) +
+               slab->freelist = index_to_obj(cachep, slab, objfreelist) +
                                                obj_offset(cachep);
                count--;
        }
@@ -2454,51 +2457,51 @@ static bool shuffle_freelist(struct kmem_cache *cachep, struct page *page)
         */
        if (!precomputed) {
                for (i = 0; i < count; i++)
-                       set_free_obj(page, i, i);
+                       set_free_obj(slab, i, i);
 
                /* Fisher-Yates shuffle */
                for (i = count - 1; i > 0; i--) {
                        rand = prandom_u32_state(&state.rnd_state);
                        rand %= (i + 1);
-                       swap_free_obj(page, i, rand);
+                       swap_free_obj(slab, i, rand);
                }
        } else {
                for (i = 0; i < count; i++)
-                       set_free_obj(page, i, next_random_slot(&state));
+                       set_free_obj(slab, i, next_random_slot(&state));
        }
 
        if (OBJFREELIST_SLAB(cachep))
-               set_free_obj(page, cachep->num - 1, objfreelist);
+               set_free_obj(slab, cachep->num - 1, objfreelist);
 
        return true;
 }
 #else
 static inline bool shuffle_freelist(struct kmem_cache *cachep,
-                               struct page *page)
+                               struct slab *slab)
 {
        return false;
 }
 #endif /* CONFIG_SLAB_FREELIST_RANDOM */
 
 static void cache_init_objs(struct kmem_cache *cachep,
-                           struct page *page)
+                           struct slab *slab)
 {
        int i;
        void *objp;
        bool shuffled;
 
-       cache_init_objs_debug(cachep, page);
+       cache_init_objs_debug(cachep, slab);
 
        /* Try to randomize the freelist if enabled */
-       shuffled = shuffle_freelist(cachep, page);
+       shuffled = shuffle_freelist(cachep, slab);
 
        if (!shuffled && OBJFREELIST_SLAB(cachep)) {
-               page->freelist = index_to_obj(cachep, page, cachep->num - 1) +
+               slab->freelist = index_to_obj(cachep, slab, cachep->num - 1) +
                                                obj_offset(cachep);
        }
 
        for (i = 0; i < cachep->num; i++) {
-               objp = index_to_obj(cachep, page, i);
+               objp = index_to_obj(cachep, slab, i);
                objp = kasan_init_slab_obj(cachep, objp);
 
                /* constructor could break poison info */
@@ -2509,68 +2512,56 @@ static void cache_init_objs(struct kmem_cache *cachep,
                }
 
                if (!shuffled)
-                       set_free_obj(page, i, i);
+                       set_free_obj(slab, i, i);
        }
 }
 
-static void *slab_get_obj(struct kmem_cache *cachep, struct page *page)
+static void *slab_get_obj(struct kmem_cache *cachep, struct slab *slab)
 {
        void *objp;
 
-       objp = index_to_obj(cachep, page, get_free_obj(page, page->active));
-       page->active++;
+       objp = index_to_obj(cachep, slab, get_free_obj(slab, slab->active));
+       slab->active++;
 
        return objp;
 }
 
 static void slab_put_obj(struct kmem_cache *cachep,
-                       struct page *page, void *objp)
+                       struct slab *slab, void *objp)
 {
-       unsigned int objnr = obj_to_index(cachep, page, objp);
+       unsigned int objnr = obj_to_index(cachep, slab, objp);
 #if DEBUG
        unsigned int i;
 
        /* Verify double free bug */
-       for (i = page->active; i < cachep->num; i++) {
-               if (get_free_obj(page, i) == objnr) {
+       for (i = slab->active; i < cachep->num; i++) {
+               if (get_free_obj(slab, i) == objnr) {
                        pr_err("slab: double free detected in cache '%s', objp %px\n",
                               cachep->name, objp);
                        BUG();
                }
        }
 #endif
-       page->active--;
-       if (!page->freelist)
-               page->freelist = objp + obj_offset(cachep);
-
-       set_free_obj(page, page->active, objnr);
-}
+       slab->active--;
+       if (!slab->freelist)
+               slab->freelist = objp + obj_offset(cachep);
 
-/*
- * Map pages beginning at addr to the given cache and slab. This is required
- * for the slab allocator to be able to lookup the cache and slab of a
- * virtual address for kfree, ksize, and slab debugging.
- */
-static void slab_map_pages(struct kmem_cache *cache, struct page *page,
-                          void *freelist)
-{
-       page->slab_cache = cache;
-       page->freelist = freelist;
+       set_free_obj(slab, slab->active, objnr);
 }
 
 /*
  * Grow (by 1) the number of slabs within a cache.  This is called by
  * kmem_cache_alloc() when there are no active objs left in a cache.
  */
-static struct page *cache_grow_begin(struct kmem_cache *cachep,
+static struct slab *cache_grow_begin(struct kmem_cache *cachep,
                                gfp_t flags, int nodeid)
 {
        void *freelist;
        size_t offset;
        gfp_t local_flags;
-       int page_node;
+       int slab_node;
        struct kmem_cache_node *n;
-       struct page *page;
+       struct slab *slab;
 
        /*
         * Be lazy and only check for valid flags here,  keeping it out of the
@@ -2590,12 +2581,12 @@ static struct page *cache_grow_begin(struct kmem_cache *cachep,
         * Get mem for the objs.  Attempt to allocate a physical page from
         * 'nodeid'.
         */
-       page = kmem_getpages(cachep, local_flags, nodeid);
-       if (!page)
+       slab = kmem_getpages(cachep, local_flags, nodeid);
+       if (!slab)
                goto failed;
 
-       page_node = page_to_nid(page);
-       n = get_node(cachep, page_node);
+       slab_node = slab_nid(slab);
+       n = get_node(cachep, slab_node);
 
        /* Get colour for the slab, and cal the next value. */
        n->colour_next++;
@@ -2613,54 +2604,55 @@ static struct page *cache_grow_begin(struct kmem_cache *cachep,
         * page_address() in the latter returns a non-tagged pointer,
         * as it should be for slab pages.
         */
-       kasan_poison_slab(page);
+       kasan_poison_slab(slab);
 
        /* Get slab management. */
-       freelist = alloc_slabmgmt(cachep, page, offset,
-                       local_flags & ~GFP_CONSTRAINT_MASK, page_node);
+       freelist = alloc_slabmgmt(cachep, slab, offset,
+                       local_flags & ~GFP_CONSTRAINT_MASK, slab_node);
        if (OFF_SLAB(cachep) && !freelist)
                goto opps1;
 
-       slab_map_pages(cachep, page, freelist);
+       slab->slab_cache = cachep;
+       slab->freelist = freelist;
 
-       cache_init_objs(cachep, page);
+       cache_init_objs(cachep, slab);
 
        if (gfpflags_allow_blocking(local_flags))
                local_irq_disable();
 
-       return page;
+       return slab;
 
 opps1:
-       kmem_freepages(cachep, page);
+       kmem_freepages(cachep, slab);
 failed:
        if (gfpflags_allow_blocking(local_flags))
                local_irq_disable();
        return NULL;
 }
 
-static void cache_grow_end(struct kmem_cache *cachep, struct page *page)
+static void cache_grow_end(struct kmem_cache *cachep, struct slab *slab)
 {
        struct kmem_cache_node *n;
        void *list = NULL;
 
        check_irq_off();
 
-       if (!page)
+       if (!slab)
                return;
 
-       INIT_LIST_HEAD(&page->slab_list);
-       n = get_node(cachep, page_to_nid(page));
+       INIT_LIST_HEAD(&slab->slab_list);
+       n = get_node(cachep, slab_nid(slab));
 
        spin_lock(&n->list_lock);
        n->total_slabs++;
-       if (!page->active) {
-               list_add_tail(&page->slab_list, &n->slabs_free);
+       if (!slab->active) {
+               list_add_tail(&slab->slab_list, &n->slabs_free);
                n->free_slabs++;
        } else
-               fixup_slab_list(cachep, n, page, &list);
+               fixup_slab_list(cachep, n, slab, &list);
 
        STATS_INC_GROWN(cachep);
-       n->free_objects += cachep->num - page->active;
+       n->free_objects += cachep->num - slab->active;
        spin_unlock(&n->list_lock);
 
        fixup_objfreelist_debug(cachep, &list);
@@ -2708,13 +2700,13 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
                                   unsigned long caller)
 {
        unsigned int objnr;
-       struct page *page;
+       struct slab *slab;
 
        BUG_ON(virt_to_cache(objp) != cachep);
 
        objp -= obj_offset(cachep);
        kfree_debugcheck(objp);
-       page = virt_to_head_page(objp);
+       slab = virt_to_slab(objp);
 
        if (cachep->flags & SLAB_RED_ZONE) {
                verify_redzone_free(cachep, objp);
@@ -2724,10 +2716,10 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
        if (cachep->flags & SLAB_STORE_USER)
                *dbg_userword(cachep, objp) = (void *)caller;
 
-       objnr = obj_to_index(cachep, page, objp);
+       objnr = obj_to_index(cachep, slab, objp);
 
        BUG_ON(objnr >= cachep->num);
-       BUG_ON(objp != index_to_obj(cachep, page, objnr));
+       BUG_ON(objp != index_to_obj(cachep, slab, objnr));
 
        if (cachep->flags & SLAB_POISON) {
                poison_obj(cachep, objp, POISON_FREE);
@@ -2757,97 +2749,97 @@ static inline void fixup_objfreelist_debug(struct kmem_cache *cachep,
 }
 
 static inline void fixup_slab_list(struct kmem_cache *cachep,
-                               struct kmem_cache_node *n, struct page *page,
+                               struct kmem_cache_node *n, struct slab *slab,
                                void **list)
 {
        /* move slabp to correct slabp list: */
-       list_del(&page->slab_list);
-       if (page->active == cachep->num) {
-               list_add(&page->slab_list, &n->slabs_full);
+       list_del(&slab->slab_list);
+       if (slab->active == cachep->num) {
+               list_add(&slab->slab_list, &n->slabs_full);
                if (OBJFREELIST_SLAB(cachep)) {
 #if DEBUG
                        /* Poisoning will be done without holding the lock */
                        if (cachep->flags & SLAB_POISON) {
-                               void **objp = page->freelist;
+                               void **objp = slab->freelist;
 
                                *objp = *list;
                                *list = objp;
                        }
 #endif
-                       page->freelist = NULL;
+                       slab->freelist = NULL;
                }
        } else
-               list_add(&page->slab_list, &n->slabs_partial);
+               list_add(&slab->slab_list, &n->slabs_partial);
 }
 
 /* Try to find non-pfmemalloc slab if needed */
-static noinline struct page *get_valid_first_slab(struct kmem_cache_node *n,
-                                       struct page *page, bool pfmemalloc)
+static noinline struct slab *get_valid_first_slab(struct kmem_cache_node *n,
+                                       struct slab *slab, bool pfmemalloc)
 {
-       if (!page)
+       if (!slab)
                return NULL;
 
        if (pfmemalloc)
-               return page;
+               return slab;
 
-       if (!PageSlabPfmemalloc(page))
-               return page;
+       if (!slab_test_pfmemalloc(slab))
+               return slab;
 
        /* No need to keep pfmemalloc slab if we have enough free objects */
        if (n->free_objects > n->free_limit) {
-               ClearPageSlabPfmemalloc(page);
-               return page;
+               slab_clear_pfmemalloc(slab);
+               return slab;
        }
 
        /* Move pfmemalloc slab to the end of list to speed up next search */
-       list_del(&page->slab_list);
-       if (!page->active) {
-               list_add_tail(&page->slab_list, &n->slabs_free);
+       list_del(&slab->slab_list);
+       if (!slab->active) {
+               list_add_tail(&slab->slab_list, &n->slabs_free);
                n->free_slabs++;
        } else
-               list_add_tail(&page->slab_list, &n->slabs_partial);
+               list_add_tail(&slab->slab_list, &n->slabs_partial);
 
-       list_for_each_entry(page, &n->slabs_partial, slab_list) {
-               if (!PageSlabPfmemalloc(page))
-                       return page;
+       list_for_each_entry(slab, &n->slabs_partial, slab_list) {
+               if (!slab_test_pfmemalloc(slab))
+                       return slab;
        }
 
        n->free_touched = 1;
-       list_for_each_entry(page, &n->slabs_free, slab_list) {
-               if (!PageSlabPfmemalloc(page)) {
+       list_for_each_entry(slab, &n->slabs_free, slab_list) {
+               if (!slab_test_pfmemalloc(slab)) {
                        n->free_slabs--;
-                       return page;
+                       return slab;
                }
        }
 
        return NULL;
 }
 
-static struct page *get_first_slab(struct kmem_cache_node *n, bool pfmemalloc)
+static struct slab *get_first_slab(struct kmem_cache_node *n, bool pfmemalloc)
 {
-       struct page *page;
+       struct slab *slab;
 
        assert_spin_locked(&n->list_lock);
-       page = list_first_entry_or_null(&n->slabs_partial, struct page,
+       slab = list_first_entry_or_null(&n->slabs_partial, struct slab,
                                        slab_list);
-       if (!page) {
+       if (!slab) {
                n->free_touched = 1;
-               page = list_first_entry_or_null(&n->slabs_free, struct page,
+               slab = list_first_entry_or_null(&n->slabs_free, struct slab,
                                                slab_list);
-               if (page)
+               if (slab)
                        n->free_slabs--;
        }
 
        if (sk_memalloc_socks())
-               page = get_valid_first_slab(n, page, pfmemalloc);
+               slab = get_valid_first_slab(n, slab, pfmemalloc);
 
-       return page;
+       return slab;
 }
 
 static noinline void *cache_alloc_pfmemalloc(struct kmem_cache *cachep,
                                struct kmem_cache_node *n, gfp_t flags)
 {
-       struct page *page;
+       struct slab *slab;
        void *obj;
        void *list = NULL;
 
@@ -2855,16 +2847,16 @@ static noinline void *cache_alloc_pfmemalloc(struct kmem_cache *cachep,
                return NULL;
 
        spin_lock(&n->list_lock);
-       page = get_first_slab(n, true);
-       if (!page) {
+       slab = get_first_slab(n, true);
+       if (!slab) {
                spin_unlock(&n->list_lock);
                return NULL;
        }
 
-       obj = slab_get_obj(cachep, page);
+       obj = slab_get_obj(cachep, slab);
        n->free_objects--;
 
-       fixup_slab_list(cachep, n, page, &list);
+       fixup_slab_list(cachep, n, slab, &list);
 
        spin_unlock(&n->list_lock);
        fixup_objfreelist_debug(cachep, &list);
@@ -2877,20 +2869,20 @@ static noinline void *cache_alloc_pfmemalloc(struct kmem_cache *cachep,
  * or cache_grow_end() for new slab
  */
 static __always_inline int alloc_block(struct kmem_cache *cachep,
-               struct array_cache *ac, struct page *page, int batchcount)
+               struct array_cache *ac, struct slab *slab, int batchcount)
 {
        /*
         * There must be at least one object available for
         * allocation.
         */
-       BUG_ON(page->active >= cachep->num);
+       BUG_ON(slab->active >= cachep->num);
 
-       while (page->active < cachep->num && batchcount--) {
+       while (slab->active < cachep->num && batchcount--) {
                STATS_INC_ALLOCED(cachep);
                STATS_INC_ACTIVE(cachep);
                STATS_SET_HIGH(cachep);
 
-               ac->entry[ac->avail++] = slab_get_obj(cachep, page);
+               ac->entry[ac->avail++] = slab_get_obj(cachep, slab);
        }
 
        return batchcount;
@@ -2903,7 +2895,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
        struct array_cache *ac, *shared;
        int node;
        void *list = NULL;
-       struct page *page;
+       struct slab *slab;
 
        check_irq_off();
        node = numa_mem_id();
@@ -2936,14 +2928,14 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
 
        while (batchcount > 0) {
                /* Get slab alloc is to come from. */
-               page = get_first_slab(n, false);
-               if (!page)
+               slab = get_first_slab(n, false);
+               if (!slab)
                        goto must_grow;
 
                check_spinlock_acquired(cachep);
 
-               batchcount = alloc_block(cachep, ac, page, batchcount);
-               fixup_slab_list(cachep, n, page, &list);
+               batchcount = alloc_block(cachep, ac, slab, batchcount);
+               fixup_slab_list(cachep, n, slab, &list);
        }
 
 must_grow:
@@ -2962,16 +2954,16 @@ direct_grow:
                                return obj;
                }
 
-               page = cache_grow_begin(cachep, gfp_exact_node(flags), node);
+               slab = cache_grow_begin(cachep, gfp_exact_node(flags), node);
 
                /*
                 * cache_grow_begin() can reenable interrupts,
                 * then ac could change.
                 */
                ac = cpu_cache_get(cachep);
-               if (!ac->avail && page)
-                       alloc_block(cachep, ac, page, batchcount);
-               cache_grow_end(cachep, page);
+               if (!ac->avail && slab)
+                       alloc_block(cachep, ac, slab, batchcount);
+               cache_grow_end(cachep, slab);
 
                if (!ac->avail)
                        return NULL;
@@ -3101,7 +3093,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
        struct zone *zone;
        enum zone_type highest_zoneidx = gfp_zone(flags);
        void *obj = NULL;
-       struct page *page;
+       struct slab *slab;
        int nid;
        unsigned int cpuset_mems_cookie;
 
@@ -3137,10 +3129,10 @@ retry:
                 * We may trigger various forms of reclaim on the allowed
                 * set and go into memory reserves if necessary.
                 */
-               page = cache_grow_begin(cache, flags, numa_mem_id());
-               cache_grow_end(cache, page);
-               if (page) {
-                       nid = page_to_nid(page);
+               slab = cache_grow_begin(cache, flags, numa_mem_id());
+               cache_grow_end(cache, slab);
+               if (slab) {
+                       nid = slab_nid(slab);
                        obj = ____cache_alloc_node(cache,
                                gfp_exact_node(flags), nid);
 
@@ -3164,7 +3156,7 @@ retry:
 static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
                                int nodeid)
 {
-       struct page *page;
+       struct slab *slab;
        struct kmem_cache_node *n;
        void *obj = NULL;
        void *list = NULL;
@@ -3175,8 +3167,8 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
 
        check_irq_off();
        spin_lock(&n->list_lock);
-       page = get_first_slab(n, false);
-       if (!page)
+       slab = get_first_slab(n, false);
+       if (!slab)
                goto must_grow;
 
        check_spinlock_acquired_node(cachep, nodeid);
@@ -3185,12 +3177,12 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
        STATS_INC_ACTIVE(cachep);
        STATS_SET_HIGH(cachep);
 
-       BUG_ON(page->active == cachep->num);
+       BUG_ON(slab->active == cachep->num);
 
-       obj = slab_get_obj(cachep, page);
+       obj = slab_get_obj(cachep, slab);
        n->free_objects--;
 
-       fixup_slab_list(cachep, n, page, &list);
+       fixup_slab_list(cachep, n, slab, &list);
 
        spin_unlock(&n->list_lock);
        fixup_objfreelist_debug(cachep, &list);
@@ -3198,12 +3190,12 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
 
 must_grow:
        spin_unlock(&n->list_lock);
-       page = cache_grow_begin(cachep, gfp_exact_node(flags), nodeid);
-       if (page) {
+       slab = cache_grow_begin(cachep, gfp_exact_node(flags), nodeid);
+       if (slab) {
                /* This slab isn't counted yet so don't update free_objects */
-               obj = slab_get_obj(cachep, page);
+               obj = slab_get_obj(cachep, slab);
        }
-       cache_grow_end(cachep, page);
+       cache_grow_end(cachep, slab);
 
        return obj ? obj : fallback_alloc(cachep, flags);
 }
@@ -3333,40 +3325,40 @@ static void free_block(struct kmem_cache *cachep, void **objpp,
 {
        int i;
        struct kmem_cache_node *n = get_node(cachep, node);
-       struct page *page;
+       struct slab *slab;
 
        n->free_objects += nr_objects;
 
        for (i = 0; i < nr_objects; i++) {
                void *objp;
-               struct page *page;
+               struct slab *slab;
 
                objp = objpp[i];
 
-               page = virt_to_head_page(objp);
-               list_del(&page->slab_list);
+               slab = virt_to_slab(objp);
+               list_del(&slab->slab_list);
                check_spinlock_acquired_node(cachep, node);
-               slab_put_obj(cachep, page, objp);
+               slab_put_obj(cachep, slab, objp);
                STATS_DEC_ACTIVE(cachep);
 
                /* fixup slab chains */
-               if (page->active == 0) {
-                       list_add(&page->slab_list, &n->slabs_free);
+               if (slab->active == 0) {
+                       list_add(&slab->slab_list, &n->slabs_free);
                        n->free_slabs++;
                } else {
                        /* Unconditionally move a slab to the end of the
                         * partial list on free - maximum time for the
                         * other objects to be freed, too.
                         */
-                       list_add_tail(&page->slab_list, &n->slabs_partial);
+                       list_add_tail(&slab->slab_list, &n->slabs_partial);
                }
        }
 
        while (n->free_objects > n->free_limit && !list_empty(&n->slabs_free)) {
                n->free_objects -= cachep->num;
 
-               page = list_last_entry(&n->slabs_free, struct page, slab_list);
-               list_move(&page->slab_list, list);
+               slab = list_last_entry(&n->slabs_free, struct slab, slab_list);
+               list_move(&slab->slab_list, list);
                n->free_slabs--;
                n->total_slabs--;
        }
@@ -3402,10 +3394,10 @@ free_done:
 #if STATS
        {
                int i = 0;
-               struct page *page;
+               struct slab *slab;
 
-               list_for_each_entry(page, &n->slabs_free, slab_list) {
-                       BUG_ON(page->active);
+               list_for_each_entry(slab, &n->slabs_free, slab_list) {
+                       BUG_ON(slab->active);
 
                        i++;
                }
@@ -3481,10 +3473,10 @@ void ___cache_free(struct kmem_cache *cachep, void *objp,
        }
 
        if (sk_memalloc_socks()) {
-               struct page *page = virt_to_head_page(objp);
+               struct slab *slab = virt_to_slab(objp);
 
-               if (unlikely(PageSlabPfmemalloc(page))) {
-                       cache_free_pfmemalloc(cachep, page, objp);
+               if (unlikely(slab_test_pfmemalloc(slab))) {
+                       cache_free_pfmemalloc(cachep, slab, objp);
                        return;
                }
        }
@@ -3657,21 +3649,21 @@ EXPORT_SYMBOL(__kmalloc_node_track_caller);
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_PRINTK
-void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
+void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct slab *slab)
 {
        struct kmem_cache *cachep;
        unsigned int objnr;
        void *objp;
 
        kpp->kp_ptr = object;
-       kpp->kp_page = page;
-       cachep = page->slab_cache;
+       kpp->kp_slab = slab;
+       cachep = slab->slab_cache;
        kpp->kp_slab_cache = cachep;
        objp = object - obj_offset(cachep);
        kpp->kp_data_offset = obj_offset(cachep);
-       page = virt_to_head_page(objp);
-       objnr = obj_to_index(cachep, page, objp);
-       objp = index_to_obj(cachep, page, objnr);
+       slab = virt_to_slab(objp);
+       objnr = obj_to_index(cachep, slab, objp);
+       objp = index_to_obj(cachep, slab, objnr);
        kpp->kp_objp = objp;
        if (DEBUG && cachep->flags & SLAB_STORE_USER)
                kpp->kp_ret = *dbg_userword(cachep, objp);
@@ -4177,8 +4169,8 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
  * Returns NULL if check passes, otherwise const char * to name of cache
  * to indicate an error.
  */
-void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
-                        bool to_user)
+void __check_heap_object(const void *ptr, unsigned long n,
+                        const struct slab *slab, bool to_user)
 {
        struct kmem_cache *cachep;
        unsigned int objnr;
@@ -4187,15 +4179,15 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
        ptr = kasan_reset_tag(ptr);
 
        /* Find and validate object. */
-       cachep = page->slab_cache;
-       objnr = obj_to_index(cachep, page, (void *)ptr);
+       cachep = slab->slab_cache;
+       objnr = obj_to_index(cachep, slab, (void *)ptr);
        BUG_ON(objnr >= cachep->num);
 
        /* Find offset within object. */
        if (is_kfence_address(ptr))
                offset = ptr - kfence_object_start(ptr);
        else
-               offset = ptr - index_to_obj(cachep, page, objnr) - obj_offset(cachep);
+               offset = ptr - index_to_obj(cachep, slab, objnr) - obj_offset(cachep);
 
        /* Allow address range falling entirely within usercopy region. */
        if (offset >= cachep->useroffset &&
index 56ad7ee..95b9a74 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -5,6 +5,197 @@
  * Internal slab definitions
  */
 
+/* Reuses the bits in struct page */
+struct slab {
+       unsigned long __page_flags;
+
+#if defined(CONFIG_SLAB)
+
+       union {
+               struct list_head slab_list;
+               struct rcu_head rcu_head;
+       };
+       struct kmem_cache *slab_cache;
+       void *freelist; /* array of free object indexes */
+       void *s_mem;    /* first object */
+       unsigned int active;
+
+#elif defined(CONFIG_SLUB)
+
+       union {
+               struct list_head slab_list;
+               struct rcu_head rcu_head;
+#ifdef CONFIG_SLUB_CPU_PARTIAL
+               struct {
+                       struct slab *next;
+                       int slabs;      /* Nr of slabs left */
+               };
+#endif
+       };
+       struct kmem_cache *slab_cache;
+       /* Double-word boundary */
+       void *freelist;         /* first free object */
+       union {
+               unsigned long counters;
+               struct {
+                       unsigned inuse:16;
+                       unsigned objects:15;
+                       unsigned frozen:1;
+               };
+       };
+       unsigned int __unused;
+
+#elif defined(CONFIG_SLOB)
+
+       struct list_head slab_list;
+       void *__unused_1;
+       void *freelist;         /* first free block */
+       long units;
+       unsigned int __unused_2;
+
+#else
+#error "Unexpected slab allocator configured"
+#endif
+
+       atomic_t __page_refcount;
+#ifdef CONFIG_MEMCG
+       unsigned long memcg_data;
+#endif
+};
+
+#define SLAB_MATCH(pg, sl)                                             \
+       static_assert(offsetof(struct page, pg) == offsetof(struct slab, sl))
+SLAB_MATCH(flags, __page_flags);
+SLAB_MATCH(compound_head, slab_list);  /* Ensure bit 0 is clear */
+SLAB_MATCH(slab_list, slab_list);
+#ifndef CONFIG_SLOB
+SLAB_MATCH(rcu_head, rcu_head);
+SLAB_MATCH(slab_cache, slab_cache);
+#endif
+#ifdef CONFIG_SLAB
+SLAB_MATCH(s_mem, s_mem);
+SLAB_MATCH(active, active);
+#endif
+SLAB_MATCH(_refcount, __page_refcount);
+#ifdef CONFIG_MEMCG
+SLAB_MATCH(memcg_data, memcg_data);
+#endif
+#undef SLAB_MATCH
+static_assert(sizeof(struct slab) <= sizeof(struct page));
+
+/**
+ * folio_slab - Converts from folio to slab.
+ * @folio: The folio.
+ *
+ * Currently struct slab is a different representation of a folio where
+ * folio_test_slab() is true.
+ *
+ * Return: The slab which contains this folio.
+ */
+#define folio_slab(folio)      (_Generic((folio),                      \
+       const struct folio *:   (const struct slab *)(folio),           \
+       struct folio *:         (struct slab *)(folio)))
+
+/**
+ * slab_folio - The folio allocated for a slab
+ * @slab: The slab.
+ *
+ * Slabs are allocated as folios that contain the individual objects and are
+ * using some fields in the first struct page of the folio - those fields are
+ * now accessed by struct slab. It is occasionally necessary to convert back to
+ * a folio in order to communicate with the rest of the mm.  Please use this
+ * helper function instead of casting yourself, as the implementation may change
+ * in the future.
+ */
+#define slab_folio(s)          (_Generic((s),                          \
+       const struct slab *:    (const struct folio *)s,                \
+       struct slab *:          (struct folio *)s))
+
+/**
+ * page_slab - Converts from first struct page to slab.
+ * @p: The first (either head of compound or single) page of slab.
+ *
+ * A temporary wrapper to convert struct page to struct slab in situations where
+ * we know the page is the compound head, or single order-0 page.
+ *
+ * Long-term ideally everything would work with struct slab directly or go
+ * through folio to struct slab.
+ *
+ * Return: The slab which contains this page
+ */
+#define page_slab(p)           (_Generic((p),                          \
+       const struct page *:    (const struct slab *)(p),               \
+       struct page *:          (struct slab *)(p)))
+
+/**
+ * slab_page - The first struct page allocated for a slab
+ * @slab: The slab.
+ *
+ * A convenience wrapper for converting slab to the first struct page of the
+ * underlying folio, to communicate with code not yet converted to folio or
+ * struct slab.
+ */
+#define slab_page(s) folio_page(slab_folio(s), 0)
+
+/*
+ * If network-based swap is enabled, sl*b must keep track of whether pages
+ * were allocated from pfmemalloc reserves.
+ */
+static inline bool slab_test_pfmemalloc(const struct slab *slab)
+{
+       return folio_test_active((struct folio *)slab_folio(slab));
+}
+
+static inline void slab_set_pfmemalloc(struct slab *slab)
+{
+       folio_set_active(slab_folio(slab));
+}
+
+static inline void slab_clear_pfmemalloc(struct slab *slab)
+{
+       folio_clear_active(slab_folio(slab));
+}
+
+static inline void __slab_clear_pfmemalloc(struct slab *slab)
+{
+       __folio_clear_active(slab_folio(slab));
+}
+
+static inline void *slab_address(const struct slab *slab)
+{
+       return folio_address(slab_folio(slab));
+}
+
+static inline int slab_nid(const struct slab *slab)
+{
+       return folio_nid(slab_folio(slab));
+}
+
+static inline pg_data_t *slab_pgdat(const struct slab *slab)
+{
+       return folio_pgdat(slab_folio(slab));
+}
+
+static inline struct slab *virt_to_slab(const void *addr)
+{
+       struct folio *folio = virt_to_folio(addr);
+
+       if (!folio_test_slab(folio))
+               return NULL;
+
+       return folio_slab(folio);
+}
+
+static inline int slab_order(const struct slab *slab)
+{
+       return folio_order((struct folio *)slab_folio(slab));
+}
+
+static inline size_t slab_size(const struct slab *slab)
+{
+       return PAGE_SIZE << slab_order(slab);
+}
+
 #ifdef CONFIG_SLOB
 /*
  * Common fields provided in kmem_cache by all slab allocators
@@ -245,15 +436,33 @@ static inline bool kmem_cache_debug_flags(struct kmem_cache *s, slab_flags_t fla
 }
 
 #ifdef CONFIG_MEMCG_KMEM
-int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
-                                gfp_t gfp, bool new_page);
+/*
+ * slab_objcgs - get the object cgroups vector associated with a slab
+ * @slab: a pointer to the slab struct
+ *
+ * Returns a pointer to the object cgroups vector associated with the slab,
+ * or NULL if no such vector has been associated yet.
+ */
+static inline struct obj_cgroup **slab_objcgs(struct slab *slab)
+{
+       unsigned long memcg_data = READ_ONCE(slab->memcg_data);
+
+       VM_BUG_ON_PAGE(memcg_data && !(memcg_data & MEMCG_DATA_OBJCGS),
+                                                       slab_page(slab));
+       VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, slab_page(slab));
+
+       return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
+}
+
+int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s,
+                                gfp_t gfp, bool new_slab);
 void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
                     enum node_stat_item idx, int nr);
 
-static inline void memcg_free_page_obj_cgroups(struct page *page)
+static inline void memcg_free_slab_cgroups(struct slab *slab)
 {
-       kfree(page_objcgs(page));
-       page->memcg_data = 0;
+       kfree(slab_objcgs(slab));
+       slab->memcg_data = 0;
 }
 
 static inline size_t obj_full_size(struct kmem_cache *s)
@@ -298,7 +507,7 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
                                              gfp_t flags, size_t size,
                                              void **p)
 {
-       struct page *page;
+       struct slab *slab;
        unsigned long off;
        size_t i;
 
@@ -307,19 +516,19 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
 
        for (i = 0; i < size; i++) {
                if (likely(p[i])) {
-                       page = virt_to_head_page(p[i]);
+                       slab = virt_to_slab(p[i]);
 
-                       if (!page_objcgs(page) &&
-                           memcg_alloc_page_obj_cgroups(page, s, flags,
+                       if (!slab_objcgs(slab) &&
+                           memcg_alloc_slab_cgroups(slab, s, flags,
                                                         false)) {
                                obj_cgroup_uncharge(objcg, obj_full_size(s));
                                continue;
                        }
 
-                       off = obj_to_index(s, page, p[i]);
+                       off = obj_to_index(s, slab, p[i]);
                        obj_cgroup_get(objcg);
-                       page_objcgs(page)[off] = objcg;
-                       mod_objcg_state(objcg, page_pgdat(page),
+                       slab_objcgs(slab)[off] = objcg;
+                       mod_objcg_state(objcg, slab_pgdat(slab),
                                        cache_vmstat_idx(s), obj_full_size(s));
                } else {
                        obj_cgroup_uncharge(objcg, obj_full_size(s));
@@ -334,7 +543,7 @@ static inline void memcg_slab_free_hook(struct kmem_cache *s_orig,
        struct kmem_cache *s;
        struct obj_cgroup **objcgs;
        struct obj_cgroup *objcg;
-       struct page *page;
+       struct slab *slab;
        unsigned int off;
        int i;
 
@@ -345,43 +554,52 @@ static inline void memcg_slab_free_hook(struct kmem_cache *s_orig,
                if (unlikely(!p[i]))
                        continue;
 
-               page = virt_to_head_page(p[i]);
-               objcgs = page_objcgs_check(page);
+               slab = virt_to_slab(p[i]);
+               /* we could be given a kmalloc_large() object, skip those */
+               if (!slab)
+                       continue;
+
+               objcgs = slab_objcgs(slab);
                if (!objcgs)
                        continue;
 
                if (!s_orig)
-                       s = page->slab_cache;
+                       s = slab->slab_cache;
                else
                        s = s_orig;
 
-               off = obj_to_index(s, page, p[i]);
+               off = obj_to_index(s, slab, p[i]);
                objcg = objcgs[off];
                if (!objcg)
                        continue;
 
                objcgs[off] = NULL;
                obj_cgroup_uncharge(objcg, obj_full_size(s));
-               mod_objcg_state(objcg, page_pgdat(page), cache_vmstat_idx(s),
+               mod_objcg_state(objcg, slab_pgdat(slab), cache_vmstat_idx(s),
                                -obj_full_size(s));
                obj_cgroup_put(objcg);
        }
 }
 
 #else /* CONFIG_MEMCG_KMEM */
+static inline struct obj_cgroup **slab_objcgs(struct slab *slab)
+{
+       return NULL;
+}
+
 static inline struct mem_cgroup *memcg_from_slab_obj(void *ptr)
 {
        return NULL;
 }
 
-static inline int memcg_alloc_page_obj_cgroups(struct page *page,
+static inline int memcg_alloc_slab_cgroups(struct slab *slab,
                                               struct kmem_cache *s, gfp_t gfp,
-                                              bool new_page)
+                                              bool new_slab)
 {
        return 0;
 }
 
-static inline void memcg_free_page_obj_cgroups(struct page *page)
+static inline void memcg_free_slab_cgroups(struct slab *slab)
 {
 }
 
@@ -405,35 +623,35 @@ static inline void memcg_slab_free_hook(struct kmem_cache *s,
 }
 #endif /* CONFIG_MEMCG_KMEM */
 
+#ifndef CONFIG_SLOB
 static inline struct kmem_cache *virt_to_cache(const void *obj)
 {
-       struct page *page;
+       struct slab *slab;
 
-       page = virt_to_head_page(obj);
-       if (WARN_ONCE(!PageSlab(page), "%s: Object is not a Slab page!\n",
+       slab = virt_to_slab(obj);
+       if (WARN_ONCE(!slab, "%s: Object is not a Slab page!\n",
                                        __func__))
                return NULL;
-       return page->slab_cache;
+       return slab->slab_cache;
 }
 
-static __always_inline void account_slab_page(struct page *page, int order,
-                                             struct kmem_cache *s,
-                                             gfp_t gfp)
+static __always_inline void account_slab(struct slab *slab, int order,
+                                        struct kmem_cache *s, gfp_t gfp)
 {
        if (memcg_kmem_enabled() && (s->flags & SLAB_ACCOUNT))
-               memcg_alloc_page_obj_cgroups(page, s, gfp, true);
+               memcg_alloc_slab_cgroups(slab, s, gfp, true);
 
-       mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
+       mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
                            PAGE_SIZE << order);
 }
 
-static __always_inline void unaccount_slab_page(struct page *page, int order,
-                                               struct kmem_cache *s)
+static __always_inline void unaccount_slab(struct slab *slab, int order,
+                                          struct kmem_cache *s)
 {
        if (memcg_kmem_enabled())
-               memcg_free_page_obj_cgroups(page);
+               memcg_free_slab_cgroups(slab);
 
-       mod_node_page_state(page_pgdat(page), cache_vmstat_idx(s),
+       mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
                            -(PAGE_SIZE << order));
 }
 
@@ -452,6 +670,7 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
                print_tracking(cachep, x);
        return cachep;
 }
+#endif /* CONFIG_SLOB */
 
 static inline size_t slab_ksize(const struct kmem_cache *s)
 {
@@ -635,7 +854,7 @@ static inline void debugfs_slab_release(struct kmem_cache *s) { }
 #define KS_ADDRS_COUNT 16
 struct kmem_obj_info {
        void *kp_ptr;
-       struct page *kp_page;
+       struct slab *kp_slab;
        void *kp_objp;
        unsigned long kp_data_offset;
        struct kmem_cache *kp_slab_cache;
@@ -643,7 +862,18 @@ struct kmem_obj_info {
        void *kp_stack[KS_ADDRS_COUNT];
        void *kp_free_stack[KS_ADDRS_COUNT];
 };
-void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page);
+void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct slab *slab);
+#endif
+
+#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR
+void __check_heap_object(const void *ptr, unsigned long n,
+                        const struct slab *slab, bool to_user);
+#else
+static inline
+void __check_heap_object(const void *ptr, unsigned long n,
+                        const struct slab *slab, bool to_user)
+{
+}
 #endif
 
 #endif /* MM_SLAB_H */
index e5d080a..dc15566 100644 (file)
@@ -550,13 +550,13 @@ bool slab_is_available(void)
  */
 bool kmem_valid_obj(void *object)
 {
-       struct page *page;
+       struct folio *folio;
 
        /* Some arches consider ZERO_SIZE_PTR to be a valid address. */
        if (object < (void *)PAGE_SIZE || !virt_addr_valid(object))
                return false;
-       page = virt_to_head_page(object);
-       return PageSlab(page);
+       folio = virt_to_folio(object);
+       return folio_test_slab(folio);
 }
 EXPORT_SYMBOL_GPL(kmem_valid_obj);
 
@@ -579,18 +579,18 @@ void kmem_dump_obj(void *object)
 {
        char *cp = IS_ENABLED(CONFIG_MMU) ? "" : "/vmalloc";
        int i;
-       struct page *page;
+       struct slab *slab;
        unsigned long ptroffset;
        struct kmem_obj_info kp = { };
 
        if (WARN_ON_ONCE(!virt_addr_valid(object)))
                return;
-       page = virt_to_head_page(object);
-       if (WARN_ON_ONCE(!PageSlab(page))) {
+       slab = virt_to_slab(object);
+       if (WARN_ON_ONCE(!slab)) {
                pr_cont(" non-slab memory.\n");
                return;
        }
-       kmem_obj_info(&kp, object, page);
+       kmem_obj_info(&kp, object, slab);
        if (kp.kp_slab_cache)
                pr_cont(" slab%s %s", cp, kp.kp_slab_cache->name);
        else
index 03deee1..60c5842 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -30,7 +30,7 @@
  * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls
  * alloc_pages() directly, allocating compound pages so the page order
  * does not have to be separately tracked.
- * These objects are detected in kfree() because PageSlab()
+ * These objects are detected in kfree() because folio_test_slab()
  * is false for them.
  *
  * SLAB is emulated on top of SLOB by simply calling constructors and
@@ -105,21 +105,21 @@ static LIST_HEAD(free_slob_large);
 /*
  * slob_page_free: true for pages on free_slob_pages list.
  */
-static inline int slob_page_free(struct page *sp)
+static inline int slob_page_free(struct slab *slab)
 {
-       return PageSlobFree(sp);
+       return PageSlobFree(slab_page(slab));
 }
 
-static void set_slob_page_free(struct page *sp, struct list_head *list)
+static void set_slob_page_free(struct slab *slab, struct list_head *list)
 {
-       list_add(&sp->slab_list, list);
-       __SetPageSlobFree(sp);
+       list_add(&slab->slab_list, list);
+       __SetPageSlobFree(slab_page(slab));
 }
 
-static inline void clear_slob_page_free(struct page *sp)
+static inline void clear_slob_page_free(struct slab *slab)
 {
-       list_del(&sp->slab_list);
-       __ClearPageSlobFree(sp);
+       list_del(&slab->slab_list);
+       __ClearPageSlobFree(slab_page(slab));
 }
 
 #define SLOB_UNIT sizeof(slob_t)
@@ -234,7 +234,7 @@ static void slob_free_pages(void *b, int order)
  *         freelist, in this case @page_removed_from_list will be set to
  *         true (set to false otherwise).
  */
-static void *slob_page_alloc(struct page *sp, size_t size, int align,
+static void *slob_page_alloc(struct slab *sp, size_t size, int align,
                              int align_offset, bool *page_removed_from_list)
 {
        slob_t *prev, *cur, *aligned = NULL;
@@ -301,7 +301,8 @@ static void *slob_page_alloc(struct page *sp, size_t size, int align,
 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node,
                                                        int align_offset)
 {
-       struct page *sp;
+       struct folio *folio;
+       struct slab *sp;
        struct list_head *slob_list;
        slob_t *b = NULL;
        unsigned long flags;
@@ -323,7 +324,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node,
                 * If there's a node specification, search for a partial
                 * page with a matching node id in the freelist.
                 */
-               if (node != NUMA_NO_NODE && page_to_nid(sp) != node)
+               if (node != NUMA_NO_NODE && slab_nid(sp) != node)
                        continue;
 #endif
                /* Enough room on this page? */
@@ -358,8 +359,9 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node,
                b = slob_new_pages(gfp & ~__GFP_ZERO, 0, node);
                if (!b)
                        return NULL;
-               sp = virt_to_page(b);
-               __SetPageSlab(sp);
+               folio = virt_to_folio(b);
+               __folio_set_slab(folio);
+               sp = folio_slab(folio);
 
                spin_lock_irqsave(&slob_lock, flags);
                sp->units = SLOB_UNITS(PAGE_SIZE);
@@ -381,7 +383,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node,
  */
 static void slob_free(void *block, int size)
 {
-       struct page *sp;
+       struct slab *sp;
        slob_t *prev, *next, *b = (slob_t *)block;
        slobidx_t units;
        unsigned long flags;
@@ -391,7 +393,7 @@ static void slob_free(void *block, int size)
                return;
        BUG_ON(!size);
 
-       sp = virt_to_page(block);
+       sp = virt_to_slab(block);
        units = SLOB_UNITS(size);
 
        spin_lock_irqsave(&slob_lock, flags);
@@ -401,8 +403,7 @@ static void slob_free(void *block, int size)
                if (slob_page_free(sp))
                        clear_slob_page_free(sp);
                spin_unlock_irqrestore(&slob_lock, flags);
-               __ClearPageSlab(sp);
-               page_mapcount_reset(sp);
+               __folio_clear_slab(slab_folio(sp));
                slob_free_pages(b, 0);
                return;
        }
@@ -462,10 +463,10 @@ out:
 }
 
 #ifdef CONFIG_PRINTK
-void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
+void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct slab *slab)
 {
        kpp->kp_ptr = object;
-       kpp->kp_page = page;
+       kpp->kp_slab = slab;
 }
 #endif
 
@@ -544,7 +545,7 @@ EXPORT_SYMBOL(__kmalloc_node_track_caller);
 
 void kfree(const void *block)
 {
-       struct page *sp;
+       struct folio *sp;
 
        trace_kfree(_RET_IP_, block);
 
@@ -552,16 +553,17 @@ void kfree(const void *block)
                return;
        kmemleak_free(block);
 
-       sp = virt_to_page(block);
-       if (PageSlab(sp)) {
+       sp = virt_to_folio(block);
+       if (folio_test_slab(sp)) {
                int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
                unsigned int *m = (unsigned int *)(block - align);
                slob_free(m, *m + align);
        } else {
-               unsigned int order = compound_order(sp);
-               mod_node_page_state(page_pgdat(sp), NR_SLAB_UNRECLAIMABLE_B,
+               unsigned int order = folio_order(sp);
+
+               mod_node_page_state(folio_pgdat(sp), NR_SLAB_UNRECLAIMABLE_B,
                                    -(PAGE_SIZE << order));
-               __free_pages(sp, order);
+               __free_pages(folio_page(sp, 0), order);
 
        }
 }
@@ -570,7 +572,7 @@ EXPORT_SYMBOL(kfree);
 /* can't use ksize for kmem_cache_alloc memory, only kmalloc */
 size_t __ksize(const void *block)
 {
-       struct page *sp;
+       struct folio *folio;
        int align;
        unsigned int *m;
 
@@ -578,9 +580,9 @@ size_t __ksize(const void *block)
        if (unlikely(block == ZERO_SIZE_PTR))
                return 0;
 
-       sp = virt_to_page(block);
-       if (unlikely(!PageSlab(sp)))
-               return page_size(sp);
+       folio = virt_to_folio(block);
+       if (unlikely(!folio_test_slab(folio)))
+               return folio_size(folio);
 
        align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
        m = (unsigned int *)(block - align);
index a862682..2614740 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -48,7 +48,7 @@
  *   1. slab_mutex (Global Mutex)
  *   2. node->list_lock (Spinlock)
  *   3. kmem_cache->cpu_slab->lock (Local lock)
- *   4. slab_lock(page) (Only on some arches or for debugging)
+ *   4. slab_lock(slab) (Only on some arches or for debugging)
  *   5. object_map_lock (Only for debugging)
  *
  *   slab_mutex
  *
  *   The slab_lock is only used for debugging and on arches that do not
  *   have the ability to do a cmpxchg_double. It only protects:
- *     A. page->freelist       -> List of object free in a page
- *     B. page->inuse          -> Number of objects in use
- *     C. page->objects        -> Number of objects in page
- *     D. page->frozen         -> frozen state
+ *     A. slab->freelist       -> List of free objects in a slab
+ *     B. slab->inuse          -> Number of objects in use
+ *     C. slab->objects        -> Number of objects in slab
+ *     D. slab->frozen         -> frozen state
  *
  *   Frozen slabs
  *
  *   If a slab is frozen then it is exempt from list management. It is not
  *   on any list except per cpu partial list. The processor that froze the
- *   slab is the one who can perform list operations on the page. Other
+ *   slab is the one who can perform list operations on the slab. Other
  *   processors may put objects onto the freelist but the processor that
  *   froze the slab is the only one that can retrieve the objects from the
- *   page's freelist.
+ *   slab's freelist.
  *
  *   list_lock
  *
  * minimal so we rely on the page allocators per cpu caches for
  * fast frees and allocs.
  *
- * page->frozen                The slab is frozen and exempt from list processing.
+ * slab->frozen                The slab is frozen and exempt from list processing.
  *                     This means that the slab is dedicated to a purpose
  *                     such as satisfying allocations for a specific
  *                     processor. Objects may be freed in the slab while
@@ -250,7 +250,7 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
 
 #define OO_SHIFT       16
 #define OO_MASK                ((1 << OO_SHIFT) - 1)
-#define MAX_OBJS_PER_PAGE      32767 /* since page.objects is u15 */
+#define MAX_OBJS_PER_PAGE      32767 /* since slab.objects is u15 */
 
 /* Internal SLUB flags */
 /* Poison object */
@@ -417,18 +417,18 @@ static inline unsigned int oo_objects(struct kmem_cache_order_objects x)
 #ifdef CONFIG_SLUB_CPU_PARTIAL
 static void slub_set_cpu_partial(struct kmem_cache *s, unsigned int nr_objects)
 {
-       unsigned int nr_pages;
+       unsigned int nr_slabs;
 
        s->cpu_partial = nr_objects;
 
        /*
         * We take the number of objects but actually limit the number of
-        * pages on the per cpu partial list, in order to limit excessive
-        * growth of the list. For simplicity we assume that the pages will
+        * slabs on the per cpu partial list, in order to limit excessive
+        * growth of the list. For simplicity we assume that the slabs will
         * be half-full.
         */
-       nr_pages = DIV_ROUND_UP(nr_objects * 2, oo_objects(s->oo));
-       s->cpu_partial_pages = nr_pages;
+       nr_slabs = DIV_ROUND_UP(nr_objects * 2, oo_objects(s->oo));
+       s->cpu_partial_slabs = nr_slabs;
 }
 #else
 static inline void
@@ -440,28 +440,32 @@ slub_set_cpu_partial(struct kmem_cache *s, unsigned int nr_objects)
 /*
  * Per slab locking using the pagelock
  */
-static __always_inline void __slab_lock(struct page *page)
+static __always_inline void __slab_lock(struct slab *slab)
 {
+       struct page *page = slab_page(slab);
+
        VM_BUG_ON_PAGE(PageTail(page), page);
        bit_spin_lock(PG_locked, &page->flags);
 }
 
-static __always_inline void __slab_unlock(struct page *page)
+static __always_inline void __slab_unlock(struct slab *slab)
 {
+       struct page *page = slab_page(slab);
+
        VM_BUG_ON_PAGE(PageTail(page), page);
        __bit_spin_unlock(PG_locked, &page->flags);
 }
 
-static __always_inline void slab_lock(struct page *page, unsigned long *flags)
+static __always_inline void slab_lock(struct slab *slab, unsigned long *flags)
 {
        if (IS_ENABLED(CONFIG_PREEMPT_RT))
                local_irq_save(*flags);
-       __slab_lock(page);
+       __slab_lock(slab);
 }
 
-static __always_inline void slab_unlock(struct page *page, unsigned long *flags)
+static __always_inline void slab_unlock(struct slab *slab, unsigned long *flags)
 {
-       __slab_unlock(page);
+       __slab_unlock(slab);
        if (IS_ENABLED(CONFIG_PREEMPT_RT))
                local_irq_restore(*flags);
 }
@@ -471,7 +475,7 @@ static __always_inline void slab_unlock(struct page *page, unsigned long *flags)
  * by an _irqsave() lock variant. Except on PREEMPT_RT where locks are different
  * so we disable interrupts as part of slab_[un]lock().
  */
-static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct slab *slab,
                void *freelist_old, unsigned long counters_old,
                void *freelist_new, unsigned long counters_new,
                const char *n)
@@ -481,7 +485,7 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
 #if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
     defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (s->flags & __CMPXCHG_DOUBLE) {
-               if (cmpxchg_double(&page->freelist, &page->counters,
+               if (cmpxchg_double(&slab->freelist, &slab->counters,
                                   freelist_old, counters_old,
                                   freelist_new, counters_new))
                        return true;
@@ -491,15 +495,15 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
                /* init to 0 to prevent spurious warnings */
                unsigned long flags = 0;
 
-               slab_lock(page, &flags);
-               if (page->freelist == freelist_old &&
-                                       page->counters == counters_old) {
-                       page->freelist = freelist_new;
-                       page->counters = counters_new;
-                       slab_unlock(page, &flags);
+               slab_lock(slab, &flags);
+               if (slab->freelist == freelist_old &&
+                                       slab->counters == counters_old) {
+                       slab->freelist = freelist_new;
+                       slab->counters = counters_new;
+                       slab_unlock(slab, &flags);
                        return true;
                }
-               slab_unlock(page, &flags);
+               slab_unlock(slab, &flags);
        }
 
        cpu_relax();
@@ -512,7 +516,7 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
        return false;
 }
 
-static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct slab *slab,
                void *freelist_old, unsigned long counters_old,
                void *freelist_new, unsigned long counters_new,
                const char *n)
@@ -520,7 +524,7 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
 #if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
     defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (s->flags & __CMPXCHG_DOUBLE) {
-               if (cmpxchg_double(&page->freelist, &page->counters,
+               if (cmpxchg_double(&slab->freelist, &slab->counters,
                                   freelist_old, counters_old,
                                   freelist_new, counters_new))
                        return true;
@@ -530,16 +534,16 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                unsigned long flags;
 
                local_irq_save(flags);
-               __slab_lock(page);
-               if (page->freelist == freelist_old &&
-                                       page->counters == counters_old) {
-                       page->freelist = freelist_new;
-                       page->counters = counters_new;
-                       __slab_unlock(page);
+               __slab_lock(slab);
+               if (slab->freelist == freelist_old &&
+                                       slab->counters == counters_old) {
+                       slab->freelist = freelist_new;
+                       slab->counters = counters_new;
+                       __slab_unlock(slab);
                        local_irq_restore(flags);
                        return true;
                }
-               __slab_unlock(page);
+               __slab_unlock(slab);
                local_irq_restore(flags);
        }
 
@@ -558,14 +562,14 @@ static unsigned long object_map[BITS_TO_LONGS(MAX_OBJS_PER_PAGE)];
 static DEFINE_RAW_SPINLOCK(object_map_lock);
 
 static void __fill_map(unsigned long *obj_map, struct kmem_cache *s,
-                      struct page *page)
+                      struct slab *slab)
 {
-       void *addr = page_address(page);
+       void *addr = slab_address(slab);
        void *p;
 
-       bitmap_zero(obj_map, page->objects);
+       bitmap_zero(obj_map, slab->objects);
 
-       for (p = page->freelist; p; p = get_freepointer(s, p))
+       for (p = slab->freelist; p; p = get_freepointer(s, p))
                set_bit(__obj_to_index(s, addr, p), obj_map);
 }
 
@@ -590,19 +594,19 @@ static inline bool slab_add_kunit_errors(void) { return false; }
 #endif
 
 /*
- * Determine a map of object in use on a page.
+ * Determine a map of objects in use in a slab.
  *
- * Node listlock must be held to guarantee that the page does
+ * Node listlock must be held to guarantee that the slab does
  * not vanish from under us.
  */
-static unsigned long *get_map(struct kmem_cache *s, struct page *page)
+static unsigned long *get_map(struct kmem_cache *s, struct slab *slab)
        __acquires(&object_map_lock)
 {
        VM_BUG_ON(!irqs_disabled());
 
        raw_spin_lock(&object_map_lock);
 
-       __fill_map(object_map, s, page);
+       __fill_map(object_map, s, slab);
 
        return object_map;
 }
@@ -663,17 +667,17 @@ static inline void metadata_access_disable(void)
 
 /* 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)
+                               struct slab *slab, void *object)
 {
        void *base;
 
        if (!object)
                return 1;
 
-       base = page_address(page);
+       base = slab_address(slab);
        object = kasan_reset_tag(object);
        object = restore_red_left(s, object);
-       if (object < base || object >= base + page->objects * s->size ||
+       if (object < base || object >= base + slab->objects * s->size ||
                (object - base) % s->size) {
                return 0;
        }
@@ -784,12 +788,13 @@ void print_tracking(struct kmem_cache *s, void *object)
        print_track("Freed", get_track(s, object, TRACK_FREE), pr_time);
 }
 
-static void print_page_info(struct page *page)
+static void print_slab_info(const struct slab *slab)
 {
-       pr_err("Slab 0x%p objects=%u used=%u fp=0x%p flags=%pGp\n",
-              page, page->objects, page->inuse, page->freelist,
-              &page->flags);
+       struct folio *folio = (struct folio *)slab_folio(slab);
 
+       pr_err("Slab 0x%p objects=%u used=%u fp=0x%p flags=%pGp\n",
+              slab, slab->objects, slab->inuse, slab->freelist,
+              folio_flags(folio, 0));
 }
 
 static void slab_bug(struct kmem_cache *s, char *fmt, ...)
@@ -822,28 +827,14 @@ static void slab_fix(struct kmem_cache *s, char *fmt, ...)
        va_end(args);
 }
 
-static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
-                              void **freelist, void *nextfree)
-{
-       if ((s->flags & SLAB_CONSISTENCY_CHECKS) &&
-           !check_valid_pointer(s, page, nextfree) && freelist) {
-               object_err(s, page, *freelist, "Freechain corrupt");
-               *freelist = NULL;
-               slab_fix(s, "Isolate corrupted freechain");
-               return true;
-       }
-
-       return false;
-}
-
-static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
+static void print_trailer(struct kmem_cache *s, struct slab *slab, u8 *p)
 {
        unsigned int off;       /* Offset of last byte */
-       u8 *addr = page_address(page);
+       u8 *addr = slab_address(slab);
 
        print_tracking(s, p);
 
-       print_page_info(page);
+       print_slab_info(slab);
 
        pr_err("Object 0x%p @offset=%tu fp=0x%p\n\n",
               p, p - addr, get_freepointer(s, p));
@@ -875,18 +866,32 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
        dump_stack();
 }
 
-void object_err(struct kmem_cache *s, struct page *page,
+static void object_err(struct kmem_cache *s, struct slab *slab,
                        u8 *object, char *reason)
 {
        if (slab_add_kunit_errors())
                return;
 
        slab_bug(s, "%s", reason);
-       print_trailer(s, page, object);
+       print_trailer(s, slab, object);
        add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
 }
 
-static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page,
+static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
+                              void **freelist, void *nextfree)
+{
+       if ((s->flags & SLAB_CONSISTENCY_CHECKS) &&
+           !check_valid_pointer(s, slab, nextfree) && freelist) {
+               object_err(s, slab, *freelist, "Freechain corrupt");
+               *freelist = NULL;
+               slab_fix(s, "Isolate corrupted freechain");
+               return true;
+       }
+
+       return false;
+}
+
+static __printf(3, 4) void slab_err(struct kmem_cache *s, struct slab *slab,
                        const char *fmt, ...)
 {
        va_list args;
@@ -899,7 +904,7 @@ static __printf(3, 4) void slab_err(struct kmem_cache *s, struct page *page,
        vsnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);
        slab_bug(s, "%s", buf);
-       print_page_info(page);
+       print_slab_info(slab);
        dump_stack();
        add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
 }
@@ -927,13 +932,13 @@ static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
        memset(from, data, to - from);
 }
 
-static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
+static int check_bytes_and_report(struct kmem_cache *s, struct slab *slab,
                        u8 *object, char *what,
                        u8 *start, unsigned int value, unsigned int bytes)
 {
        u8 *fault;
        u8 *end;
-       u8 *addr = page_address(page);
+       u8 *addr = slab_address(slab);
 
        metadata_access_enable();
        fault = memchr_inv(kasan_reset_tag(start), value, bytes);
@@ -952,7 +957,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
        pr_err("0x%p-0x%p @offset=%tu. First byte 0x%x instead of 0x%x\n",
                                        fault, end - 1, fault - addr,
                                        fault[0], value);
-       print_trailer(s, page, object);
+       print_trailer(s, slab, object);
        add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
 
 skip_bug_print:
@@ -998,7 +1003,7 @@ skip_bug_print:
  * may be used with merged slabcaches.
  */
 
-static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
+static int check_pad_bytes(struct kmem_cache *s, struct slab *slab, u8 *p)
 {
        unsigned long off = get_info_end(s);    /* The end of info */
 
@@ -1011,12 +1016,12 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
        if (size_from_object(s) == off)
                return 1;
 
-       return check_bytes_and_report(s, page, p, "Object padding",
+       return check_bytes_and_report(s, slab, p, "Object padding",
                        p + off, POISON_INUSE, size_from_object(s) - off);
 }
 
 /* Check the pad bytes at the end of a slab page */
-static int slab_pad_check(struct kmem_cache *s, struct page *page)
+static int slab_pad_check(struct kmem_cache *s, struct slab *slab)
 {
        u8 *start;
        u8 *fault;
@@ -1028,8 +1033,8 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
        if (!(s->flags & SLAB_POISON))
                return 1;
 
-       start = page_address(page);
-       length = page_size(page);
+       start = slab_address(slab);
+       length = slab_size(slab);
        end = start + length;
        remainder = length % s->size;
        if (!remainder)
@@ -1044,7 +1049,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
        while (end > fault && end[-1] == POISON_INUSE)
                end--;
 
-       slab_err(s, page, "Padding overwritten. 0x%p-0x%p @offset=%tu",
+       slab_err(s, slab, "Padding overwritten. 0x%p-0x%p @offset=%tu",
                        fault, end - 1, fault - start);
        print_section(KERN_ERR, "Padding ", pad, remainder);
 
@@ -1052,23 +1057,23 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
        return 0;
 }
 
-static int check_object(struct kmem_cache *s, struct page *page,
+static int check_object(struct kmem_cache *s, struct slab *slab,
                                        void *object, u8 val)
 {
        u8 *p = object;
        u8 *endobject = object + s->object_size;
 
        if (s->flags & SLAB_RED_ZONE) {
-               if (!check_bytes_and_report(s, page, object, "Left Redzone",
+               if (!check_bytes_and_report(s, slab, object, "Left Redzone",
                        object - s->red_left_pad, val, s->red_left_pad))
                        return 0;
 
-               if (!check_bytes_and_report(s, page, object, "Right Redzone",
+               if (!check_bytes_and_report(s, slab, object, "Right Redzone",
                        endobject, val, s->inuse - s->object_size))
                        return 0;
        } else {
                if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
-                       check_bytes_and_report(s, page, p, "Alignment padding",
+                       check_bytes_and_report(s, slab, p, "Alignment padding",
                                endobject, POISON_INUSE,
                                s->inuse - s->object_size);
                }
@@ -1076,15 +1081,15 @@ static int check_object(struct kmem_cache *s, struct page *page,
 
        if (s->flags & SLAB_POISON) {
                if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
-                       (!check_bytes_and_report(s, page, p, "Poison", p,
+                       (!check_bytes_and_report(s, slab, p, "Poison", p,
                                        POISON_FREE, s->object_size - 1) ||
-                        !check_bytes_and_report(s, page, p, "End Poison",
+                        !check_bytes_and_report(s, slab, p, "End Poison",
                                p + s->object_size - 1, POISON_END, 1)))
                        return 0;
                /*
                 * check_pad_bytes cleans up on its own.
                 */
-               check_pad_bytes(s, page, p);
+               check_pad_bytes(s, slab, p);
        }
 
        if (!freeptr_outside_object(s) && val == SLUB_RED_ACTIVE)
@@ -1095,8 +1100,8 @@ static int check_object(struct kmem_cache *s, struct page *page,
                return 1;
 
        /* Check free pointer validity */
-       if (!check_valid_pointer(s, page, get_freepointer(s, p))) {
-               object_err(s, page, p, "Freepointer corrupt");
+       if (!check_valid_pointer(s, slab, get_freepointer(s, p))) {
+               object_err(s, slab, p, "Freepointer corrupt");
                /*
                 * No choice but to zap it and thus lose the remainder
                 * of the free objects in this slab. May cause
@@ -1108,55 +1113,55 @@ static int check_object(struct kmem_cache *s, struct page *page,
        return 1;
 }
 
-static int check_slab(struct kmem_cache *s, struct page *page)
+static int check_slab(struct kmem_cache *s, struct slab *slab)
 {
        int maxobj;
 
-       if (!PageSlab(page)) {
-               slab_err(s, page, "Not a valid slab page");
+       if (!folio_test_slab(slab_folio(slab))) {
+               slab_err(s, slab, "Not a valid slab page");
                return 0;
        }
 
-       maxobj = order_objects(compound_order(page), s->size);
-       if (page->objects > maxobj) {
-               slab_err(s, page, "objects %u > max %u",
-                       page->objects, maxobj);
+       maxobj = order_objects(slab_order(slab), s->size);
+       if (slab->objects > maxobj) {
+               slab_err(s, slab, "objects %u > max %u",
+                       slab->objects, maxobj);
                return 0;
        }
-       if (page->inuse > page->objects) {
-               slab_err(s, page, "inuse %u > max %u",
-                       page->inuse, page->objects);
+       if (slab->inuse > slab->objects) {
+               slab_err(s, slab, "inuse %u > max %u",
+                       slab->inuse, slab->objects);
                return 0;
        }
        /* Slab_pad_check fixes things up after itself */
-       slab_pad_check(s, page);
+       slab_pad_check(s, slab);
        return 1;
 }
 
 /*
- * Determine if a certain object on a page is on the freelist. Must hold the
+ * Determine if a certain object in a slab is on the freelist. Must hold the
  * slab lock to guarantee that the chains are in a consistent state.
  */
-static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
+static int on_freelist(struct kmem_cache *s, struct slab *slab, void *search)
 {
        int nr = 0;
        void *fp;
        void *object = NULL;
        int max_objects;
 
-       fp = page->freelist;
-       while (fp && nr <= page->objects) {
+       fp = slab->freelist;
+       while (fp && nr <= slab->objects) {
                if (fp == search)
                        return 1;
-               if (!check_valid_pointer(s, page, fp)) {
+               if (!check_valid_pointer(s, slab, fp)) {
                        if (object) {
-                               object_err(s, page, object,
+                               object_err(s, slab, object,
                                        "Freechain corrupt");
                                set_freepointer(s, object, NULL);
                        } else {
-                               slab_err(s, page, "Freepointer corrupt");
-                               page->freelist = NULL;
-                               page->inuse = page->objects;
+                               slab_err(s, slab, "Freepointer corrupt");
+                               slab->freelist = NULL;
+                               slab->inuse = slab->objects;
                                slab_fix(s, "Freelist cleared");
                                return 0;
                        }
@@ -1167,34 +1172,34 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
                nr++;
        }
 
-       max_objects = order_objects(compound_order(page), s->size);
+       max_objects = order_objects(slab_order(slab), s->size);
        if (max_objects > MAX_OBJS_PER_PAGE)
                max_objects = MAX_OBJS_PER_PAGE;
 
-       if (page->objects != max_objects) {
-               slab_err(s, page, "Wrong number of objects. Found %d but should be %d",
-                        page->objects, max_objects);
-               page->objects = max_objects;
+       if (slab->objects != max_objects) {
+               slab_err(s, slab, "Wrong number of objects. Found %d but should be %d",
+                        slab->objects, max_objects);
+               slab->objects = max_objects;
                slab_fix(s, "Number of objects adjusted");
        }
-       if (page->inuse != page->objects - nr) {
-               slab_err(s, page, "Wrong object count. Counter is %d but counted were %d",
-                        page->inuse, page->objects - nr);
-               page->inuse = page->objects - nr;
+       if (slab->inuse != slab->objects - nr) {
+               slab_err(s, slab, "Wrong object count. Counter is %d but counted were %d",
+                        slab->inuse, slab->objects - nr);
+               slab->inuse = slab->objects - nr;
                slab_fix(s, "Object count adjusted");
        }
        return search == NULL;
 }
 
-static void trace(struct kmem_cache *s, struct page *page, void *object,
+static void trace(struct kmem_cache *s, struct slab *slab, void *object,
                                                                int alloc)
 {
        if (s->flags & SLAB_TRACE) {
                pr_info("TRACE %s %s 0x%p inuse=%d fp=0x%p\n",
                        s->name,
                        alloc ? "alloc" : "free",
-                       object, page->inuse,
-                       page->freelist);
+                       object, slab->inuse,
+                       slab->freelist);
 
                if (!alloc)
                        print_section(KERN_INFO, "Object ", (void *)object,
@@ -1208,22 +1213,22 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
  * Tracking of fully allocated slabs for debugging purposes.
  */
 static void add_full(struct kmem_cache *s,
-       struct kmem_cache_node *n, struct page *page)
+       struct kmem_cache_node *n, struct slab *slab)
 {
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
        lockdep_assert_held(&n->list_lock);
-       list_add(&page->slab_list, &n->full);
+       list_add(&slab->slab_list, &n->full);
 }
 
-static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct page *page)
+static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct slab *slab)
 {
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
        lockdep_assert_held(&n->list_lock);
-       list_del(&page->slab_list);
+       list_del(&slab->slab_list);
 }
 
 /* Tracking of the number of slabs for debugging purposes */
@@ -1263,7 +1268,7 @@ static inline void dec_slabs_node(struct kmem_cache *s, int node, int objects)
 }
 
 /* Object debug checks for alloc/free paths */
-static void setup_object_debug(struct kmem_cache *s, struct page *page,
+static void setup_object_debug(struct kmem_cache *s, struct slab *slab,
                                                                void *object)
 {
        if (!kmem_cache_debug_flags(s, SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON))
@@ -1274,89 +1279,89 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
 }
 
 static
-void setup_page_debug(struct kmem_cache *s, struct page *page, void *addr)
+void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr)
 {
        if (!kmem_cache_debug_flags(s, SLAB_POISON))
                return;
 
        metadata_access_enable();
-       memset(kasan_reset_tag(addr), POISON_INUSE, page_size(page));
+       memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
        metadata_access_disable();
 }
 
 static inline int alloc_consistency_checks(struct kmem_cache *s,
-                                       struct page *page, void *object)
+                                       struct slab *slab, void *object)
 {
-       if (!check_slab(s, page))
+       if (!check_slab(s, slab))
                return 0;
 
-       if (!check_valid_pointer(s, page, object)) {
-               object_err(s, page, object, "Freelist Pointer check fails");
+       if (!check_valid_pointer(s, slab, object)) {
+               object_err(s, slab, object, "Freelist Pointer check fails");
                return 0;
        }
 
-       if (!check_object(s, page, object, SLUB_RED_INACTIVE))
+       if (!check_object(s, slab, object, SLUB_RED_INACTIVE))
                return 0;
 
        return 1;
 }
 
 static noinline int alloc_debug_processing(struct kmem_cache *s,
-                                       struct page *page,
+                                       struct slab *slab,
                                        void *object, unsigned long addr)
 {
        if (s->flags & SLAB_CONSISTENCY_CHECKS) {
-               if (!alloc_consistency_checks(s, page, object))
+               if (!alloc_consistency_checks(s, slab, object))
                        goto bad;
        }
 
        /* Success perform special debug activities for allocs */
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_ALLOC, addr);
-       trace(s, page, object, 1);
+       trace(s, slab, object, 1);
        init_object(s, object, SLUB_RED_ACTIVE);
        return 1;
 
 bad:
-       if (PageSlab(page)) {
+       if (folio_test_slab(slab_folio(slab))) {
                /*
                 * If this is a slab page then lets do the best we can
                 * to avoid issues in the future. Marking all objects
                 * as used avoids touching the remaining objects.
                 */
                slab_fix(s, "Marking all objects used");
-               page->inuse = page->objects;
-               page->freelist = NULL;
+               slab->inuse = slab->objects;
+               slab->freelist = NULL;
        }
        return 0;
 }
 
 static inline int free_consistency_checks(struct kmem_cache *s,
-               struct page *page, void *object, unsigned long addr)
+               struct slab *slab, void *object, unsigned long addr)
 {
-       if (!check_valid_pointer(s, page, object)) {
-               slab_err(s, page, "Invalid object pointer 0x%p", object);
+       if (!check_valid_pointer(s, slab, object)) {
+               slab_err(s, slab, "Invalid object pointer 0x%p", object);
                return 0;
        }
 
-       if (on_freelist(s, page, object)) {
-               object_err(s, page, object, "Object already free");
+       if (on_freelist(s, slab, object)) {
+               object_err(s, slab, object, "Object already free");
                return 0;
        }
 
-       if (!check_object(s, page, object, SLUB_RED_ACTIVE))
+       if (!check_object(s, slab, object, SLUB_RED_ACTIVE))
                return 0;
 
-       if (unlikely(s != page->slab_cache)) {
-               if (!PageSlab(page)) {
-                       slab_err(s, page, "Attempt to free object(0x%p) outside of slab",
+       if (unlikely(s != slab->slab_cache)) {
+               if (!folio_test_slab(slab_folio(slab))) {
+                       slab_err(s, slab, "Attempt to free object(0x%p) outside of slab",
                                 object);
-               } else if (!page->slab_cache) {
+               } else if (!slab->slab_cache) {
                        pr_err("SLUB <none>: no slab for object 0x%p.\n",
                               object);
                        dump_stack();
                } else
-                       object_err(s, page, object,
+                       object_err(s, slab, object,
                                        "page slab pointer corrupt.");
                return 0;
        }
@@ -1365,21 +1370,21 @@ static inline int free_consistency_checks(struct kmem_cache *s,
 
 /* Supports checking bulk free of a constructed freelist */
 static noinline int free_debug_processing(
-       struct kmem_cache *s, struct page *page,
+       struct kmem_cache *s, struct slab *slab,
        void *head, void *tail, int bulk_cnt,
        unsigned long addr)
 {
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+       struct kmem_cache_node *n = get_node(s, slab_nid(slab));
        void *object = head;
        int cnt = 0;
        unsigned long flags, flags2;
        int ret = 0;
 
        spin_lock_irqsave(&n->list_lock, flags);
-       slab_lock(page, &flags2);
+       slab_lock(slab, &flags2);
 
        if (s->flags & SLAB_CONSISTENCY_CHECKS) {
-               if (!check_slab(s, page))
+               if (!check_slab(s, slab))
                        goto out;
        }
 
@@ -1387,13 +1392,13 @@ next_object:
        cnt++;
 
        if (s->flags & SLAB_CONSISTENCY_CHECKS) {
-               if (!free_consistency_checks(s, page, object, addr))
+               if (!free_consistency_checks(s, slab, object, addr))
                        goto out;
        }
 
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_FREE, addr);
-       trace(s, page, object, 0);
+       trace(s, slab, object, 0);
        /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */
        init_object(s, object, SLUB_RED_INACTIVE);
 
@@ -1406,10 +1411,10 @@ next_object:
 
 out:
        if (cnt != bulk_cnt)
-               slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n",
+               slab_err(s, slab, "Bulk freelist count(%d) invalid(%d)\n",
                         bulk_cnt, cnt);
 
-       slab_unlock(page, &flags2);
+       slab_unlock(slab, &flags2);
        spin_unlock_irqrestore(&n->list_lock, flags);
        if (!ret)
                slab_fix(s, "Object at 0x%p not freed", object);
@@ -1624,26 +1629,26 @@ slab_flags_t kmem_cache_flags(unsigned int object_size,
 }
 #else /* !CONFIG_SLUB_DEBUG */
 static inline void setup_object_debug(struct kmem_cache *s,
-                       struct page *page, void *object) {}
+                       struct slab *slab, void *object) {}
 static inline
-void setup_page_debug(struct kmem_cache *s, struct page *page, void *addr) {}
+void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr) {}
 
 static inline int alloc_debug_processing(struct kmem_cache *s,
-       struct page *page, void *object, unsigned long addr) { return 0; }
+       struct slab *slab, void *object, unsigned long addr) { return 0; }
 
 static inline int free_debug_processing(
-       struct kmem_cache *s, struct page *page,
+       struct kmem_cache *s, struct slab *slab,
        void *head, void *tail, int bulk_cnt,
        unsigned long addr) { return 0; }
 
-static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
+static inline int slab_pad_check(struct kmem_cache *s, struct slab *slab)
                        { return 1; }
-static inline int check_object(struct kmem_cache *s, struct page *page,
+static inline int check_object(struct kmem_cache *s, struct slab *slab,
                        void *object, u8 val) { return 1; }
 static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
-                                       struct page *page) {}
+                                       struct slab *slab) {}
 static inline void remove_full(struct kmem_cache *s, struct kmem_cache_node *n,
-                                       struct page *page) {}
+                                       struct slab *slab) {}
 slab_flags_t kmem_cache_flags(unsigned int object_size,
        slab_flags_t flags, const char *name)
 {
@@ -1662,7 +1667,7 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node,
 static inline void dec_slabs_node(struct kmem_cache *s, int node,
                                                        int objects) {}
 
-static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
+static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
                               void **freelist, void *nextfree)
 {
        return false;
@@ -1767,10 +1772,10 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
        return *head != NULL;
 }
 
-static void *setup_object(struct kmem_cache *s, struct page *page,
+static void *setup_object(struct kmem_cache *s, struct slab *slab,
                                void *object)
 {
-       setup_object_debug(s, page, object);
+       setup_object_debug(s, slab, object);
        object = kasan_init_slab_obj(s, object);
        if (unlikely(s->ctor)) {
                kasan_unpoison_object_data(s, object);
@@ -1783,18 +1788,27 @@ static void *setup_object(struct kmem_cache *s, struct page *page,
 /*
  * Slab allocation and freeing
  */
-static inline struct page *alloc_slab_page(struct kmem_cache *s,
+static inline struct slab *alloc_slab_page(struct kmem_cache *s,
                gfp_t flags, int node, struct kmem_cache_order_objects oo)
 {
-       struct page *page;
+       struct folio *folio;
+       struct slab *slab;
        unsigned int order = oo_order(oo);
 
        if (node == NUMA_NO_NODE)
-               page = alloc_pages(flags, order);
+               folio = (struct folio *)alloc_pages(flags, order);
        else
-               page = __alloc_pages_node(node, flags, order);
+               folio = (struct folio *)__alloc_pages_node(node, flags, order);
+
+       if (!folio)
+               return NULL;
+
+       slab = folio_slab(folio);
+       __folio_set_slab(folio);
+       if (page_is_pfmemalloc(folio_page(folio, 0)))
+               slab_set_pfmemalloc(slab);
 
-       return page;
+       return slab;
 }
 
 #ifdef CONFIG_SLAB_FREELIST_RANDOM
@@ -1839,7 +1853,7 @@ static void __init init_freelist_randomization(void)
 }
 
 /* Get the next entry on the pre-computed freelist randomized */
-static void *next_freelist_entry(struct kmem_cache *s, struct page *page,
+static void *next_freelist_entry(struct kmem_cache *s, struct slab *slab,
                                unsigned long *pos, void *start,
                                unsigned long page_limit,
                                unsigned long freelist_count)
@@ -1861,32 +1875,32 @@ static void *next_freelist_entry(struct kmem_cache *s, struct page *page,
 }
 
 /* Shuffle the single linked freelist based on a random pre-computed sequence */
-static bool shuffle_freelist(struct kmem_cache *s, struct page *page)
+static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
 {
        void *start;
        void *cur;
        void *next;
        unsigned long idx, pos, page_limit, freelist_count;
 
-       if (page->objects < 2 || !s->random_seq)
+       if (slab->objects < 2 || !s->random_seq)
                return false;
 
        freelist_count = oo_objects(s->oo);
        pos = get_random_int() % freelist_count;
 
-       page_limit = page->objects * s->size;
-       start = fixup_red_left(s, page_address(page));
+       page_limit = slab->objects * s->size;
+       start = fixup_red_left(s, slab_address(slab));
 
        /* First entry is used as the base of the freelist */
-       cur = next_freelist_entry(s, page, &pos, start, page_limit,
+       cur = next_freelist_entry(s, slab, &pos, start, page_limit,
                                freelist_count);
-       cur = setup_object(s, page, cur);
-       page->freelist = cur;
+       cur = setup_object(s, slab, cur);
+       slab->freelist = cur;
 
-       for (idx = 1; idx < page->objects; idx++) {
-               next = next_freelist_entry(s, page, &pos, start, page_limit,
+       for (idx = 1; idx < slab->objects; idx++) {
+               next = next_freelist_entry(s, slab, &pos, start, page_limit,
                        freelist_count);
-               next = setup_object(s, page, next);
+               next = setup_object(s, slab, next);
                set_freepointer(s, cur, next);
                cur = next;
        }
@@ -1900,15 +1914,15 @@ static inline int init_cache_random_seq(struct kmem_cache *s)
        return 0;
 }
 static inline void init_freelist_randomization(void) { }
-static inline bool shuffle_freelist(struct kmem_cache *s, struct page *page)
+static inline bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
 {
        return false;
 }
 #endif /* CONFIG_SLAB_FREELIST_RANDOM */
 
-static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
 {
-       struct page *page;
+       struct slab *slab;
        struct kmem_cache_order_objects oo = s->oo;
        gfp_t alloc_gfp;
        void *start, *p, *next;
@@ -1927,63 +1941,60 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
        if ((alloc_gfp & __GFP_DIRECT_RECLAIM) && oo_order(oo) > oo_order(s->min))
                alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~(__GFP_RECLAIM|__GFP_NOFAIL);
 
-       page = alloc_slab_page(s, alloc_gfp, node, oo);
-       if (unlikely(!page)) {
+       slab = alloc_slab_page(s, alloc_gfp, node, oo);
+       if (unlikely(!slab)) {
                oo = s->min;
                alloc_gfp = flags;
                /*
                 * Allocation may have failed due to fragmentation.
                 * Try a lower order alloc if possible
                 */
-               page = alloc_slab_page(s, alloc_gfp, node, oo);
-               if (unlikely(!page))
+               slab = alloc_slab_page(s, alloc_gfp, node, oo);
+               if (unlikely(!slab))
                        goto out;
                stat(s, ORDER_FALLBACK);
        }
 
-       page->objects = oo_objects(oo);
+       slab->objects = oo_objects(oo);
 
-       account_slab_page(page, oo_order(oo), s, flags);
+       account_slab(slab, oo_order(oo), s, flags);
 
-       page->slab_cache = s;
-       __SetPageSlab(page);
-       if (page_is_pfmemalloc(page))
-               SetPageSlabPfmemalloc(page);
+       slab->slab_cache = s;
 
-       kasan_poison_slab(page);
+       kasan_poison_slab(slab);
 
-       start = page_address(page);
+       start = slab_address(slab);
 
-       setup_page_debug(s, page, start);
+       setup_slab_debug(s, slab, start);
 
-       shuffle = shuffle_freelist(s, page);
+       shuffle = shuffle_freelist(s, slab);
 
        if (!shuffle) {
                start = fixup_red_left(s, start);
-               start = setup_object(s, page, start);
-               page->freelist = start;
-               for (idx = 0, p = start; idx < page->objects - 1; idx++) {
+               start = setup_object(s, slab, start);
+               slab->freelist = start;
+               for (idx = 0, p = start; idx < slab->objects - 1; idx++) {
                        next = p + s->size;
-                       next = setup_object(s, page, next);
+                       next = setup_object(s, slab, next);
                        set_freepointer(s, p, next);
                        p = next;
                }
                set_freepointer(s, p, NULL);
        }
 
-       page->inuse = page->objects;
-       page->frozen = 1;
+       slab->inuse = slab->objects;
+       slab->frozen = 1;
 
 out:
-       if (!page)
+       if (!slab)
                return NULL;
 
-       inc_slabs_node(s, page_to_nid(page), page->objects);
+       inc_slabs_node(s, slab_nid(slab), slab->objects);
 
-       return page;
+       return slab;
 }
 
-static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
+static struct slab *new_slab(struct kmem_cache *s, gfp_t flags, int node)
 {
        if (unlikely(flags & GFP_SLAB_BUG_MASK))
                flags = kmalloc_fix_flags(flags);
@@ -1994,76 +2005,75 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
                flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
 }
 
-static void __free_slab(struct kmem_cache *s, struct page *page)
+static void __free_slab(struct kmem_cache *s, struct slab *slab)
 {
-       int order = compound_order(page);
+       struct folio *folio = slab_folio(slab);
+       int order = folio_order(folio);
        int pages = 1 << order;
 
        if (kmem_cache_debug_flags(s, SLAB_CONSISTENCY_CHECKS)) {
                void *p;
 
-               slab_pad_check(s, page);
-               for_each_object(p, s, page_address(page),
-                                               page->objects)
-                       check_object(s, page, p, SLUB_RED_INACTIVE);
+               slab_pad_check(s, slab);
+               for_each_object(p, s, slab_address(slab), slab->objects)
+                       check_object(s, slab, p, SLUB_RED_INACTIVE);
        }
 
-       __ClearPageSlabPfmemalloc(page);
-       __ClearPageSlab(page);
-       /* In union with page->mapping where page allocator expects NULL */
-       page->slab_cache = NULL;
+       __slab_clear_pfmemalloc(slab);
+       __folio_clear_slab(folio);
+       folio->mapping = NULL;
        if (current->reclaim_state)
                current->reclaim_state->reclaimed_slab += pages;
-       unaccount_slab_page(page, order, s);
-       __free_pages(page, order);
+       unaccount_slab(slab, order, s);
+       __free_pages(folio_page(folio, 0), order);
 }
 
 static void rcu_free_slab(struct rcu_head *h)
 {
-       struct page *page = container_of(h, struct page, rcu_head);
+       struct slab *slab = container_of(h, struct slab, rcu_head);
 
-       __free_slab(page->slab_cache, page);
+       __free_slab(slab->slab_cache, slab);
 }
 
-static void free_slab(struct kmem_cache *s, struct page *page)
+static void free_slab(struct kmem_cache *s, struct slab *slab)
 {
        if (unlikely(s->flags & SLAB_TYPESAFE_BY_RCU)) {
-               call_rcu(&page->rcu_head, rcu_free_slab);
+               call_rcu(&slab->rcu_head, rcu_free_slab);
        } else
-               __free_slab(s, page);
+               __free_slab(s, slab);
 }
 
-static void discard_slab(struct kmem_cache *s, struct page *page)
+static void discard_slab(struct kmem_cache *s, struct slab *slab)
 {
-       dec_slabs_node(s, page_to_nid(page), page->objects);
-       free_slab(s, page);
+       dec_slabs_node(s, slab_nid(slab), slab->objects);
+       free_slab(s, slab);
 }
 
 /*
  * Management of partially allocated slabs.
  */
 static inline void
-__add_partial(struct kmem_cache_node *n, struct page *page, int tail)
+__add_partial(struct kmem_cache_node *n, struct slab *slab, int tail)
 {
        n->nr_partial++;
        if (tail == DEACTIVATE_TO_TAIL)
-               list_add_tail(&page->slab_list, &n->partial);
+               list_add_tail(&slab->slab_list, &n->partial);
        else
-               list_add(&page->slab_list, &n->partial);
+               list_add(&slab->slab_list, &n->partial);
 }
 
 static inline void add_partial(struct kmem_cache_node *n,
-                               struct page *page, int tail)
+                               struct slab *slab, int tail)
 {
        lockdep_assert_held(&n->list_lock);
-       __add_partial(n, page, tail);
+       __add_partial(n, slab, tail);
 }
 
 static inline void remove_partial(struct kmem_cache_node *n,
-                                       struct page *page)
+                                       struct slab *slab)
 {
        lockdep_assert_held(&n->list_lock);
-       list_del(&page->slab_list);
+       list_del(&slab->slab_list);
        n->nr_partial--;
 }
 
@@ -2074,12 +2084,12 @@ static inline void remove_partial(struct kmem_cache_node *n,
  * Returns a list of objects or NULL if it fails.
  */
 static inline void *acquire_slab(struct kmem_cache *s,
-               struct kmem_cache_node *n, struct page *page,
+               struct kmem_cache_node *n, struct slab *slab,
                int mode)
 {
        void *freelist;
        unsigned long counters;
-       struct page new;
+       struct slab new;
 
        lockdep_assert_held(&n->list_lock);
 
@@ -2088,11 +2098,11 @@ static inline void *acquire_slab(struct kmem_cache *s,
         * The old freelist is the list of objects for the
         * per cpu allocation list.
         */
-       freelist = page->freelist;
-       counters = page->counters;
+       freelist = slab->freelist;
+       counters = slab->counters;
        new.counters = counters;
        if (mode) {
-               new.inuse = page->objects;
+               new.inuse = slab->objects;
                new.freelist = NULL;
        } else {
                new.freelist = freelist;
@@ -2101,35 +2111,35 @@ static inline void *acquire_slab(struct kmem_cache *s,
        VM_BUG_ON(new.frozen);
        new.frozen = 1;
 
-       if (!__cmpxchg_double_slab(s, page,
+       if (!__cmpxchg_double_slab(s, slab,
                        freelist, counters,
                        new.freelist, new.counters,
                        "acquire_slab"))
                return NULL;
 
-       remove_partial(n, page);
+       remove_partial(n, slab);
        WARN_ON(!freelist);
        return freelist;
 }
 
 #ifdef CONFIG_SLUB_CPU_PARTIAL
-static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain);
+static void put_cpu_partial(struct kmem_cache *s, struct slab *slab, int drain);
 #else
-static inline void put_cpu_partial(struct kmem_cache *s, struct page *page,
+static inline void put_cpu_partial(struct kmem_cache *s, struct slab *slab,
                                   int drain) { }
 #endif
-static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags);
+static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags);
 
 /*
  * Try to allocate a partial slab from a specific node.
  */
 static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
-                             struct page **ret_page, gfp_t gfpflags)
+                             struct slab **ret_slab, gfp_t gfpflags)
 {
-       struct page *page, *page2;
+       struct slab *slab, *slab2;
        void *object = NULL;
        unsigned long flags;
-       unsigned int partial_pages = 0;
+       unsigned int partial_slabs = 0;
 
        /*
         * Racy check. If we mistakenly see no partial slabs then we
@@ -2141,28 +2151,28 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
                return NULL;
 
        spin_lock_irqsave(&n->list_lock, flags);
-       list_for_each_entry_safe(page, page2, &n->partial, slab_list) {
+       list_for_each_entry_safe(slab, slab2, &n->partial, slab_list) {
                void *t;
 
-               if (!pfmemalloc_match(page, gfpflags))
+               if (!pfmemalloc_match(slab, gfpflags))
                        continue;
 
-               t = acquire_slab(s, n, page, object == NULL);
+               t = acquire_slab(s, n, slab, object == NULL);
                if (!t)
                        break;
 
                if (!object) {
-                       *ret_page = page;
+                       *ret_slab = slab;
                        stat(s, ALLOC_FROM_PARTIAL);
                        object = t;
                } else {
-                       put_cpu_partial(s, page, 0);
+                       put_cpu_partial(s, slab, 0);
                        stat(s, CPU_PARTIAL_NODE);
-                       partial_pages++;
+                       partial_slabs++;
                }
 #ifdef CONFIG_SLUB_CPU_PARTIAL
                if (!kmem_cache_has_cpu_partial(s)
-                       || partial_pages > s->cpu_partial_pages / 2)
+                       || partial_slabs > s->cpu_partial_slabs / 2)
                        break;
 #else
                break;
@@ -2174,10 +2184,10 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
 }
 
 /*
- * Get a page from somewhere. Search in increasing NUMA distances.
+ * Get a slab from somewhere. Search in increasing NUMA distances.
  */
 static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
-                            struct page **ret_page)
+                            struct slab **ret_slab)
 {
 #ifdef CONFIG_NUMA
        struct zonelist *zonelist;
@@ -2219,7 +2229,7 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
 
                        if (n && cpuset_zone_allowed(zone, flags) &&
                                        n->nr_partial > s->min_partial) {
-                               object = get_partial_node(s, n, ret_page, flags);
+                               object = get_partial_node(s, n, ret_slab, flags);
                                if (object) {
                                        /*
                                         * Don't check read_mems_allowed_retry()
@@ -2238,10 +2248,10 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
 }
 
 /*
- * Get a partial page, lock it and return it.
+ * Get a partial slab, lock it and return it.
  */
 static void *get_partial(struct kmem_cache *s, gfp_t flags, int node,
-                        struct page **ret_page)
+                        struct slab **ret_slab)
 {
        void *object;
        int searchnode = node;
@@ -2249,11 +2259,11 @@ static void *get_partial(struct kmem_cache *s, gfp_t flags, int node,
        if (node == NUMA_NO_NODE)
                searchnode = numa_mem_id();
 
-       object = get_partial_node(s, get_node(s, searchnode), ret_page, flags);
+       object = get_partial_node(s, get_node(s, searchnode), ret_slab, flags);
        if (object || node != NUMA_NO_NODE)
                return object;
 
-       return get_any_partial(s, flags, ret_page);
+       return get_any_partial(s, flags, ret_slab);
 }
 
 #ifdef CONFIG_PREEMPTION
@@ -2330,25 +2340,25 @@ static void init_kmem_cache_cpus(struct kmem_cache *s)
 }
 
 /*
- * Finishes removing the cpu slab. Merges cpu's freelist with page's freelist,
+ * Finishes removing the cpu slab. Merges cpu's freelist with slab's freelist,
  * unfreezes the slabs and puts it on the proper list.
  * Assumes the slab has been already safely taken away from kmem_cache_cpu
  * by the caller.
  */
-static void deactivate_slab(struct kmem_cache *s, struct page *page,
+static void deactivate_slab(struct kmem_cache *s, struct slab *slab,
                            void *freelist)
 {
        enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+       struct kmem_cache_node *n = get_node(s, slab_nid(slab));
        int lock = 0, free_delta = 0;
        enum slab_modes l = M_NONE, m = M_NONE;
        void *nextfree, *freelist_iter, *freelist_tail;
        int tail = DEACTIVATE_TO_HEAD;
        unsigned long flags = 0;
-       struct page new;
-       struct page old;
+       struct slab new;
+       struct slab old;
 
-       if (page->freelist) {
+       if (slab->freelist) {
                stat(s, DEACTIVATE_REMOTE_FREES);
                tail = DEACTIVATE_TO_TAIL;
        }
@@ -2367,7 +2377,7 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page,
                 * 'freelist_iter' is already corrupted.  So isolate all objects
                 * starting at 'freelist_iter' by skipping them.
                 */
-               if (freelist_corrupted(s, page, &freelist_iter, nextfree))
+               if (freelist_corrupted(s, slab, &freelist_iter, nextfree))
                        break;
 
                freelist_tail = freelist_iter;
@@ -2377,25 +2387,25 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page,
        }
 
        /*
-        * Stage two: Unfreeze the page while splicing the per-cpu
-        * freelist to the head of page's freelist.
+        * Stage two: Unfreeze the slab while splicing the per-cpu
+        * freelist to the head of slab's freelist.
         *
-        * Ensure that the page is unfrozen while the list presence
+        * Ensure that the slab is unfrozen while the list presence
         * reflects the actual number of objects during unfreeze.
         *
         * We setup the list membership and then perform a cmpxchg
-        * with the count. If there is a mismatch then the page
-        * is not unfrozen but the page is on the wrong list.
+        * with the count. If there is a mismatch then the slab
+        * is not unfrozen but the slab is on the wrong list.
         *
         * Then we restart the process which may have to remove
-        * the page from the list that we just put it on again
+        * the slab from the list that we just put it on again
         * because the number of objects in the slab may have
         * changed.
         */
 redo:
 
-       old.freelist = READ_ONCE(page->freelist);
-       old.counters = READ_ONCE(page->counters);
+       old.freelist = READ_ONCE(slab->freelist);
+       old.counters = READ_ONCE(slab->counters);
        VM_BUG_ON(!old.frozen);
 
        /* Determine target state of the slab */
@@ -2416,9 +2426,8 @@ redo:
                if (!lock) {
                        lock = 1;
                        /*
-                        * Taking the spinlock removes the possibility
-                        * that acquire_slab() will see a slab page that
-                        * is frozen
+                        * Taking the spinlock removes the possibility that
+                        * acquire_slab() will see a slab that is frozen
                         */
                        spin_lock_irqsave(&n->list_lock, flags);
                }
@@ -2437,18 +2446,18 @@ redo:
 
        if (l != m) {
                if (l == M_PARTIAL)
-                       remove_partial(n, page);
+                       remove_partial(n, slab);
                else if (l == M_FULL)
-                       remove_full(s, n, page);
+                       remove_full(s, n, slab);
 
                if (m == M_PARTIAL)
-                       add_partial(n, page, tail);
+                       add_partial(n, slab, tail);
                else if (m == M_FULL)
-                       add_full(s, n, page);
+                       add_full(s, n, slab);
        }
 
        l = m;
-       if (!cmpxchg_double_slab(s, page,
+       if (!cmpxchg_double_slab(s, slab,
                                old.freelist, old.counters,
                                new.freelist, new.counters,
                                "unfreezing slab"))
@@ -2463,26 +2472,26 @@ redo:
                stat(s, DEACTIVATE_FULL);
        else if (m == M_FREE) {
                stat(s, DEACTIVATE_EMPTY);
-               discard_slab(s, page);
+               discard_slab(s, slab);
                stat(s, FREE_SLAB);
        }
 }
 
 #ifdef CONFIG_SLUB_CPU_PARTIAL
-static void __unfreeze_partials(struct kmem_cache *s, struct page *partial_page)
+static void __unfreeze_partials(struct kmem_cache *s, struct slab *partial_slab)
 {
        struct kmem_cache_node *n = NULL, *n2 = NULL;
-       struct page *page, *discard_page = NULL;
+       struct slab *slab, *slab_to_discard = NULL;
        unsigned long flags = 0;
 
-       while (partial_page) {
-               struct page new;
-               struct page old;
+       while (partial_slab) {
+               struct slab new;
+               struct slab old;
 
-               page = partial_page;
-               partial_page = page->next;
+               slab = partial_slab;
+               partial_slab = slab->next;
 
-               n2 = get_node(s, page_to_nid(page));
+               n2 = get_node(s, slab_nid(slab));
                if (n != n2) {
                        if (n)
                                spin_unlock_irqrestore(&n->list_lock, flags);
@@ -2493,8 +2502,8 @@ static void __unfreeze_partials(struct kmem_cache *s, struct page *partial_page)
 
                do {
 
-                       old.freelist = page->freelist;
-                       old.counters = page->counters;
+                       old.freelist = slab->freelist;
+                       old.counters = slab->counters;
                        VM_BUG_ON(!old.frozen);
 
                        new.counters = old.counters;
@@ -2502,16 +2511,16 @@ static void __unfreeze_partials(struct kmem_cache *s, struct page *partial_page)
 
                        new.frozen = 0;
 
-               } while (!__cmpxchg_double_slab(s, page,
+               } while (!__cmpxchg_double_slab(s, slab,
                                old.freelist, old.counters,
                                new.freelist, new.counters,
                                "unfreezing slab"));
 
                if (unlikely(!new.inuse && n->nr_partial >= s->min_partial)) {
-                       page->next = discard_page;
-                       discard_page = page;
+                       slab->next = slab_to_discard;
+                       slab_to_discard = slab;
                } else {
-                       add_partial(n, page, DEACTIVATE_TO_TAIL);
+                       add_partial(n, slab, DEACTIVATE_TO_TAIL);
                        stat(s, FREE_ADD_PARTIAL);
                }
        }
@@ -2519,12 +2528,12 @@ static void __unfreeze_partials(struct kmem_cache *s, struct page *partial_page)
        if (n)
                spin_unlock_irqrestore(&n->list_lock, flags);
 
-       while (discard_page) {
-               page = discard_page;
-               discard_page = discard_page->next;
+       while (slab_to_discard) {
+               slab = slab_to_discard;
+               slab_to_discard = slab_to_discard->next;
 
                stat(s, DEACTIVATE_EMPTY);
-               discard_slab(s, page);
+               discard_slab(s, slab);
                stat(s, FREE_SLAB);
        }
 }
@@ -2534,73 +2543,73 @@ static void __unfreeze_partials(struct kmem_cache *s, struct page *partial_page)
  */
 static void unfreeze_partials(struct kmem_cache *s)
 {
-       struct page *partial_page;
+       struct slab *partial_slab;
        unsigned long flags;
 
        local_lock_irqsave(&s->cpu_slab->lock, flags);
-       partial_page = this_cpu_read(s->cpu_slab->partial);
+       partial_slab = this_cpu_read(s->cpu_slab->partial);
        this_cpu_write(s->cpu_slab->partial, NULL);
        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 
-       if (partial_page)
-               __unfreeze_partials(s, partial_page);
+       if (partial_slab)
+               __unfreeze_partials(s, partial_slab);
 }
 
 static void unfreeze_partials_cpu(struct kmem_cache *s,
                                  struct kmem_cache_cpu *c)
 {
-       struct page *partial_page;
+       struct slab *partial_slab;
 
-       partial_page = slub_percpu_partial(c);
+       partial_slab = slub_percpu_partial(c);
        c->partial = NULL;
 
-       if (partial_page)
-               __unfreeze_partials(s, partial_page);
+       if (partial_slab)
+               __unfreeze_partials(s, partial_slab);
 }
 
 /*
- * Put a page that was just frozen (in __slab_free|get_partial_node) into a
- * partial page slot if available.
+ * Put a slab that was just frozen (in __slab_free|get_partial_node) into a
+ * partial slab slot if available.
  *
  * If we did not find a slot then simply move all the partials to the
  * per node partial list.
  */
-static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
+static void put_cpu_partial(struct kmem_cache *s, struct slab *slab, int drain)
 {
-       struct page *oldpage;
-       struct page *page_to_unfreeze = NULL;
+       struct slab *oldslab;
+       struct slab *slab_to_unfreeze = NULL;
        unsigned long flags;
-       int pages = 0;
+       int slabs = 0;
 
        local_lock_irqsave(&s->cpu_slab->lock, flags);
 
-       oldpage = this_cpu_read(s->cpu_slab->partial);
+       oldslab = this_cpu_read(s->cpu_slab->partial);
 
-       if (oldpage) {
-               if (drain && oldpage->pages >= s->cpu_partial_pages) {
+       if (oldslab) {
+               if (drain && oldslab->slabs >= s->cpu_partial_slabs) {
                        /*
                         * Partial array is full. Move the existing set to the
                         * per node partial list. Postpone the actual unfreezing
                         * outside of the critical section.
                         */
-                       page_to_unfreeze = oldpage;
-                       oldpage = NULL;
+                       slab_to_unfreeze = oldslab;
+                       oldslab = NULL;
                } else {
-                       pages = oldpage->pages;
+                       slabs = oldslab->slabs;
                }
        }
 
-       pages++;
+       slabs++;
 
-       page->pages = pages;
-       page->next = oldpage;
+       slab->slabs = slabs;
+       slab->next = oldslab;
 
-       this_cpu_write(s->cpu_slab->partial, page);
+       this_cpu_write(s->cpu_slab->partial, slab);
 
        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 
-       if (page_to_unfreeze) {
-               __unfreeze_partials(s, page_to_unfreeze);
+       if (slab_to_unfreeze) {
+               __unfreeze_partials(s, slab_to_unfreeze);
                stat(s, CPU_PARTIAL_DRAIN);
        }
 }
@@ -2616,22 +2625,22 @@ static inline void unfreeze_partials_cpu(struct kmem_cache *s,
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 {
        unsigned long flags;
-       struct page *page;
+       struct slab *slab;
        void *freelist;
 
        local_lock_irqsave(&s->cpu_slab->lock, flags);
 
-       page = c->page;
+       slab = c->slab;
        freelist = c->freelist;
 
-       c->page = NULL;
+       c->slab = NULL;
        c->freelist = NULL;
        c->tid = next_tid(c->tid);
 
        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 
-       if (page) {
-               deactivate_slab(s, page, freelist);
+       if (slab) {
+               deactivate_slab(s, slab, freelist);
                stat(s, CPUSLAB_FLUSH);
        }
 }
@@ -2640,14 +2649,14 @@ static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
 {
        struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
        void *freelist = c->freelist;
-       struct page *page = c->page;
+       struct slab *slab = c->slab;
 
-       c->page = NULL;
+       c->slab = NULL;
        c->freelist = NULL;
        c->tid = next_tid(c->tid);
 
-       if (page) {
-               deactivate_slab(s, page, freelist);
+       if (slab) {
+               deactivate_slab(s, slab, freelist);
                stat(s, CPUSLAB_FLUSH);
        }
 
@@ -2676,7 +2685,7 @@ static void flush_cpu_slab(struct work_struct *w)
        s = sfw->s;
        c = this_cpu_ptr(s->cpu_slab);
 
-       if (c->page)
+       if (c->slab)
                flush_slab(s, c);
 
        unfreeze_partials(s);
@@ -2686,7 +2695,7 @@ static bool has_cpu_slab(int cpu, struct kmem_cache *s)
 {
        struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
 
-       return c->page || slub_percpu_partial(c);
+       return c->slab || slub_percpu_partial(c);
 }
 
 static DEFINE_MUTEX(flush_lock);
@@ -2748,19 +2757,19 @@ static int slub_cpu_dead(unsigned int cpu)
  * Check if the objects in a per cpu structure fit numa
  * locality expectations.
  */
-static inline int node_match(struct page *page, int node)
+static inline int node_match(struct slab *slab, int node)
 {
 #ifdef CONFIG_NUMA
-       if (node != NUMA_NO_NODE && page_to_nid(page) != node)
+       if (node != NUMA_NO_NODE && slab_nid(slab) != node)
                return 0;
 #endif
        return 1;
 }
 
 #ifdef CONFIG_SLUB_DEBUG
-static int count_free(struct page *page)
+static int count_free(struct slab *slab)
 {
-       return page->objects - page->inuse;
+       return slab->objects - slab->inuse;
 }
 
 static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
@@ -2771,15 +2780,15 @@ static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
 
 #if defined(CONFIG_SLUB_DEBUG) || defined(CONFIG_SYSFS)
 static unsigned long count_partial(struct kmem_cache_node *n,
-                                       int (*get_count)(struct page *))
+                                       int (*get_count)(struct slab *))
 {
        unsigned long flags;
        unsigned long x = 0;
-       struct page *page;
+       struct slab *slab;
 
        spin_lock_irqsave(&n->list_lock, flags);
-       list_for_each_entry(page, &n->partial, slab_list)
-               x += get_count(page);
+       list_for_each_entry(slab, &n->partial, slab_list)
+               x += get_count(slab);
        spin_unlock_irqrestore(&n->list_lock, flags);
        return x;
 }
@@ -2822,54 +2831,41 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
 #endif
 }
 
-static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags)
-{
-       if (unlikely(PageSlabPfmemalloc(page)))
-               return gfp_pfmemalloc_allowed(gfpflags);
-
-       return true;
-}
-
-/*
- * A variant of pfmemalloc_match() that tests page flags without asserting
- * PageSlab. Intended for opportunistic checks before taking a lock and
- * rechecking that nobody else freed the page under us.
- */
-static inline bool pfmemalloc_match_unsafe(struct page *page, gfp_t gfpflags)
+static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
 {
-       if (unlikely(__PageSlabPfmemalloc(page)))
+       if (unlikely(slab_test_pfmemalloc(slab)))
                return gfp_pfmemalloc_allowed(gfpflags);
 
        return true;
 }
 
 /*
- * Check the page->freelist of a page and either transfer the freelist to the
- * per cpu freelist or deactivate the page.
+ * Check the slab->freelist and either transfer the freelist to the
+ * per cpu freelist or deactivate the slab.
  *
- * The page is still frozen if the return value is not NULL.
+ * The slab is still frozen if the return value is not NULL.
  *
- * If this function returns NULL then the page has been unfrozen.
+ * If this function returns NULL then the slab has been unfrozen.
  */
-static inline void *get_freelist(struct kmem_cache *s, struct page *page)
+static inline void *get_freelist(struct kmem_cache *s, struct slab *slab)
 {
-       struct page new;
+       struct slab new;
        unsigned long counters;
        void *freelist;
 
        lockdep_assert_held(this_cpu_ptr(&s->cpu_slab->lock));
 
        do {
-               freelist = page->freelist;
-               counters = page->counters;
+               freelist = slab->freelist;
+               counters = slab->counters;
 
                new.counters = counters;
                VM_BUG_ON(!new.frozen);
 
-               new.inuse = page->objects;
+               new.inuse = slab->objects;
                new.frozen = freelist != NULL;
 
-       } while (!__cmpxchg_double_slab(s, page,
+       } while (!__cmpxchg_double_slab(s, slab,
                freelist, counters,
                NULL, new.counters,
                "get_freelist"));
@@ -2900,15 +2896,15 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
                          unsigned long addr, struct kmem_cache_cpu *c)
 {
        void *freelist;
-       struct page *page;
+       struct slab *slab;
        unsigned long flags;
 
        stat(s, ALLOC_SLOWPATH);
 
-reread_page:
+reread_slab:
 
-       page = READ_ONCE(c->page);
-       if (!page) {
+       slab = READ_ONCE(c->slab);
+       if (!slab) {
                /*
                 * if the node is not online or has no normal memory, just
                 * ignore the node constraint
@@ -2920,7 +2916,7 @@ reread_page:
        }
 redo:
 
-       if (unlikely(!node_match(page, node))) {
+       if (unlikely(!node_match(slab, node))) {
                /*
                 * same as above but node_match() being false already
                 * implies node != NUMA_NO_NODE
@@ -2939,23 +2935,23 @@ redo:
         * PFMEMALLOC but right now, we are losing the pfmemalloc
         * information when the page leaves the per-cpu allocator
         */
-       if (unlikely(!pfmemalloc_match_unsafe(page, gfpflags)))
+       if (unlikely(!pfmemalloc_match(slab, gfpflags)))
                goto deactivate_slab;
 
-       /* must check again c->page in case we got preempted and it changed */
+       /* must check again c->slab in case we got preempted and it changed */
        local_lock_irqsave(&s->cpu_slab->lock, flags);
-       if (unlikely(page != c->page)) {
+       if (unlikely(slab != c->slab)) {
                local_unlock_irqrestore(&s->cpu_slab->lock, flags);
-               goto reread_page;
+               goto reread_slab;
        }
        freelist = c->freelist;
        if (freelist)
                goto load_freelist;
 
-       freelist = get_freelist(s, page);
+       freelist = get_freelist(s, slab);
 
        if (!freelist) {
-               c->page = NULL;
+               c->slab = NULL;
                local_unlock_irqrestore(&s->cpu_slab->lock, flags);
                stat(s, DEACTIVATE_BYPASS);
                goto new_slab;
@@ -2969,10 +2965,10 @@ load_freelist:
 
        /*
         * freelist is pointing to the list of objects to be used.
-        * page is pointing to the page from which the objects are obtained.
-        * That page must be frozen for per cpu allocations to work.
+        * slab is pointing to the slab from which the objects are obtained.
+        * That slab must be frozen for per cpu allocations to work.
         */
-       VM_BUG_ON(!c->page->frozen);
+       VM_BUG_ON(!c->slab->frozen);
        c->freelist = get_freepointer(s, freelist);
        c->tid = next_tid(c->tid);
        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
@@ -2981,23 +2977,23 @@ load_freelist:
 deactivate_slab:
 
        local_lock_irqsave(&s->cpu_slab->lock, flags);
-       if (page != c->page) {
+       if (slab != c->slab) {
                local_unlock_irqrestore(&s->cpu_slab->lock, flags);
-               goto reread_page;
+               goto reread_slab;
        }
        freelist = c->freelist;
-       c->page = NULL;
+       c->slab = NULL;
        c->freelist = NULL;
        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
-       deactivate_slab(s, page, freelist);
+       deactivate_slab(s, slab, freelist);
 
 new_slab:
 
        if (slub_percpu_partial(c)) {
                local_lock_irqsave(&s->cpu_slab->lock, flags);
-               if (unlikely(c->page)) {
+               if (unlikely(c->slab)) {
                        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
-                       goto reread_page;
+                       goto reread_slab;
                }
                if (unlikely(!slub_percpu_partial(c))) {
                        local_unlock_irqrestore(&s->cpu_slab->lock, flags);
@@ -3005,8 +3001,8 @@ new_slab:
                        goto new_objects;
                }
 
-               page = c->page = slub_percpu_partial(c);
-               slub_set_percpu_partial(c, page);
+               slab = c->slab = slub_percpu_partial(c);
+               slub_set_percpu_partial(c, slab);
                local_unlock_irqrestore(&s->cpu_slab->lock, flags);
                stat(s, CPU_PARTIAL_ALLOC);
                goto redo;
@@ -3014,32 +3010,32 @@ new_slab:
 
 new_objects:
 
-       freelist = get_partial(s, gfpflags, node, &page);
+       freelist = get_partial(s, gfpflags, node, &slab);
        if (freelist)
-               goto check_new_page;
+               goto check_new_slab;
 
        slub_put_cpu_ptr(s->cpu_slab);
-       page = new_slab(s, gfpflags, node);
+       slab = new_slab(s, gfpflags, node);
        c = slub_get_cpu_ptr(s->cpu_slab);
 
-       if (unlikely(!page)) {
+       if (unlikely(!slab)) {
                slab_out_of_memory(s, gfpflags, node);
                return NULL;
        }
 
        /*
-        * No other reference to the page yet so we can
+        * No other reference to the slab yet so we can
         * muck around with it freely without cmpxchg
         */
-       freelist = page->freelist;
-       page->freelist = NULL;
+       freelist = slab->freelist;
+       slab->freelist = NULL;
 
        stat(s, ALLOC_SLAB);
 
-check_new_page:
+check_new_slab:
 
        if (kmem_cache_debug(s)) {
-               if (!alloc_debug_processing(s, page, freelist, addr)) {
+               if (!alloc_debug_processing(s, slab, freelist, addr)) {
                        /* Slab failed checks. Next slab needed */
                        goto new_slab;
                } else {
@@ -3051,39 +3047,39 @@ check_new_page:
                }
        }
 
-       if (unlikely(!pfmemalloc_match(page, gfpflags)))
+       if (unlikely(!pfmemalloc_match(slab, gfpflags)))
                /*
                 * For !pfmemalloc_match() case we don't load freelist so that
                 * we don't make further mismatched allocations easier.
                 */
                goto return_single;
 
-retry_load_page:
+retry_load_slab:
 
        local_lock_irqsave(&s->cpu_slab->lock, flags);
-       if (unlikely(c->page)) {
+       if (unlikely(c->slab)) {
                void *flush_freelist = c->freelist;
-               struct page *flush_page = c->page;
+               struct slab *flush_slab = c->slab;
 
-               c->page = NULL;
+               c->slab = NULL;
                c->freelist = NULL;
                c->tid = next_tid(c->tid);
 
                local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 
-               deactivate_slab(s, flush_page, flush_freelist);
+               deactivate_slab(s, flush_slab, flush_freelist);
 
                stat(s, CPUSLAB_FLUSH);
 
-               goto retry_load_page;
+               goto retry_load_slab;
        }
-       c->page = page;
+       c->slab = slab;
 
        goto load_freelist;
 
 return_single:
 
-       deactivate_slab(s, page, get_freepointer(s, freelist));
+       deactivate_slab(s, slab, get_freepointer(s, freelist));
        return freelist;
 }
 
@@ -3140,7 +3136,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
 {
        void *object;
        struct kmem_cache_cpu *c;
-       struct page *page;
+       struct slab *slab;
        unsigned long tid;
        struct obj_cgroup *objcg = NULL;
        bool init = false;
@@ -3172,9 +3168,9 @@ redo:
        /*
         * Irqless object alloc/free algorithm used here depends on sequence
         * of fetching cpu_slab's data. tid should be fetched before anything
-        * on c to guarantee that object and page associated with previous tid
+        * on c to guarantee that object and slab associated with previous tid
         * won't be used with current tid. If we fetch tid first, object and
-        * page could be one associated with next tid and our alloc/free
+        * slab could be one associated with next tid and our alloc/free
         * request will be failed. In this case, we will retry. So, no problem.
         */
        barrier();
@@ -3187,7 +3183,7 @@ redo:
         */
 
        object = c->freelist;
-       page = c->page;
+       slab = c->slab;
        /*
         * We cannot use the lockless fastpath on PREEMPT_RT because if a
         * slowpath has taken the local_lock_irqsave(), it is not protected
@@ -3196,7 +3192,7 @@ redo:
         * there is a suitable cpu freelist.
         */
        if (IS_ENABLED(CONFIG_PREEMPT_RT) ||
-           unlikely(!object || !page || !node_match(page, node))) {
+           unlikely(!object || !slab || !node_match(slab, node))) {
                object = __slab_alloc(s, gfpflags, node, addr, c);
        } else {
                void *next_object = get_freepointer_safe(s, object);
@@ -3298,17 +3294,17 @@ EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
  * have a longer lifetime than the cpu slabs in most processing loads.
  *
  * So we still attempt to reduce cache line usage. Just take the slab
- * lock and free the item. If there is no additional partial page
+ * lock and free the item. If there is no additional partial slab
  * handling required then we can return immediately.
  */
-static void __slab_free(struct kmem_cache *s, struct page *page,
+static void __slab_free(struct kmem_cache *s, struct slab *slab,
                        void *head, void *tail, int cnt,
                        unsigned long addr)
 
 {
        void *prior;
        int was_frozen;
-       struct page new;
+       struct slab new;
        unsigned long counters;
        struct kmem_cache_node *n = NULL;
        unsigned long flags;
@@ -3319,7 +3315,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                return;
 
        if (kmem_cache_debug(s) &&
-           !free_debug_processing(s, page, head, tail, cnt, addr))
+           !free_debug_processing(s, slab, head, tail, cnt, addr))
                return;
 
        do {
@@ -3327,8 +3323,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                        spin_unlock_irqrestore(&n->list_lock, flags);
                        n = NULL;
                }
-               prior = page->freelist;
-               counters = page->counters;
+               prior = slab->freelist;
+               counters = slab->counters;
                set_freepointer(s, tail, prior);
                new.counters = counters;
                was_frozen = new.frozen;
@@ -3347,7 +3343,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 
                        } else { /* Needs to be taken off a list */
 
-                               n = get_node(s, page_to_nid(page));
+                               n = get_node(s, slab_nid(slab));
                                /*
                                 * Speculatively acquire the list_lock.
                                 * If the cmpxchg does not succeed then we may
@@ -3361,7 +3357,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                        }
                }
 
-       } while (!cmpxchg_double_slab(s, page,
+       } while (!cmpxchg_double_slab(s, slab,
                prior, counters,
                head, new.counters,
                "__slab_free"));
@@ -3376,10 +3372,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                        stat(s, FREE_FROZEN);
                } else if (new.frozen) {
                        /*
-                        * If we just froze the page then put it onto the
+                        * If we just froze the slab then put it onto the
                         * per cpu partial list.
                         */
-                       put_cpu_partial(s, page, 1);
+                       put_cpu_partial(s, slab, 1);
                        stat(s, CPU_PARTIAL_FREE);
                }
 
@@ -3394,8 +3390,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
         * then add it.
         */
        if (!kmem_cache_has_cpu_partial(s) && unlikely(!prior)) {
-               remove_full(s, n, page);
-               add_partial(n, page, DEACTIVATE_TO_TAIL);
+               remove_full(s, n, slab);
+               add_partial(n, slab, DEACTIVATE_TO_TAIL);
                stat(s, FREE_ADD_PARTIAL);
        }
        spin_unlock_irqrestore(&n->list_lock, flags);
@@ -3406,16 +3402,16 @@ slab_empty:
                /*
                 * Slab on the partial list.
                 */
-               remove_partial(n, page);
+               remove_partial(n, slab);
                stat(s, FREE_REMOVE_PARTIAL);
        } else {
                /* Slab must be on the full list */
-               remove_full(s, n, page);
+               remove_full(s, n, slab);
        }
 
        spin_unlock_irqrestore(&n->list_lock, flags);
        stat(s, FREE_SLAB);
-       discard_slab(s, page);
+       discard_slab(s, slab);
 }
 
 /*
@@ -3430,11 +3426,11 @@ slab_empty:
  * with all sorts of special processing.
  *
  * Bulk free of a freelist with several objects (all pointing to the
- * same page) possible by specifying head and tail ptr, plus objects
+ * same slab) possible by specifying head and tail ptr, plus objects
  * count (cnt). Bulk free indicated by tail pointer being set.
  */
 static __always_inline void do_slab_free(struct kmem_cache *s,
-                               struct page *page, void *head, void *tail,
+                               struct slab *slab, void *head, void *tail,
                                int cnt, unsigned long addr)
 {
        void *tail_obj = tail ? : head;
@@ -3457,7 +3453,7 @@ redo:
        /* Same with comment on barrier() in slab_alloc_node() */
        barrier();
 
-       if (likely(page == c->page)) {
+       if (likely(slab == c->slab)) {
 #ifndef CONFIG_PREEMPT_RT
                void **freelist = READ_ONCE(c->freelist);
 
@@ -3483,7 +3479,7 @@ redo:
 
                local_lock(&s->cpu_slab->lock);
                c = this_cpu_ptr(s->cpu_slab);
-               if (unlikely(page != c->page)) {
+               if (unlikely(slab != c->slab)) {
                        local_unlock(&s->cpu_slab->lock);
                        goto redo;
                }
@@ -3498,11 +3494,11 @@ redo:
 #endif
                stat(s, FREE_FASTPATH);
        } else
-               __slab_free(s, page, head, tail_obj, cnt, addr);
+               __slab_free(s, slab, head, tail_obj, cnt, addr);
 
 }
 
-static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
+static __always_inline void slab_free(struct kmem_cache *s, struct slab *slab,
                                      void *head, void *tail, int cnt,
                                      unsigned long addr)
 {
@@ -3511,13 +3507,13 @@ static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
         * to remove objects, whose reuse must be delayed.
         */
        if (slab_free_freelist_hook(s, &head, &tail, &cnt))
-               do_slab_free(s, page, head, tail, cnt, addr);
+               do_slab_free(s, slab, head, tail, cnt, addr);
 }
 
 #ifdef CONFIG_KASAN_GENERIC
 void ___cache_free(struct kmem_cache *cache, void *x, unsigned long addr)
 {
-       do_slab_free(cache, virt_to_head_page(x), x, NULL, 1, addr);
+       do_slab_free(cache, virt_to_slab(x), x, NULL, 1, addr);
 }
 #endif
 
@@ -3527,35 +3523,36 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
        if (!s)
                return;
        trace_kmem_cache_free(_RET_IP_, x, s->name);
-       slab_free(s, virt_to_head_page(x), x, NULL, 1, _RET_IP_);
+       slab_free(s, virt_to_slab(x), x, NULL, 1, _RET_IP_);
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
 struct detached_freelist {
-       struct page *page;
+       struct slab *slab;
        void *tail;
        void *freelist;
        int cnt;
        struct kmem_cache *s;
 };
 
-static inline void free_nonslab_page(struct page *page, void *object)
+static inline void free_large_kmalloc(struct folio *folio, void *object)
 {
-       unsigned int order = compound_order(page);
+       unsigned int order = folio_order(folio);
 
-       if (WARN_ON_ONCE(!PageCompound(page)))
+       if (WARN_ON_ONCE(order == 0))
                pr_warn_once("object pointer: 0x%p\n", object);
 
        kfree_hook(object);
-       mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE_B, -(PAGE_SIZE << order));
-       __free_pages(page, order);
+       mod_lruvec_page_state(folio_page(folio, 0), NR_SLAB_UNRECLAIMABLE_B,
+                             -(PAGE_SIZE << order));
+       __free_pages(folio_page(folio, 0), order);
 }
 
 /*
  * This function progressively scans the array with free objects (with
  * a limited look ahead) and extract objects belonging to the same
- * page.  It builds a detached freelist directly within the given
- * page/objects.  This can happen without any need for
+ * slab.  It builds a detached freelist directly within the given
+ * slab/objects.  This can happen without any need for
  * synchronization, because the objects are owned by running process.
  * The freelist is build up as a single linked list in the objects.
  * The idea is, that this detached freelist can then be bulk
@@ -3570,10 +3567,11 @@ int build_detached_freelist(struct kmem_cache *s, size_t size,
        size_t first_skipped_index = 0;
        int lookahead = 3;
        void *object;
-       struct page *page;
+       struct folio *folio;
+       struct slab *slab;
 
        /* Always re-init detached_freelist */
-       df->page = NULL;
+       df->slab = NULL;
 
        do {
                object = p[--size];
@@ -3583,17 +3581,19 @@ int build_detached_freelist(struct kmem_cache *s, size_t size,
        if (!object)
                return 0;
 
-       page = virt_to_head_page(object);
+       folio = virt_to_folio(object);
        if (!s) {
                /* Handle kalloc'ed objects */
-               if (unlikely(!PageSlab(page))) {
-                       free_nonslab_page(page, object);
+               if (unlikely(!folio_test_slab(folio))) {
+                       free_large_kmalloc(folio, object);
                        p[size] = NULL; /* mark object processed */
                        return size;
                }
                /* Derive kmem_cache from object */
-               df->s = page->slab_cache;
+               slab = folio_slab(folio);
+               df->s = slab->slab_cache;
        } else {
+               slab = folio_slab(folio);
                df->s = cache_from_obj(s, object); /* Support for memcg */
        }
 
@@ -3605,7 +3605,7 @@ int build_detached_freelist(struct kmem_cache *s, size_t size,
        }
 
        /* Start new detached freelist */
-       df->page = page;
+       df->slab = slab;
        set_freepointer(df->s, object, NULL);
        df->tail = object;
        df->freelist = object;
@@ -3617,8 +3617,8 @@ int build_detached_freelist(struct kmem_cache *s, size_t size,
                if (!object)
                        continue; /* Skip processed objects */
 
-               /* df->page is always set at this point */
-               if (df->page == virt_to_head_page(object)) {
+               /* df->slab is always set at this point */
+               if (df->slab == virt_to_slab(object)) {
                        /* Opportunity build freelist */
                        set_freepointer(df->s, object, df->freelist);
                        df->freelist = object;
@@ -3650,10 +3650,10 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
                struct detached_freelist df;
 
                size = build_detached_freelist(s, size, p, &df);
-               if (!df.page)
+               if (!df.slab)
                        continue;
 
-               slab_free(df.s, df.page, df.freelist, df.tail, df.cnt, _RET_IP_);
+               slab_free(df.s, df.slab, df.freelist, df.tail, df.cnt, _RET_IP_);
        } while (likely(size));
 }
 EXPORT_SYMBOL(kmem_cache_free_bulk);
@@ -3787,7 +3787,7 @@ static unsigned int slub_min_objects;
  * requested a higher minimum order then we start with that one instead of
  * the smallest order which will fit the object.
  */
-static inline unsigned int slab_order(unsigned int size,
+static inline unsigned int calc_slab_order(unsigned int size,
                unsigned int min_objects, unsigned int max_order,
                unsigned int fract_leftover)
 {
@@ -3851,7 +3851,7 @@ static inline int calculate_order(unsigned int size)
 
                fraction = 16;
                while (fraction >= 4) {
-                       order = slab_order(size, min_objects,
+                       order = calc_slab_order(size, min_objects,
                                        slub_max_order, fraction);
                        if (order <= slub_max_order)
                                return order;
@@ -3864,14 +3864,14 @@ static inline int calculate_order(unsigned int size)
         * We were unable to place multiple objects in a slab. Now
         * lets see if we can place a single object there.
         */
-       order = slab_order(size, 1, slub_max_order, 1);
+       order = calc_slab_order(size, 1, slub_max_order, 1);
        if (order <= slub_max_order)
                return order;
 
        /*
         * Doh this slab cannot be placed using slub_max_order.
         */
-       order = slab_order(size, 1, MAX_ORDER, 1);
+       order = calc_slab_order(size, 1, MAX_ORDER, 1);
        if (order < MAX_ORDER)
                return order;
        return -ENOSYS;
@@ -3923,38 +3923,38 @@ static struct kmem_cache *kmem_cache_node;
  */
 static void early_kmem_cache_node_alloc(int node)
 {
-       struct page *page;
+       struct slab *slab;
        struct kmem_cache_node *n;
 
        BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
 
-       page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
+       slab = new_slab(kmem_cache_node, GFP_NOWAIT, node);
 
-       BUG_ON(!page);
-       if (page_to_nid(page) != node) {
+       BUG_ON(!slab);
+       if (slab_nid(slab) != node) {
                pr_err("SLUB: Unable to allocate memory from node %d\n", node);
                pr_err("SLUB: Allocating a useless per node structure in order to be able to continue\n");
        }
 
-       n = page->freelist;
+       n = slab->freelist;
        BUG_ON(!n);
 #ifdef CONFIG_SLUB_DEBUG
        init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
        init_tracking(kmem_cache_node, n);
 #endif
        n = kasan_slab_alloc(kmem_cache_node, n, GFP_KERNEL, false);
-       page->freelist = get_freepointer(kmem_cache_node, n);
-       page->inuse = 1;
-       page->frozen = 0;
+       slab->freelist = get_freepointer(kmem_cache_node, n);
+       slab->inuse = 1;
+       slab->frozen = 0;
        kmem_cache_node->node[node] = n;
        init_kmem_cache_node(n);
-       inc_slabs_node(kmem_cache_node, node, page->objects);
+       inc_slabs_node(kmem_cache_node, node, slab->objects);
 
        /*
         * No locks need to be taken here as it has just been
         * initialized and there is no concurrent access.
         */
-       __add_partial(n, page, DEACTIVATE_TO_HEAD);
+       __add_partial(n, slab, DEACTIVATE_TO_HEAD);
 }
 
 static void free_kmem_cache_nodes(struct kmem_cache *s)
@@ -4212,7 +4212,7 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags)
 #endif
 
        /*
-        * The larger the object size is, the more pages we want on the partial
+        * The larger the object size is, the more slabs we want on the partial
         * list to avoid pounding the page allocator excessively.
         */
        set_min_partial(s, ilog2(s->size) / 2);
@@ -4240,20 +4240,20 @@ error:
        return -EINVAL;
 }
 
-static void list_slab_objects(struct kmem_cache *s, struct page *page,
+static void list_slab_objects(struct kmem_cache *s, struct slab *slab,
                              const char *text)
 {
 #ifdef CONFIG_SLUB_DEBUG
-       void *addr = page_address(page);
+       void *addr = slab_address(slab);
        unsigned long flags;
        unsigned long *map;
        void *p;
 
-       slab_err(s, page, text, s->name);
-       slab_lock(page, &flags);
+       slab_err(s, slab, text, s->name);
+       slab_lock(slab, &flags);
 
-       map = get_map(s, page);
-       for_each_object(p, s, addr, page->objects) {
+       map = get_map(s, slab);
+       for_each_object(p, s, addr, slab->objects) {
 
                if (!test_bit(__obj_to_index(s, addr, p), map)) {
                        pr_err("Object 0x%p @offset=%tu\n", p, p - addr);
@@ -4261,7 +4261,7 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
                }
        }
        put_map(map);
-       slab_unlock(page, &flags);
+       slab_unlock(slab, &flags);
 #endif
 }
 
@@ -4273,23 +4273,23 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
 static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 {
        LIST_HEAD(discard);
-       struct page *page, *h;
+       struct slab *slab, *h;
 
        BUG_ON(irqs_disabled());
        spin_lock_irq(&n->list_lock);
-       list_for_each_entry_safe(page, h, &n->partial, slab_list) {
-               if (!page->inuse) {
-                       remove_partial(n, page);
-                       list_add(&page->slab_list, &discard);
+       list_for_each_entry_safe(slab, h, &n->partial, slab_list) {
+               if (!slab->inuse) {
+                       remove_partial(n, slab);
+                       list_add(&slab->slab_list, &discard);
                } else {
-                       list_slab_objects(s, page,
+                       list_slab_objects(s, slab,
                          "Objects remaining in %s on __kmem_cache_shutdown()");
                }
        }
        spin_unlock_irq(&n->list_lock);
 
-       list_for_each_entry_safe(page, h, &discard, slab_list)
-               discard_slab(s, page);
+       list_for_each_entry_safe(slab, h, &discard, slab_list)
+               discard_slab(s, slab);
 }
 
 bool __kmem_cache_empty(struct kmem_cache *s)
@@ -4322,31 +4322,32 @@ int __kmem_cache_shutdown(struct kmem_cache *s)
 }
 
 #ifdef CONFIG_PRINTK
-void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
+void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct slab *slab)
 {
        void *base;
        int __maybe_unused i;
        unsigned int objnr;
        void *objp;
        void *objp0;
-       struct kmem_cache *s = page->slab_cache;
+       struct kmem_cache *s = slab->slab_cache;
        struct track __maybe_unused *trackp;
 
        kpp->kp_ptr = object;
-       kpp->kp_page = page;
+       kpp->kp_slab = slab;
        kpp->kp_slab_cache = s;
-       base = page_address(page);
+       base = slab_address(slab);
        objp0 = kasan_reset_tag(object);
 #ifdef CONFIG_SLUB_DEBUG
        objp = restore_red_left(s, objp0);
 #else
        objp = objp0;
 #endif
-       objnr = obj_to_index(s, page, objp);
+       objnr = obj_to_index(s, slab, objp);
        kpp->kp_data_offset = (unsigned long)((char *)objp0 - (char *)objp);
        objp = base + s->size * objnr;
        kpp->kp_objp = objp;
-       if (WARN_ON_ONCE(objp < base || objp >= base + page->objects * s->size || (objp - base) % s->size) ||
+       if (WARN_ON_ONCE(objp < base || objp >= base + slab->objects * s->size
+                        || (objp - base) % s->size) ||
            !(s->flags & SLAB_STORE_USER))
                return;
 #ifdef CONFIG_SLUB_DEBUG
@@ -4484,8 +4485,8 @@ EXPORT_SYMBOL(__kmalloc_node);
  * Returns NULL if check passes, otherwise const char * to name of cache
  * to indicate an error.
  */
-void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
-                        bool to_user)
+void __check_heap_object(const void *ptr, unsigned long n,
+                        const struct slab *slab, bool to_user)
 {
        struct kmem_cache *s;
        unsigned int offset;
@@ -4494,10 +4495,10 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
        ptr = kasan_reset_tag(ptr);
 
        /* Find object and usable object size. */
-       s = page->slab_cache;
+       s = slab->slab_cache;
 
        /* Reject impossible pointers. */
-       if (ptr < page_address(page))
+       if (ptr < slab_address(slab))
                usercopy_abort("SLUB object not in SLUB page?!", NULL,
                               to_user, 0, n);
 
@@ -4505,7 +4506,7 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
        if (is_kfence)
                offset = ptr - kfence_object_start(ptr);
        else
-               offset = (ptr - page_address(page)) % s->size;
+               offset = (ptr - slab_address(slab)) % s->size;
 
        /* Adjust for redzone and reject if within the redzone. */
        if (!is_kfence && kmem_cache_debug_flags(s, SLAB_RED_ZONE)) {
@@ -4527,25 +4528,24 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
 
 size_t __ksize(const void *object)
 {
-       struct page *page;
+       struct folio *folio;
 
        if (unlikely(object == ZERO_SIZE_PTR))
                return 0;
 
-       page = virt_to_head_page(object);
+       folio = virt_to_folio(object);
 
-       if (unlikely(!PageSlab(page))) {
-               WARN_ON(!PageCompound(page));
-               return page_size(page);
-       }
+       if (unlikely(!folio_test_slab(folio)))
+               return folio_size(folio);
 
-       return slab_ksize(page->slab_cache);
+       return slab_ksize(folio_slab(folio)->slab_cache);
 }
 EXPORT_SYMBOL(__ksize);
 
 void kfree(const void *x)
 {
-       struct page *page;
+       struct folio *folio;
+       struct slab *slab;
        void *object = (void *)x;
 
        trace_kfree(_RET_IP_, x);
@@ -4553,12 +4553,13 @@ void kfree(const void *x)
        if (unlikely(ZERO_OR_NULL_PTR(x)))
                return;
 
-       page = virt_to_head_page(x);
-       if (unlikely(!PageSlab(page))) {
-               free_nonslab_page(page, object);
+       folio = virt_to_folio(x);
+       if (unlikely(!folio_test_slab(folio))) {
+               free_large_kmalloc(folio, object);
                return;
        }
-       slab_free(page->slab_cache, page, object, NULL, 1, _RET_IP_);
+       slab = folio_slab(folio);
+       slab_free(slab->slab_cache, slab, object, NULL, 1, _RET_IP_);
 }
 EXPORT_SYMBOL(kfree);
 
@@ -4578,8 +4579,8 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s)
        int node;
        int i;
        struct kmem_cache_node *n;
-       struct page *page;
-       struct page *t;
+       struct slab *slab;
+       struct slab *t;
        struct list_head discard;
        struct list_head promote[SHRINK_PROMOTE_MAX];
        unsigned long flags;
@@ -4596,22 +4597,22 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s)
                 * Build lists of slabs to discard or promote.
                 *
                 * Note that concurrent frees may occur while we hold the
-                * list_lock. page->inuse here is the upper limit.
+                * list_lock. slab->inuse here is the upper limit.
                 */
-               list_for_each_entry_safe(page, t, &n->partial, slab_list) {
-                       int free = page->objects - page->inuse;
+               list_for_each_entry_safe(slab, t, &n->partial, slab_list) {
+                       int free = slab->objects - slab->inuse;
 
-                       /* Do not reread page->inuse */
+                       /* Do not reread slab->inuse */
                        barrier();
 
                        /* We do not keep full slabs on the list */
                        BUG_ON(free <= 0);
 
-                       if (free == page->objects) {
-                               list_move(&page->slab_list, &discard);
+                       if (free == slab->objects) {
+                               list_move(&slab->slab_list, &discard);
                                n->nr_partial--;
                        } else if (free <= SHRINK_PROMOTE_MAX)
-                               list_move(&page->slab_list, promote + free - 1);
+                               list_move(&slab->slab_list, promote + free - 1);
                }
 
                /*
@@ -4624,8 +4625,8 @@ static int __kmem_cache_do_shrink(struct kmem_cache *s)
                spin_unlock_irqrestore(&n->list_lock, flags);
 
                /* Release empty slabs */
-               list_for_each_entry_safe(page, t, &discard, slab_list)
-                       discard_slab(s, page);
+               list_for_each_entry_safe(slab, t, &discard, slab_list)
+                       discard_slab(s, slab);
 
                if (slabs_node(s, node))
                        ret = 1;
@@ -4786,7 +4787,7 @@ static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
         */
        __flush_cpu_slab(s, smp_processor_id());
        for_each_kmem_cache_node(s, node, n) {
-               struct page *p;
+               struct slab *p;
 
                list_for_each_entry(p, &n->partial, slab_list)
                        p->slab_cache = s;
@@ -4964,54 +4965,54 @@ EXPORT_SYMBOL(__kmalloc_node_track_caller);
 #endif
 
 #ifdef CONFIG_SYSFS
-static int count_inuse(struct page *page)
+static int count_inuse(struct slab *slab)
 {
-       return page->inuse;
+       return slab->inuse;
 }
 
-static int count_total(struct page *page)
+static int count_total(struct slab *slab)
 {
-       return page->objects;
+       return slab->objects;
 }
 #endif
 
 #ifdef CONFIG_SLUB_DEBUG
-static void validate_slab(struct kmem_cache *s, struct page *page,
+static void validate_slab(struct kmem_cache *s, struct slab *slab,
                          unsigned long *obj_map)
 {
        void *p;
-       void *addr = page_address(page);
+       void *addr = slab_address(slab);
        unsigned long flags;
 
-       slab_lock(page, &flags);
+       slab_lock(slab, &flags);
 
-       if (!check_slab(s, page) || !on_freelist(s, page, NULL))
+       if (!check_slab(s, slab) || !on_freelist(s, slab, NULL))
                goto unlock;
 
        /* Now we know that a valid freelist exists */
-       __fill_map(obj_map, s, page);
-       for_each_object(p, s, addr, page->objects) {
+       __fill_map(obj_map, s, slab);
+       for_each_object(p, s, addr, slab->objects) {
                u8 val = test_bit(__obj_to_index(s, addr, p), obj_map) ?
                         SLUB_RED_INACTIVE : SLUB_RED_ACTIVE;
 
-               if (!check_object(s, page, p, val))
+               if (!check_object(s, slab, p, val))
                        break;
        }
 unlock:
-       slab_unlock(page, &flags);
+       slab_unlock(slab, &flags);
 }
 
 static int validate_slab_node(struct kmem_cache *s,
                struct kmem_cache_node *n, unsigned long *obj_map)
 {
        unsigned long count = 0;
-       struct page *page;
+       struct slab *slab;
        unsigned long flags;
 
        spin_lock_irqsave(&n->list_lock, flags);
 
-       list_for_each_entry(page, &n->partial, slab_list) {
-               validate_slab(s, page, obj_map);
+       list_for_each_entry(slab, &n->partial, slab_list) {
+               validate_slab(s, slab, obj_map);
                count++;
        }
        if (count != n->nr_partial) {
@@ -5023,8 +5024,8 @@ static int validate_slab_node(struct kmem_cache *s,
        if (!(s->flags & SLAB_STORE_USER))
                goto out;
 
-       list_for_each_entry(page, &n->full, slab_list) {
-               validate_slab(s, page, obj_map);
+       list_for_each_entry(slab, &n->full, slab_list) {
+               validate_slab(s, slab, obj_map);
                count++;
        }
        if (count != atomic_long_read(&n->nr_slabs)) {
@@ -5081,6 +5082,7 @@ struct loc_track {
        unsigned long max;
        unsigned long count;
        struct location *loc;
+       loff_t idx;
 };
 
 static struct dentry *slab_debugfs_root;
@@ -5189,15 +5191,15 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
 }
 
 static void process_slab(struct loc_track *t, struct kmem_cache *s,
-               struct page *page, enum track_item alloc,
+               struct slab *slab, enum track_item alloc,
                unsigned long *obj_map)
 {
-       void *addr = page_address(page);
+       void *addr = slab_address(slab);
        void *p;
 
-       __fill_map(obj_map, s, page);
+       __fill_map(obj_map, s, slab);
 
-       for_each_object(p, s, addr, page->objects)
+       for_each_object(p, s, addr, slab->objects)
                if (!test_bit(__obj_to_index(s, addr, p), obj_map))
                        add_location(t, s, get_track(s, p, alloc));
 }
@@ -5239,35 +5241,37 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                        struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab,
                                                               cpu);
                        int node;
-                       struct page *page;
+                       struct slab *slab;
 
-                       page = READ_ONCE(c->page);
-                       if (!page)
+                       slab = READ_ONCE(c->slab);
+                       if (!slab)
                                continue;
 
-                       node = page_to_nid(page);
+                       node = slab_nid(slab);
                        if (flags & SO_TOTAL)
-                               x = page->objects;
+                               x = slab->objects;
                        else if (flags & SO_OBJECTS)
-                               x = page->inuse;
+                               x = slab->inuse;
                        else
                                x = 1;
 
                        total += x;
                        nodes[node] += x;
 
-                       page = slub_percpu_partial_read_once(c);
-                       if (page) {
-                               node = page_to_nid(page);
+#ifdef CONFIG_SLUB_CPU_PARTIAL
+                       slab = slub_percpu_partial_read_once(c);
+                       if (slab) {
+                               node = slab_nid(slab);
                                if (flags & SO_TOTAL)
                                        WARN_ON_ONCE(1);
                                else if (flags & SO_OBJECTS)
                                        WARN_ON_ONCE(1);
                                else
-                                       x = page->pages;
+                                       x = slab->slabs;
                                total += x;
                                nodes[node] += x;
                        }
+#endif
                }
        }
 
@@ -5466,33 +5470,35 @@ SLAB_ATTR_RO(objects_partial);
 static ssize_t slabs_cpu_partial_show(struct kmem_cache *s, char *buf)
 {
        int objects = 0;
-       int pages = 0;
-       int cpu;
+       int slabs = 0;
+       int cpu __maybe_unused;
        int len = 0;
 
+#ifdef CONFIG_SLUB_CPU_PARTIAL
        for_each_online_cpu(cpu) {
-               struct page *page;
+               struct slab *slab;
 
-               page = slub_percpu_partial(per_cpu_ptr(s->cpu_slab, cpu));
+               slab = slub_percpu_partial(per_cpu_ptr(s->cpu_slab, cpu));
 
-               if (page)
-                       pages += page->pages;
+               if (slab)
+                       slabs += slab->slabs;
        }
+#endif
 
-       /* Approximate half-full pages , see slub_set_cpu_partial() */
-       objects = (pages * oo_objects(s->oo)) / 2;
-       len += sysfs_emit_at(buf, len, "%d(%d)", objects, pages);
+       /* Approximate half-full slabs, see slub_set_cpu_partial() */
+       objects = (slabs * oo_objects(s->oo)) / 2;
+       len += sysfs_emit_at(buf, len, "%d(%d)", objects, slabs);
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SLUB_CPU_PARTIAL) && defined(CONFIG_SMP)
        for_each_online_cpu(cpu) {
-               struct page *page;
+               struct slab *slab;
 
-               page = slub_percpu_partial(per_cpu_ptr(s->cpu_slab, cpu));
-               if (page) {
-                       pages = READ_ONCE(page->pages);
-                       objects = (pages * oo_objects(s->oo)) / 2;
+               slab = slub_percpu_partial(per_cpu_ptr(s->cpu_slab, cpu));
+               if (slab) {
+                       slabs = READ_ONCE(slab->slabs);
+                       objects = (slabs * oo_objects(s->oo)) / 2;
                        len += sysfs_emit_at(buf, len, " C%d=%d(%d)",
-                                            cpu, objects, pages);
+                                            cpu, objects, slabs);
                }
        }
 #endif
@@ -6052,11 +6058,11 @@ __initcall(slab_sysfs_init);
 #if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)
 static int slab_debugfs_show(struct seq_file *seq, void *v)
 {
-
-       struct location *l;
-       unsigned int idx = *(unsigned int *)v;
        struct loc_track *t = seq->private;
+       struct location *l;
+       unsigned long idx;
 
+       idx = (unsigned long) t->idx;
        if (idx < t->count) {
                l = &t->loc[idx];
 
@@ -6105,16 +6111,18 @@ static void *slab_debugfs_next(struct seq_file *seq, void *v, loff_t *ppos)
 {
        struct loc_track *t = seq->private;
 
-       v = ppos;
-       ++*ppos;
+       t->idx = ++(*ppos);
        if (*ppos <= t->count)
-               return v;
+               return ppos;
 
        return NULL;
 }
 
 static void *slab_debugfs_start(struct seq_file *seq, loff_t *ppos)
 {
+       struct loc_track *t = seq->private;
+
+       t->idx = *ppos;
        return ppos;
 }
 
@@ -6158,16 +6166,16 @@ static int slab_debug_trace_open(struct inode *inode, struct file *filep)
 
        for_each_kmem_cache_node(s, node, n) {
                unsigned long flags;
-               struct page *page;
+               struct slab *slab;
 
                if (!atomic_long_read(&n->nr_slabs))
                        continue;
 
                spin_lock_irqsave(&n->list_lock, flags);
-               list_for_each_entry(page, &n->partial, slab_list)
-                       process_slab(t, s, page, alloc, obj_map);
-               list_for_each_entry(page, &n->full, slab_list)
-                       process_slab(t, s, page, alloc, obj_map);
+               list_for_each_entry(slab, &n->partial, slab_list)
+                       process_slab(t, s, slab, alloc, obj_map);
+               list_for_each_entry(slab, &n->full, slab_list)
+                       process_slab(t, s, slab, alloc, obj_map);
                spin_unlock_irqrestore(&n->list_lock, flags);
        }
 
index e5c84b0..d21c6e5 100644 (file)
@@ -722,7 +722,7 @@ static void free_map_bootmem(struct page *memmap)
                >> PAGE_SHIFT;
 
        for (i = 0; i < nr_pages; i++, page++) {
-               magic = (unsigned long) page->freelist;
+               magic = page->index;
 
                BUG_ON(magic == NODE_INFO);
 
index 16f706c..2b55318 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/swap_slots.h>
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
index b3de3c4..d0d2681 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/atomic.h>
 #include <linux/jump_label.h>
 #include <asm/sections.h>
+#include "slab.h"
 
 /*
  * Checks if a given pointer and length is contained by the current
@@ -223,7 +224,7 @@ static inline void check_page_span(const void *ptr, unsigned long n,
 static inline void check_heap_object(const void *ptr, unsigned long n,
                                     bool to_user)
 {
-       struct page *page;
+       struct folio *folio;
 
        if (!virt_addr_valid(ptr))
                return;
@@ -231,16 +232,16 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
        /*
         * When CONFIG_HIGHMEM=y, kmap_to_page() will give either the
         * highmem page or fallback to virt_to_page(). The following
-        * is effectively a highmem-aware virt_to_head_page().
+        * is effectively a highmem-aware virt_to_slab().
         */
-       page = compound_head(kmap_to_page((void *)ptr));
+       folio = page_folio(kmap_to_page((void *)ptr));
 
-       if (PageSlab(page)) {
+       if (folio_test_slab(folio)) {
                /* Check slab allocator for flags and size. */
-               __check_heap_object(ptr, n, page, to_user);
+               __check_heap_object(ptr, n, folio_slab(folio), to_user);
        } else {
                /* Verify object does not incorrectly span multiple pages. */
-               check_page_span(ptr, n, page, to_user);
+               check_page_span(ptr, n, folio_page(folio, 0), to_user);
        }
 }
 
index b897ce3..0d3b659 100644 (file)
  *
  * Usage of struct page fields:
  *     page->private: points to zspage
- *     page->freelist(index): links together all component pages of a zspage
+ *     page->index: links together all component pages of a zspage
  *             For the huge page, this is always 0, so we use this field
  *             to store handle.
- *     page->units: first object offset in a subpage of zspage
+ *     page->page_type: first object offset in a subpage of zspage
  *
  * Usage of struct page flags:
  *     PG_private: identifies the first component page
@@ -489,12 +489,12 @@ static inline struct page *get_first_page(struct zspage *zspage)
 
 static inline int get_first_obj_offset(struct page *page)
 {
-       return page->units;
+       return page->page_type;
 }
 
 static inline void set_first_obj_offset(struct page *page, int offset)
 {
-       page->units = offset;
+       page->page_type = offset;
 }
 
 static inline unsigned int get_freeobj(struct zspage *zspage)
@@ -827,7 +827,7 @@ static struct page *get_next_page(struct page *page)
        if (unlikely(PageHugeObject(page)))
                return NULL;
 
-       return page->freelist;
+       return (struct page *)page->index;
 }
 
 /**
@@ -901,7 +901,7 @@ static void reset_page(struct page *page)
        set_page_private(page, 0);
        page_mapcount_reset(page);
        ClearPageHugeObject(page);
-       page->freelist = NULL;
+       page->index = 0;
 }
 
 static int trylock_zspage(struct zspage *zspage)
@@ -1027,7 +1027,7 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,
 
        /*
         * Allocate individual pages and link them together as:
-        * 1. all pages are linked together using page->freelist
+        * 1. all pages are linked together using page->index
         * 2. each sub-page point to zspage using page->private
         *
         * we set PG_private to identify the first page (i.e. no other sub-page
@@ -1036,7 +1036,7 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,
        for (i = 0; i < nr_pages; i++) {
                page = pages[i];
                set_page_private(page, (unsigned long)zspage);
-               page->freelist = NULL;
+               page->index = 0;
                if (i == 0) {
                        zspage->first_page = page;
                        SetPagePrivate(page);
@@ -1044,7 +1044,7 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,
                                        class->pages_per_zspage == 1))
                                SetPageHugeObject(page);
                } else {
-                       prev_page->freelist = page;
+                       prev_page->index = (unsigned long)page;
                }
                prev_page = page;
        }
index 5ad72db..c06c9ba 100644 (file)
@@ -4110,14 +4110,6 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
                return err;
        }
 
-       if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
-           info->attrs[DEVLINK_ATTR_NETNS_FD] ||
-           info->attrs[DEVLINK_ATTR_NETNS_ID]) {
-               dest_net = devlink_netns_get(skb, info);
-               if (IS_ERR(dest_net))
-                       return PTR_ERR(dest_net);
-       }
-
        if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION])
                action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]);
        else
@@ -4160,6 +4152,14 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
                }
        }
+       if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
+           info->attrs[DEVLINK_ATTR_NETNS_FD] ||
+           info->attrs[DEVLINK_ATTR_NETNS_ID]) {
+               dest_net = devlink_netns_get(skb, info);
+               if (IS_ERR(dest_net))
+                       return PTR_ERR(dest_net);
+       }
+
        err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack);
 
        if (dest_net)
index 72ba027..dda12fb 100644 (file)
@@ -763,11 +763,10 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
 
        ASSERT_RTNL();
 
-       n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
+       n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
        if (!n)
                goto out;
 
-       n->protocol = 0;
        write_pnet(&n->net, net);
        memcpy(n->key, pkey, key_len);
        n->dev = dev;
index ba2f382..909db87 100644 (file)
@@ -832,7 +832,7 @@ void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt)
               ntohs(skb->protocol), skb->pkt_type, skb->skb_iif);
 
        if (dev)
-               printk("%sdev name=%s feat=0x%pNF\n",
+               printk("%sdev name=%s feat=%pNF\n",
                       level, dev->name, &dev->features);
        if (sk)
                printk("%ssk family=%hu type=%u proto=%u\n",
index 1ae52ac..8eb671c 100644 (file)
@@ -1124,6 +1124,8 @@ void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
 
 void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
 {
+       psock_set_prog(&psock->progs.stream_parser, NULL);
+
        if (!psock->saved_data_ready)
                return;
 
@@ -1212,6 +1214,9 @@ void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock)
 
 void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
 {
+       psock_set_prog(&psock->progs.stream_verdict, NULL);
+       psock_set_prog(&psock->progs.skb_verdict, NULL);
+
        if (!psock->saved_data_ready)
                return;
 
index f39ef79..4ca4b11 100644 (file)
@@ -167,8 +167,11 @@ static void sock_map_del_link(struct sock *sk,
                write_lock_bh(&sk->sk_callback_lock);
                if (strp_stop)
                        sk_psock_stop_strp(sk, psock);
-               else
+               if (verdict_stop)
                        sk_psock_stop_verdict(sk, psock);
+
+               if (psock->psock_update_sk_prot)
+                       psock->psock_update_sk_prot(sk, psock, false);
                write_unlock_bh(&sk->sk_callback_lock);
        }
 }
@@ -282,6 +285,12 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
 
        if (msg_parser)
                psock_set_prog(&psock->progs.msg_parser, msg_parser);
+       if (stream_parser)
+               psock_set_prog(&psock->progs.stream_parser, stream_parser);
+       if (stream_verdict)
+               psock_set_prog(&psock->progs.stream_verdict, stream_verdict);
+       if (skb_verdict)
+               psock_set_prog(&psock->progs.skb_verdict, skb_verdict);
 
        ret = sock_map_init_proto(sk, psock);
        if (ret < 0)
@@ -292,14 +301,10 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
                ret = sk_psock_init_strp(sk, psock);
                if (ret)
                        goto out_unlock_drop;
-               psock_set_prog(&psock->progs.stream_verdict, stream_verdict);
-               psock_set_prog(&psock->progs.stream_parser, stream_parser);
                sk_psock_start_strp(sk, psock);
        } else if (!stream_parser && stream_verdict && !psock->saved_data_ready) {
-               psock_set_prog(&psock->progs.stream_verdict, stream_verdict);
                sk_psock_start_verdict(sk,psock);
        } else if (!stream_verdict && skb_verdict && !psock->saved_data_ready) {
-               psock_set_prog(&psock->progs.skb_verdict, skb_verdict);
                sk_psock_start_verdict(sk, psock);
        }
        write_unlock_bh(&sk->sk_callback_lock);
index 38b44c0..96f4180 100644 (file)
@@ -40,7 +40,8 @@ int ethnl_ops_begin(struct net_device *dev)
        if (dev->dev.parent)
                pm_runtime_get_sync(dev->dev.parent);
 
-       if (!netif_device_present(dev)) {
+       if (!netif_device_present(dev) ||
+           dev->reg_state == NETREG_UNREGISTERING) {
                ret = -ENODEV;
                goto err;
        }
index f7fea3a..62a67fd 100644 (file)
@@ -721,7 +721,7 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
 
        sk_node_init(&nreq_sk->sk_node);
        nreq_sk->sk_tx_queue_mapping = req_sk->sk_tx_queue_mapping;
-#ifdef CONFIG_XPS
+#ifdef CONFIG_SOCK_RX_QUEUE_MAPPING
        nreq_sk->sk_rx_queue_mapping = req_sk->sk_rx_queue_mapping;
 #endif
        nreq_sk->sk_incoming_cpu = req_sk->sk_incoming_cpu;
index c8fa6e7..581b5b2 100644 (file)
@@ -261,6 +261,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
        r->idiag_state = sk->sk_state;
        r->idiag_timer = 0;
        r->idiag_retrans = 0;
+       r->idiag_expires = 0;
 
        if (inet_diag_msg_attrs_fill(sk, skb, r, ext,
                                     sk_user_ns(NETLINK_CB(cb->skb).sk),
@@ -314,9 +315,6 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                r->idiag_retrans = icsk->icsk_probes_out;
                r->idiag_expires =
                        jiffies_delta_to_msecs(sk->sk_timer.expires - jiffies);
-       } else {
-               r->idiag_timer = 0;
-               r->idiag_expires = 0;
        }
 
        if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) {
index cf913a6..7c2d3ac 100644 (file)
@@ -829,8 +829,8 @@ int tcp_child_process(struct sock *parent, struct sock *child,
        int ret = 0;
        int state = child->sk_state;
 
-       /* record NAPI ID of child */
-       sk_mark_napi_id(child, skb);
+       /* record sk_napi_id and sk_rx_queue_mapping of child. */
+       sk_mark_napi_id_set(child, skb);
 
        tcp_segs_in(tcp_sk(child), skb);
        if (!sock_owned_by_user(child)) {
index 8bcecdd..23b05e2 100644 (file)
@@ -916,7 +916,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
                        kfree_skb(skb);
                        return -EINVAL;
                }
-               if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) {
+               if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) {
                        kfree_skb(skb);
                        return -EINVAL;
                }
index 3adc5d9..d648550 100644 (file)
@@ -161,6 +161,14 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
                hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
 
                memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+
+               /* the control block has been erased, so we have to set the
+                * iif once again.
+                * We read the receiving interface index directly from the
+                * skb->skb_iif as it is done in the IPv4 receiving path (i.e.:
+                * ip_rcv_core(...)).
+                */
+               IP6CB(skb)->iif = skb->skb_iif;
        }
 
        hdr->nexthdr = NEXTHDR_ROUTING;
index 1b57ee3..8a3618a 100644 (file)
@@ -1933,7 +1933,6 @@ static int __net_init sit_init_net(struct net *net)
        return 0;
 
 err_reg_dev:
-       ipip6_dev_free(sitn->fb_tunnel_dev);
        free_netdev(sitn->fb_tunnel_dev);
 err_alloc_dev:
        return err;
index 470ff0c..7d2925b 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
  */
 
 /**
@@ -191,7 +191,8 @@ static void ieee80211_add_addbaext(struct ieee80211_sub_if_data *sdata,
        sband = ieee80211_get_sband(sdata);
        if (!sband)
                return;
-       he_cap = ieee80211_get_he_iftype_cap(sband, sdata->vif.type);
+       he_cap = ieee80211_get_he_iftype_cap(sband,
+                                            ieee80211_vif_type_p2p(&sdata->vif));
        if (!he_cap)
                return;
 
index 430a585..74a878f 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2020 Intel Corporation
+ * Copyright (C) 2018 - 2021 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -106,7 +106,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.addba_req.start_seq_num =
                                        cpu_to_le16(start_seq_num << 4);
 
-       ieee80211_tx_skb(sdata, skb);
+       ieee80211_tx_skb_tid(sdata, skb, tid);
 }
 
 void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
@@ -213,6 +213,8 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
        struct ieee80211_txq *txq = sta->sta.txq[tid];
        struct txq_info *txqi;
 
+       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+
        if (!txq)
                return;
 
@@ -290,7 +292,6 @@ static void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
        ieee80211_assign_tid_tx(sta, tid, NULL);
 
        ieee80211_agg_splice_finish(sta->sdata, tid);
-       ieee80211_agg_start_txq(sta, tid, false);
 
        kfree_rcu(tid_tx, rcu_head);
 }
@@ -480,8 +481,7 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
 
        /* send AddBA request */
        ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
-                                    tid_tx->dialog_token,
-                                    sta->tid_seq[tid] >> 4,
+                                    tid_tx->dialog_token, tid_tx->ssn,
                                     buf_size, tid_tx->timeout);
 
        WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
@@ -523,6 +523,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 
        params.ssn = sta->tid_seq[tid] >> 4;
        ret = drv_ampdu_action(local, sdata, &params);
+       tid_tx->ssn = params.ssn;
        if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
                return;
        } else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
@@ -889,6 +890,7 @@ void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        bool send_delba = false;
+       bool start_txq = false;
 
        ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n",
               sta->sta.addr, tid);
@@ -906,10 +908,14 @@ void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
                send_delba = true;
 
        ieee80211_remove_tid_tx(sta, tid);
+       start_txq = true;
 
  unlock_sta:
        spin_unlock_bh(&sta->lock);
 
+       if (start_txq)
+               ieee80211_agg_start_txq(sta, tid, false);
+
        if (send_delba)
                ieee80211_send_delba(sdata, sta->sta.addr, tid,
                        WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
index cd3731c..c336267 100644 (file)
@@ -1219,8 +1219,11 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
 
-       if (local->in_reconfig)
+       /* In reconfig don't transmit now, but mark for waking later */
+       if (local->in_reconfig) {
+               set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txq->flags);
                return;
+       }
 
        if (!check_sdata_in_driver(sdata))
                return;
index 54ab0e1..37f7d97 100644 (file)
@@ -2452,11 +2452,18 @@ static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
                                           u16 tx_time)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       u16 tid = ieee80211_get_tid(hdr);
-       int ac = ieee80211_ac_from_tid(tid);
-       struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+       u16 tid;
+       int ac;
+       struct ieee80211_sta_tx_tspec *tx_tspec;
        unsigned long now = jiffies;
 
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return;
+
+       tid = ieee80211_get_tid(hdr);
+       ac = ieee80211_ac_from_tid(tid);
+       tx_tspec = &ifmgd->tx_tspec[ac];
+
        if (likely(!tx_tspec->admitted_time))
                return;
 
index 9541a4c..0544563 100644 (file)
@@ -2944,6 +2944,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        if (!fwd_skb)
                goto out;
 
+       fwd_skb->dev = sdata->dev;
        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
        fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
        info = IEEE80211_SKB_CB(fwd_skb);
index 51b49f0..537535a 100644 (file)
@@ -644,13 +644,13 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        /* check if STA exists already */
        if (sta_info_get_bss(sdata, sta->sta.addr)) {
                err = -EEXIST;
-               goto out_err;
+               goto out_cleanup;
        }
 
        sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
        if (!sinfo) {
                err = -ENOMEM;
-               goto out_err;
+               goto out_cleanup;
        }
 
        local->num_sta++;
@@ -667,6 +667,15 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 
        list_add_tail_rcu(&sta->list, &local->sta_list);
 
+       /* update channel context before notifying the driver about state
+        * change, this enables driver using the updated channel context right away.
+        */
+       if (sta->sta_state >= IEEE80211_STA_ASSOC) {
+               ieee80211_recalc_min_chandef(sta->sdata);
+               if (!sta->sta.support_p2p_ps)
+                       ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
+       }
+
        /* notify driver */
        err = sta_info_insert_drv_state(local, sdata, sta);
        if (err)
@@ -674,12 +683,6 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 
        set_sta_flag(sta, WLAN_STA_INSERTED);
 
-       if (sta->sta_state >= IEEE80211_STA_ASSOC) {
-               ieee80211_recalc_min_chandef(sta->sdata);
-               if (!sta->sta.support_p2p_ps)
-                       ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
-       }
-
        /* accept BA sessions now */
        clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
 
@@ -706,8 +709,8 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
  out_drop_sta:
        local->num_sta--;
        synchronize_net();
+ out_cleanup:
        cleanup_single_sta(sta);
- out_err:
        mutex_unlock(&local->sta_mtx);
        kfree(sinfo);
        rcu_read_lock();
index ba27967..379fd36 100644 (file)
@@ -176,6 +176,7 @@ struct sta_info;
  * @failed_bar_ssn: ssn of the last failed BAR tx attempt
  * @bar_pending: BAR needs to be re-sent
  * @amsdu: support A-MSDU withing A-MDPU
+ * @ssn: starting sequence number of the session
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -199,6 +200,7 @@ struct tid_ampdu_tx {
        u8 stop_initiator;
        bool tx_stop;
        u16 buf_size;
+       u16 ssn;
 
        u16 failed_bar_ssn;
        bool bar_pending;
index 278945e..86a54df 100644 (file)
@@ -1822,15 +1822,15 @@ static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        ieee80211_tx_result res = TX_CONTINUE;
 
+       if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
+               CALL_TXH(ieee80211_tx_h_rate_ctrl);
+
        if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
                __skb_queue_tail(&tx->skbs, tx->skb);
                tx->skb = NULL;
                goto txh_done;
        }
 
-       if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
-               CALL_TXH(ieee80211_tx_h_rate_ctrl);
-
        CALL_TXH(ieee80211_tx_h_michael_mic_add);
        CALL_TXH(ieee80211_tx_h_sequence);
        CALL_TXH(ieee80211_tx_h_fragment);
@@ -4191,11 +4191,11 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
 
        ieee80211_aggr_check(sdata, sta, skb);
 
+       sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
+
        if (sta) {
                struct ieee80211_fast_tx *fast_tx;
 
-               sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
-
                fast_tx = rcu_dereference(sta->fast_tx);
 
                if (fast_tx &&
index 43df2f0..0e4e195 100644 (file)
@@ -943,7 +943,12 @@ static void ieee80211_parse_extension_element(u32 *crc,
                                              struct ieee802_11_elems *elems)
 {
        const void *data = elem->data + 1;
-       u8 len = elem->datalen - 1;
+       u8 len;
+
+       if (!elem->datalen)
+               return;
+
+       len = elem->datalen - 1;
 
        switch (elem->data[0]) {
        case WLAN_EID_EXT_HE_MU_EDCA:
@@ -2063,7 +2068,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
                chandef.chan = chan;
 
        skb = ieee80211_probereq_get(&local->hw, src, ssid, ssid_len,
-                                    100 + ie_len);
+                                    local->scan_ies_len + ie_len);
        if (!skb)
                return NULL;
 
@@ -2646,6 +2651,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                mutex_unlock(&local->sta_mtx);
        }
 
+       /*
+        * If this is for hw restart things are still running.
+        * We may want to change that later, however.
+        */
+       if (local->open_count && (!suspended || reconfig_due_to_wowlan))
+               drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
+
        if (local->in_reconfig) {
                local->in_reconfig = false;
                barrier();
@@ -2664,13 +2676,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                        IEEE80211_QUEUE_STOP_REASON_SUSPEND,
                                        false);
 
-       /*
-        * If this is for hw restart things are still running.
-        * We may want to change that later, however.
-        */
-       if (local->open_count && (!suspended || reconfig_due_to_wowlan))
-               drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
-
        if (!suspended)
                return 0;
 
index 7b96be1..f523051 100644 (file)
@@ -700,6 +700,9 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
 
        msk_owned_by_me(msk);
 
+       if (sk->sk_state == TCP_LISTEN)
+               return;
+
        if (!rm_list->nr)
                return;
 
index c82a76d..54613f5 100644 (file)
@@ -1524,7 +1524,7 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
                        int ret = 0;
 
                        prev_ssk = ssk;
-                       mptcp_flush_join_list(msk);
+                       __mptcp_flush_join_list(msk);
                        ssk = mptcp_subflow_get_send(msk);
 
                        /* First check. If the ssk has changed since
@@ -2879,7 +2879,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
                 */
                if (WARN_ON_ONCE(!new_mptcp_sock)) {
                        tcp_sk(newsk)->is_mptcp = 0;
-                       return newsk;
+                       goto out;
                }
 
                /* acquire the 2nd reference for the owning socket */
@@ -2891,6 +2891,8 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
                                MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK);
        }
 
+out:
+       newsk->sk_kern_sock = kern;
        return newsk;
 }
 
index 0f1e661..f8efd47 100644 (file)
@@ -525,7 +525,6 @@ static bool mptcp_supported_sockopt(int level, int optname)
                case TCP_NODELAY:
                case TCP_THIN_LINEAR_TIMEOUTS:
                case TCP_CONGESTION:
-               case TCP_ULP:
                case TCP_CORK:
                case TCP_KEEPIDLE:
                case TCP_KEEPINTVL:
index 770a631..4712a90 100644 (file)
@@ -684,7 +684,7 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
 
        tstamp = nf_conn_tstamp_find(ct);
        if (tstamp) {
-               s32 timeout = ct->timeout - nfct_time_stamp;
+               s32 timeout = READ_ONCE(ct->timeout) - nfct_time_stamp;
 
                tstamp->stop = ktime_get_real_ns();
                if (timeout < 0)
@@ -1036,7 +1036,7 @@ static int nf_ct_resolve_clash_harder(struct sk_buff *skb, u32 repl_idx)
        }
 
        /* We want the clashing entry to go away real soon: 1 second timeout. */
-       loser_ct->timeout = nfct_time_stamp + HZ;
+       WRITE_ONCE(loser_ct->timeout, nfct_time_stamp + HZ);
 
        /* IPS_NAT_CLASH removes the entry automatically on the first
         * reply.  Also prevents UDP tracker from moving the entry to
@@ -1560,7 +1560,7 @@ __nf_conntrack_alloc(struct net *net,
        /* save hash for reusing when confirming */
        *(unsigned long *)(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev) = hash;
        ct->status = 0;
-       ct->timeout = 0;
+       WRITE_ONCE(ct->timeout, 0);
        write_pnet(&ct->ct_net, net);
        memset(&ct->__nfct_init_offset, 0,
               offsetof(struct nf_conn, proto) -
index c7708bd..81d03ac 100644 (file)
@@ -1998,7 +1998,7 @@ static int ctnetlink_change_timeout(struct nf_conn *ct,
 
        if (timeout > INT_MAX)
                timeout = INT_MAX;
-       ct->timeout = nfct_time_stamp + (u32)timeout;
+       WRITE_ONCE(ct->timeout, nfct_time_stamp + (u32)timeout);
 
        if (test_bit(IPS_DYING_BIT, &ct->status))
                return -ETIME;
index 87a7388..ed37bb9 100644 (file)
@@ -201,8 +201,8 @@ static void flow_offload_fixup_ct_timeout(struct nf_conn *ct)
        if (timeout < 0)
                timeout = 0;
 
-       if (nf_flow_timeout_delta(ct->timeout) > (__s32)timeout)
-               ct->timeout = nfct_time_stamp + timeout;
+       if (nf_flow_timeout_delta(READ_ONCE(ct->timeout)) > (__s32)timeout)
+               WRITE_ONCE(ct->timeout, nfct_time_stamp + timeout);
 }
 
 static void flow_offload_fixup_ct_state(struct nf_conn *ct)
index 4acc4b8..5837e8e 100644 (file)
@@ -387,7 +387,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
        struct net_device *indev;
        struct net_device *outdev;
        struct nf_conn *ct = NULL;
-       enum ip_conntrack_info ctinfo;
+       enum ip_conntrack_info ctinfo = 0;
        struct nfnl_ct_hook *nfnl_ct;
        bool csum_verify;
        char *secdata = NULL;
index af4ee87..dbe1f2e 100644 (file)
@@ -236,7 +236,7 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
 
        tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
        if (!tcph)
-               return;
+               goto err;
 
        opt = (u8 *)tcph;
        for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
@@ -251,16 +251,16 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
                        continue;
 
                if (i + optl > tcphdr_len || priv->len + priv->offset > optl)
-                       return;
+                       goto err;
 
                if (skb_ensure_writable(pkt->skb,
                                        nft_thoff(pkt) + i + priv->len))
-                       return;
+                       goto err;
 
                tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
                                              &tcphdr_len);
                if (!tcph)
-                       return;
+                       goto err;
 
                offset = i + priv->offset;
 
@@ -303,6 +303,9 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
 
                return;
        }
+       return;
+err:
+       regs->verdict.code = NFT_BREAK;
 }
 
 static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
index e517663..6f4116e 100644 (file)
@@ -886,7 +886,7 @@ static int nft_pipapo_avx2_lookup_8b_6(unsigned long *map, unsigned long *fill,
                        NFT_PIPAPO_AVX2_BUCKET_LOAD8(4,  lt, 4, pkt[4], bsize);
 
                        NFT_PIPAPO_AVX2_AND(5, 0, 1);
-                       NFT_PIPAPO_AVX2_BUCKET_LOAD8(6,  lt, 6, pkt[5], bsize);
+                       NFT_PIPAPO_AVX2_BUCKET_LOAD8(6,  lt, 5, pkt[5], bsize);
                        NFT_PIPAPO_AVX2_AND(7, 2, 3);
 
                        /* Stall */
index 334f63c..f184b0d 100644 (file)
@@ -636,8 +636,10 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
 {
        struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
 
-       nfc_device_iter_exit(iter);
-       kfree(iter);
+       if (iter) {
+               nfc_device_iter_exit(iter);
+               kfree(iter);
+       }
 
        return 0;
 }
@@ -1392,8 +1394,10 @@ static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
 {
        struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
 
-       nfc_device_iter_exit(iter);
-       kfree(iter);
+       if (iter) {
+               nfc_device_iter_exit(iter);
+               kfree(iter);
+       }
 
        return 0;
 }
index 46943a1..76c2dca 100644 (file)
@@ -4492,9 +4492,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
        }
 
 out_free_pg_vec:
-       bitmap_free(rx_owner_map);
-       if (pg_vec)
+       if (pg_vec) {
+               bitmap_free(rx_owner_map);
                free_pg_vec(pg_vec, order, req->tp_block_nr);
+       }
 out:
        return err;
 }
index a152591..b4f90af 100644 (file)
@@ -868,6 +868,7 @@ static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp,
 
        err = pep_accept_conn(newsk, skb);
        if (err) {
+               __sock_put(sk);
                sock_put(newsk);
                newsk = NULL;
                goto drop;
index a3bc4b5..b4cc699 100644 (file)
@@ -253,6 +253,7 @@ static struct rds_connection *__rds_conn_create(struct net *net,
                                 * should end up here, but if it
                                 * does, reset/destroy the connection.
                                 */
+                               kfree(conn->c_path);
                                kmem_cache_free(rds_conn_slab, conn);
                                conn = ERR_PTR(-EOPNOTSUPP);
                                goto out;
index 2ef8f5a..e54f0a4 100644 (file)
@@ -3687,6 +3687,7 @@ int tc_setup_flow_action(struct flow_action *flow_action,
                                entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
                                break;
                        default:
+                               err = -EOPNOTSUPP;
                                goto err_out_locked;
                        }
                } else if (is_tcf_skbedit_ptype(act)) {
index 3c2300d..857aaeb 100644 (file)
@@ -2736,7 +2736,7 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
        q->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
                           GFP_KERNEL);
        if (!q->tins)
-               goto nomem;
+               return -ENOMEM;
 
        for (i = 0; i < CAKE_MAX_TINS; i++) {
                struct cake_tin_data *b = q->tins + i;
@@ -2766,10 +2766,6 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
        q->min_netlen = ~0;
        q->min_adjlen = ~0;
        return 0;
-
-nomem:
-       cake_destroy(sch);
-       return -ENOMEM;
 }
 
 static int cake_dump(struct Qdisc *sch, struct sk_buff *skb)
index e007fc7..d733934 100644 (file)
@@ -666,9 +666,9 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,
                }
        }
        for (i = q->nbands; i < oldbands; i++) {
-               qdisc_tree_flush_backlog(q->classes[i].qdisc);
-               if (i >= q->nstrict)
+               if (i >= q->nstrict && q->classes[i].qdisc->q.qlen)
                        list_del(&q->classes[i].alist);
+               qdisc_tree_flush_backlog(q->classes[i].qdisc);
        }
        q->nstrict = nstrict;
        memcpy(q->prio2band, priomap, sizeof(priomap));
index 830f355..d6aba6e 100644 (file)
@@ -531,6 +531,7 @@ static void fq_pie_destroy(struct Qdisc *sch)
        struct fq_pie_sched_data *q = qdisc_priv(sch);
 
        tcf_block_put(q->block);
+       q->p_params.tupdate = 0;
        del_timer_sync(&q->adapt_timer);
        kvfree(q->flows);
 }
index 230072f..1c9289f 100644 (file)
@@ -194,7 +194,9 @@ static int smc_release(struct socket *sock)
        /* cleanup for a dangling non-blocking connect */
        if (smc->connect_nonblock && sk->sk_state == SMC_INIT)
                tcp_abort(smc->clcsock->sk, ECONNABORTED);
-       flush_work(&smc->connect_work);
+
+       if (cancel_work_sync(&smc->connect_work))
+               sock_put(&smc->sk); /* sock_hold in smc_connect for passive closing */
 
        if (sk->sk_state == SMC_LISTEN)
                /* smc_close_non_accepted() is called and acquires
index 59ee1be..ec2c2af 100644 (file)
@@ -1299,7 +1299,8 @@ void virtio_transport_recv_pkt(struct virtio_transport *t,
        space_available = virtio_transport_space_update(sk, pkt);
 
        /* Update CID in case it has changed after a transport reset event */
-       vsk->local_addr.svm_cid = dst.svm_cid;
+       if (vsk->local_addr.svm_cid != VMADDR_CID_ANY)
+               vsk->local_addr.svm_cid = dst.svm_cid;
 
        if (space_available)
                sk->sk_write_space(sk);
index df87c7f..f8f01a3 100644 (file)
@@ -133,6 +133,7 @@ static u32 reg_is_indoor_portid;
 
 static void restore_regulatory_settings(bool reset_user, bool cached);
 static void print_regdomain(const struct ieee80211_regdomain *rd);
+static void reg_process_hint(struct regulatory_request *reg_request);
 
 static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
 {
@@ -1098,6 +1099,8 @@ int reg_reload_regdb(void)
        const struct firmware *fw;
        void *db;
        int err;
+       const struct ieee80211_regdomain *current_regdomain;
+       struct regulatory_request *request;
 
        err = request_firmware(&fw, "regulatory.db", &reg_pdev->dev);
        if (err)
@@ -1118,8 +1121,26 @@ int reg_reload_regdb(void)
        if (!IS_ERR_OR_NULL(regdb))
                kfree(regdb);
        regdb = db;
-       rtnl_unlock();
 
+       /* reset regulatory domain */
+       current_regdomain = get_cfg80211_regdom();
+
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (!request) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+
+       request->wiphy_idx = WIPHY_IDX_INVALID;
+       request->alpha2[0] = current_regdomain->alpha2[0];
+       request->alpha2[1] = current_regdomain->alpha2[1];
+       request->initiator = NL80211_REGDOM_SET_BY_CORE;
+       request->user_reg_hint_type = NL80211_USER_REG_HINT_USER;
+
+       reg_process_hint(request);
+
+out_unlock:
+       rtnl_unlock();
  out:
        release_firmware(fw);
        return err;
@@ -2338,6 +2359,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
        struct cfg80211_chan_def chandef = {};
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        enum nl80211_iftype iftype;
+       bool ret;
 
        wdev_lock(wdev);
        iftype = wdev->iftype;
@@ -2387,7 +2409,11 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
+               wiphy_lock(wiphy);
+               ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
+               wiphy_unlock(wiphy);
+
+               return ret;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
                return cfg80211_chandef_usable(wiphy, &chandef,
index f16074e..7a466ea 100644 (file)
@@ -677,8 +677,6 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
        struct xdp_sock *xs = xdp_sk(sk);
        struct xsk_buff_pool *pool;
 
-       sock_poll_wait(file, sock, wait);
-
        if (unlikely(!xsk_is_bound(xs)))
                return mask;
 
@@ -690,6 +688,8 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
                else
                        /* Poll needs to drive Tx also in copy mode */
                        __xsk_sendmsg(sk);
+       } else {
+               sock_poll_wait(file, sock, wait);
        }
 
        if (xs->rx && !xskq_prod_is_empty(xs->rx))
index b9198e2..faf8cdb 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct.o
 obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-too.o
 obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o
 obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi.o
+obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi-modify.o
 
 CFLAGS_sample-trace-array.o := -I$(src)
 obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o
diff --git a/samples/ftrace/ftrace-direct-multi-modify.c b/samples/ftrace/ftrace-direct-multi-modify.c
new file mode 100644 (file)
index 0000000..91bc42a
--- /dev/null
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/ftrace.h>
+#include <asm/asm-offsets.h>
+
+void my_direct_func1(unsigned long ip)
+{
+       trace_printk("my direct func1 ip %lx\n", ip);
+}
+
+void my_direct_func2(unsigned long ip)
+{
+       trace_printk("my direct func2 ip %lx\n", ip);
+}
+
+extern void my_tramp1(void *);
+extern void my_tramp2(void *);
+
+#ifdef CONFIG_X86_64
+
+asm (
+"      .pushsection    .text, \"ax\", @progbits\n"
+"      .type           my_tramp1, @function\n"
+"      .globl          my_tramp1\n"
+"   my_tramp1:"
+"      pushq %rbp\n"
+"      movq %rsp, %rbp\n"
+"      pushq %rdi\n"
+"      movq 8(%rbp), %rdi\n"
+"      call my_direct_func1\n"
+"      popq %rdi\n"
+"      leave\n"
+"      ret\n"
+"      .size           my_tramp1, .-my_tramp1\n"
+"      .type           my_tramp2, @function\n"
+"\n"
+"      .globl          my_tramp2\n"
+"   my_tramp2:"
+"      pushq %rbp\n"
+"      movq %rsp, %rbp\n"
+"      pushq %rdi\n"
+"      movq 8(%rbp), %rdi\n"
+"      call my_direct_func2\n"
+"      popq %rdi\n"
+"      leave\n"
+"      ret\n"
+"      .size           my_tramp2, .-my_tramp2\n"
+"      .popsection\n"
+);
+
+#endif /* CONFIG_X86_64 */
+
+#ifdef CONFIG_S390
+
+asm (
+"       .pushsection    .text, \"ax\", @progbits\n"
+"       .type           my_tramp1, @function\n"
+"       .globl          my_tramp1\n"
+"   my_tramp1:"
+"       lgr             %r1,%r15\n"
+"       stmg            %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
+"       stg             %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
+"       aghi            %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
+"       stg             %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
+"       lgr             %r2,%r0\n"
+"       brasl           %r14,my_direct_func1\n"
+"       aghi            %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
+"       lmg             %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
+"       lg              %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
+"       lgr             %r1,%r0\n"
+"       br              %r1\n"
+"       .size           my_tramp1, .-my_tramp1\n"
+"\n"
+"       .type           my_tramp2, @function\n"
+"       .globl          my_tramp2\n"
+"   my_tramp2:"
+"       lgr             %r1,%r15\n"
+"       stmg            %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
+"       stg             %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
+"       aghi            %r15,"__stringify(-STACK_FRAME_OVERHEAD)"\n"
+"       stg             %r1,"__stringify(__SF_BACKCHAIN)"(%r15)\n"
+"       lgr             %r2,%r0\n"
+"       brasl           %r14,my_direct_func2\n"
+"       aghi            %r15,"__stringify(STACK_FRAME_OVERHEAD)"\n"
+"       lmg             %r0,%r5,"__stringify(__SF_GPRS)"(%r15)\n"
+"       lg              %r14,"__stringify(__SF_GPRS+8*8)"(%r15)\n"
+"       lgr             %r1,%r0\n"
+"       br              %r1\n"
+"       .size           my_tramp2, .-my_tramp2\n"
+"       .popsection\n"
+);
+
+#endif /* CONFIG_S390 */
+
+static unsigned long my_tramp = (unsigned long)my_tramp1;
+static unsigned long tramps[2] = {
+       (unsigned long)my_tramp1,
+       (unsigned long)my_tramp2,
+};
+
+static struct ftrace_ops direct;
+
+static int simple_thread(void *arg)
+{
+       static int t;
+       int ret = 0;
+
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(2 * HZ);
+
+               if (ret)
+                       continue;
+               t ^= 1;
+               ret = modify_ftrace_direct_multi(&direct, tramps[t]);
+               if (!ret)
+                       my_tramp = tramps[t];
+               WARN_ON_ONCE(ret);
+       }
+
+       return 0;
+}
+
+static struct task_struct *simple_tsk;
+
+static int __init ftrace_direct_multi_init(void)
+{
+       int ret;
+
+       ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
+       ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);
+
+       ret = register_ftrace_direct_multi(&direct, my_tramp);
+
+       if (!ret)
+               simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");
+       return ret;
+}
+
+static void __exit ftrace_direct_multi_exit(void)
+{
+       kthread_stop(simple_tsk);
+       unregister_ftrace_direct_multi(&direct, my_tramp);
+}
+
+module_init(ftrace_direct_multi_init);
+module_exit(ftrace_direct_multi_exit);
+
+MODULE_AUTHOR("Jiri Olsa");
+MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct_multi()");
+MODULE_LICENSE("GPL");
index 7d631aa..52a000b 100755 (executable)
@@ -219,7 +219,7 @@ if ($arch eq "x86_64") {
 
 } elsif ($arch eq "s390" && $bits == 64) {
     if ($cc =~ /-DCC_USING_HOTPATCH/) {
-       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(bcrl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
        $mcount_adjust = 0;
     }
     $alignment = 8;
index 62d30c0..1afc06f 100644 (file)
@@ -611,10 +611,11 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
        return 0;
 }
 
-static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
+static int parse_sid(struct super_block *sb, const char *s, u32 *sid,
+                    gfp_t gfp)
 {
        int rc = security_context_str_to_sid(&selinux_state, s,
-                                            sid, GFP_KERNEL);
+                                            sid, gfp);
        if (rc)
                pr_warn("SELinux: security_context_str_to_sid"
                       "(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -685,7 +686,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         */
        if (opts) {
                if (opts->fscontext) {
-                       rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
+                       rc = parse_sid(sb, opts->fscontext, &fscontext_sid,
+                                       GFP_KERNEL);
                        if (rc)
                                goto out;
                        if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
@@ -694,7 +696,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        sbsec->flags |= FSCONTEXT_MNT;
                }
                if (opts->context) {
-                       rc = parse_sid(sb, opts->context, &context_sid);
+                       rc = parse_sid(sb, opts->context, &context_sid,
+                                       GFP_KERNEL);
                        if (rc)
                                goto out;
                        if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
@@ -703,7 +706,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        sbsec->flags |= CONTEXT_MNT;
                }
                if (opts->rootcontext) {
-                       rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
+                       rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid,
+                                       GFP_KERNEL);
                        if (rc)
                                goto out;
                        if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
@@ -712,7 +716,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        sbsec->flags |= ROOTCONTEXT_MNT;
                }
                if (opts->defcontext) {
-                       rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
+                       rc = parse_sid(sb, opts->defcontext, &defcontext_sid,
+                                       GFP_KERNEL);
                        if (rc)
                                goto out;
                        if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
@@ -2702,14 +2707,14 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
                return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
 
        if (opts->fscontext) {
-               rc = parse_sid(sb, opts->fscontext, &sid);
+               rc = parse_sid(sb, opts->fscontext, &sid, GFP_NOWAIT);
                if (rc)
                        return 1;
                if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
                        return 1;
        }
        if (opts->context) {
-               rc = parse_sid(sb, opts->context, &sid);
+               rc = parse_sid(sb, opts->context, &sid, GFP_NOWAIT);
                if (rc)
                        return 1;
                if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
@@ -2719,14 +2724,14 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
                struct inode_security_struct *root_isec;
 
                root_isec = backing_inode_security(sb->s_root);
-               rc = parse_sid(sb, opts->rootcontext, &sid);
+               rc = parse_sid(sb, opts->rootcontext, &sid, GFP_NOWAIT);
                if (rc)
                        return 1;
                if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
                        return 1;
        }
        if (opts->defcontext) {
-               rc = parse_sid(sb, opts->defcontext, &sid);
+               rc = parse_sid(sb, opts->defcontext, &sid, GFP_NOWAIT);
                if (rc)
                        return 1;
                if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
@@ -2749,14 +2754,14 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
                return 0;
 
        if (opts->fscontext) {
-               rc = parse_sid(sb, opts->fscontext, &sid);
+               rc = parse_sid(sb, opts->fscontext, &sid, GFP_KERNEL);
                if (rc)
                        return rc;
                if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
                        goto out_bad_option;
        }
        if (opts->context) {
-               rc = parse_sid(sb, opts->context, &sid);
+               rc = parse_sid(sb, opts->context, &sid, GFP_KERNEL);
                if (rc)
                        return rc;
                if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
@@ -2765,14 +2770,14 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
        if (opts->rootcontext) {
                struct inode_security_struct *root_isec;
                root_isec = backing_inode_security(sb->s_root);
-               rc = parse_sid(sb, opts->rootcontext, &sid);
+               rc = parse_sid(sb, opts->rootcontext, &sid, GFP_KERNEL);
                if (rc)
                        return rc;
                if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
                        goto out_bad_option;
        }
        if (opts->defcontext) {
-               rc = parse_sid(sb, opts->defcontext, &sid);
+               rc = parse_sid(sb, opts->defcontext, &sid, GFP_KERNEL);
                if (rc)
                        return rc;
                if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
index 470dabc..edff063 100644 (file)
@@ -264,6 +264,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
                                  struct snd_ctl_elem_value *data,
                                  int type, int count)
 {
+       struct snd_ctl_elem_value32 __user *data32 = userdata;
        int i, size;
 
        if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
@@ -280,6 +281,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
                if (copy_to_user(valuep, data->value.bytes.data, size))
                        return -EFAULT;
        }
+       if (copy_to_user(&data32->id, &data->id, sizeof(data32->id)))
+               return -EFAULT;
        return 0;
 }
 
index 82a8187..20a0a47 100644 (file)
@@ -147,7 +147,7 @@ snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
  *
  * Return the maximum value for field PAR.
  */
-static unsigned int
+static int
 snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
                           snd_pcm_hw_param_t var, int *dir)
 {
@@ -682,18 +682,24 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *oss_params,
                                   struct snd_pcm_hw_params *slave_params)
 {
-       size_t s;
-       size_t oss_buffer_size, oss_period_size, oss_periods;
-       size_t min_period_size, max_period_size;
+       ssize_t s;
+       ssize_t oss_buffer_size;
+       ssize_t oss_period_size, oss_periods;
+       ssize_t min_period_size, max_period_size;
        struct snd_pcm_runtime *runtime = substream->runtime;
        size_t oss_frame_size;
 
        oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
                         params_channels(oss_params) / 8;
 
+       oss_buffer_size = snd_pcm_hw_param_value_max(slave_params,
+                                                    SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                                    NULL);
+       if (oss_buffer_size <= 0)
+               return -EINVAL;
        oss_buffer_size = snd_pcm_plug_client_size(substream,
-                                                  snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
-       if (!oss_buffer_size)
+                                                  oss_buffer_size * oss_frame_size);
+       if (oss_buffer_size <= 0)
                return -EINVAL;
        oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
        if (atomic_read(&substream->mmap_count)) {
@@ -730,7 +736,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 
        min_period_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
-       if (min_period_size) {
+       if (min_period_size > 0) {
                min_period_size *= oss_frame_size;
                min_period_size = roundup_pow_of_two(min_period_size);
                if (oss_period_size < min_period_size)
@@ -739,7 +745,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 
        max_period_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
-       if (max_period_size) {
+       if (max_period_size > 0) {
                max_period_size *= oss_frame_size;
                max_period_size = rounddown_pow_of_two(max_period_size);
                if (oss_period_size > max_period_size)
@@ -752,7 +758,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
                oss_periods = substream->oss.setup.periods;
 
        s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
-       if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
+       if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
                s = runtime->oss.maxfrags;
        if (oss_periods > s)
                oss_periods = s;
@@ -878,8 +884,15 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
                err = -EINVAL;
                goto failure;
        }
-       choose_rate(substream, sparams, runtime->oss.rate);
-       snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);
+
+       err = choose_rate(substream, sparams, runtime->oss.rate);
+       if (err < 0)
+               goto failure;
+       err = snd_pcm_hw_param_near(substream, sparams,
+                                   SNDRV_PCM_HW_PARAM_CHANNELS,
+                                   runtime->oss.channels, NULL);
+       if (err < 0)
+               goto failure;
 
        format = snd_pcm_oss_format_from(runtime->oss.format);
 
@@ -1956,7 +1969,7 @@ static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsign
        if (runtime->oss.subdivision || runtime->oss.fragshift)
                return -EINVAL;
        fragshift = val & 0xffff;
-       if (fragshift >= 31)
+       if (fragshift >= 25) /* should be large enough */
                return -EINVAL;
        runtime->oss.fragshift = fragshift;
        runtime->oss.maxfrags = (val >> 16) & 0xffff;
index 9ce7457..3599f4c 100644 (file)
@@ -6503,22 +6503,26 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
 /* for alc285_fixup_ideapad_s740_coef() */
 #include "ideapad_s740_helper.c"
 
-static void alc256_fixup_tongfang_reset_persistent_settings(struct hda_codec *codec,
-                                                           const struct hda_fixup *fix,
-                                                           int action)
+static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
+       WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
+       WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
+       WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
+       {}
+};
+
+static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
+                                          const struct hda_fixup *fix,
+                                          int action)
 {
        /*
-       * A certain other OS sets these coeffs to different values. On at least one TongFang
-       * barebone these settings might survive even a cold reboot. So to restore a clean slate the
-       * values are explicitly reset to default here. Without this, the external microphone is
-       * always in a plugged-in state, while the internal microphone is always in an unplugged
-       * state, breaking the ability to use the internal microphone.
-       */
-       alc_write_coef_idx(codec, 0x24, 0x0000);
-       alc_write_coef_idx(codec, 0x26, 0x0000);
-       alc_write_coef_idx(codec, 0x29, 0x3000);
-       alc_write_coef_idx(codec, 0x37, 0xfe05);
-       alc_write_coef_idx(codec, 0x45, 0x5089);
+        * A certain other OS sets these coeffs to different values. On at least
+        * one TongFang barebone these settings might survive even a cold
+        * reboot. So to restore a clean slate the values are explicitly reset
+        * to default here. Without this, the external microphone is always in a
+        * plugged-in state, while the internal microphone is always in an
+        * unplugged state, breaking the ability to use the internal microphone.
+        */
+       alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
 }
 
 static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
@@ -6759,7 +6763,7 @@ enum {
        ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
        ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
        ALC287_FIXUP_13S_GEN2_SPEAKERS,
-       ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS,
+       ALC256_FIXUP_SET_COEF_DEFAULTS,
        ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
        ALC233_FIXUP_NO_AUDIO_JACK,
 };
@@ -8465,9 +8469,9 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE,
        },
-       [ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS] = {
+       [ALC256_FIXUP_SET_COEF_DEFAULTS] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_fixup_tongfang_reset_persistent_settings,
+               .v.func = alc256_fixup_set_coef_defaults,
        },
        [ALC245_FIXUP_HP_GPIO_LED] = {
                .type = HDA_FIXUP_FUNC,
@@ -8929,7 +8933,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
        SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
        SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
-       SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS),
+       SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
        SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
@@ -10231,6 +10235,27 @@ static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
        }
 }
 
+static void alc897_hp_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+
+       snd_hda_gen_hp_automute(codec, jack);
+       vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
+       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+}
+
+static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+       }
+}
+
 static const struct coef_fw alc668_coefs[] = {
        WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
        WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
@@ -10311,6 +10336,8 @@ enum {
        ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
        ALC668_FIXUP_HEADSET_MIC,
        ALC668_FIXUP_MIC_DET_COEF,
+       ALC897_FIXUP_LENOVO_HEADSET_MIC,
+       ALC897_FIXUP_HEADSET_MIC_PIN,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -10717,6 +10744,19 @@ static const struct hda_fixup alc662_fixups[] = {
                        {}
                },
        },
+       [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc897_fixup_lenovo_headset_mic,
+       },
+       [ALC897_FIXUP_HEADSET_MIC_PIN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x03a11050 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -10761,6 +10801,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
        SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
+       SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
index 957eeb6..7e9a9a9 100644 (file)
@@ -146,10 +146,11 @@ static int snd_acp6x_probe(struct pci_dev *pci,
 {
        struct acp6x_dev_data *adata;
        struct platform_device_info pdevinfo[ACP6x_DEVS];
-       int ret, index;
+       int index = 0;
        int val = 0x00;
        u32 addr;
        unsigned int irqflags;
+       int ret;
 
        irqflags = IRQF_SHARED;
        /* Yellow Carp device check */
index 04cb747..5224123 100644 (file)
@@ -2858,6 +2858,8 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
 
        for (i = 0; i < RT5682_DAI_NUM_CLKS; ++i) {
                struct clk_init_data init = { };
+               struct clk_parent_data parent_data;
+               const struct clk_hw *parent;
 
                dai_clk_hw = &rt5682->dai_clks_hw[i];
 
@@ -2865,17 +2867,17 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
                case RT5682_DAI_WCLK_IDX:
                        /* Make MCLK the parent of WCLK */
                        if (rt5682->mclk) {
-                               init.parent_data = &(struct clk_parent_data){
+                               parent_data = (struct clk_parent_data){
                                        .fw_name = "mclk",
                                };
+                               init.parent_data = &parent_data;
                                init.num_parents = 1;
                        }
                        break;
                case RT5682_DAI_BCLK_IDX:
                        /* Make WCLK the parent of BCLK */
-                       init.parent_hws = &(const struct clk_hw *){
-                               &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX]
-                       };
+                       parent = &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX];
+                       init.parent_hws = &parent;
                        init.num_parents = 1;
                        break;
                default:
index 470957f..d49a4f6 100644 (file)
@@ -2693,6 +2693,8 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component)
 
        for (i = 0; i < RT5682S_DAI_NUM_CLKS; ++i) {
                struct clk_init_data init = { };
+               struct clk_parent_data parent_data;
+               const struct clk_hw *parent;
 
                dai_clk_hw = &rt5682s->dai_clks_hw[i];
 
@@ -2700,17 +2702,17 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component)
                case RT5682S_DAI_WCLK_IDX:
                        /* Make MCLK the parent of WCLK */
                        if (rt5682s->mclk) {
-                               init.parent_data = &(struct clk_parent_data){
+                               parent_data = (struct clk_parent_data){
                                        .fw_name = "mclk",
                                };
+                               init.parent_data = &parent_data;
                                init.num_parents = 1;
                        }
                        break;
                case RT5682S_DAI_BCLK_IDX:
                        /* Make WCLK the parent of BCLK */
-                       init.parent_hws = &(const struct clk_hw *){
-                               &rt5682s->dai_clks_hw[RT5682S_DAI_WCLK_IDX]
-                       };
+                       parent = &rt5682s->dai_clks_hw[RT5682S_DAI_WCLK_IDX];
+                       init.parent_hws = &parent;
                        init.num_parents = 1;
                        break;
                default:
index 4f568ab..e63c6b7 100644 (file)
@@ -3256,6 +3256,9 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
        int value = ucontrol->value.integer.value[0];
        int sel;
 
+       if (wcd->comp_enabled[comp] == value)
+               return 0;
+
        wcd->comp_enabled[comp] = value;
        sel = value ? WCD934X_HPH_GAIN_SRC_SEL_COMPANDER :
                WCD934X_HPH_GAIN_SRC_SEL_REGISTER;
@@ -3279,10 +3282,10 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
        case COMPANDER_8:
                break;
        default:
-               break;
+               return 0;
        }
 
-       return 0;
+       return 1;
 }
 
 static int wcd934x_rx_hph_mode_get(struct snd_kcontrol *kc,
@@ -3326,6 +3329,31 @@ static int slim_rx_mux_get(struct snd_kcontrol *kc,
        return 0;
 }
 
+static int slim_rx_mux_to_dai_id(int mux)
+{
+       int aif_id;
+
+       switch (mux) {
+       case 1:
+               aif_id = AIF1_PB;
+               break;
+       case 2:
+               aif_id = AIF2_PB;
+               break;
+       case 3:
+               aif_id = AIF3_PB;
+               break;
+       case 4:
+               aif_id = AIF4_PB;
+               break;
+       default:
+               aif_id = -1;
+               break;
+       }
+
+       return aif_id;
+}
+
 static int slim_rx_mux_put(struct snd_kcontrol *kc,
                           struct snd_ctl_elem_value *ucontrol)
 {
@@ -3333,43 +3361,59 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
        struct wcd934x_codec *wcd = dev_get_drvdata(w->dapm->dev);
        struct soc_enum *e = (struct soc_enum *)kc->private_value;
        struct snd_soc_dapm_update *update = NULL;
+       struct wcd934x_slim_ch *ch, *c;
        u32 port_id = w->shift;
+       bool found = false;
+       int mux_idx;
+       int prev_mux_idx = wcd->rx_port_value[port_id];
+       int aif_id;
 
-       if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
-               return 0;
+       mux_idx = ucontrol->value.enumerated.item[0];
 
-       wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
+       if (mux_idx == prev_mux_idx)
+               return 0;
 
-       switch (wcd->rx_port_value[port_id]) {
+       switch(mux_idx) {
        case 0:
-               list_del_init(&wcd->rx_chs[port_id].list);
-               break;
-       case 1:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF1_PB].slim_ch_list);
-               break;
-       case 2:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF2_PB].slim_ch_list);
-               break;
-       case 3:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF3_PB].slim_ch_list);
+               aif_id = slim_rx_mux_to_dai_id(prev_mux_idx);
+               if (aif_id < 0)
+                       return 0;
+
+               list_for_each_entry_safe(ch, c, &wcd->dai[aif_id].slim_ch_list, list) {
+                       if (ch->port == port_id + WCD934X_RX_START) {
+                               found = true;
+                               list_del_init(&ch->list);
+                               break;
+                       }
+               }
+               if (!found)
+                       return 0;
+
                break;
-       case 4:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF4_PB].slim_ch_list);
+       case 1 ... 4:
+               aif_id = slim_rx_mux_to_dai_id(mux_idx);
+               if (aif_id < 0)
+                       return 0;
+
+               if (list_empty(&wcd->rx_chs[port_id].list)) {
+                       list_add_tail(&wcd->rx_chs[port_id].list,
+                                     &wcd->dai[aif_id].slim_ch_list);
+               } else {
+                       dev_err(wcd->dev ,"SLIM_RX%d PORT is busy\n", port_id);
+                       return 0;
+               }
                break;
+
        default:
-               dev_err(wcd->dev, "Unknown AIF %d\n",
-                       wcd->rx_port_value[port_id]);
+               dev_err(wcd->dev, "Unknown AIF %d\n", mux_idx);
                goto err;
        }
 
+       wcd->rx_port_value[port_id] = mux_idx;
        snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id],
                                      e, update);
 
-       return 0;
+       return 1;
 err:
        return -EINVAL;
 }
@@ -3815,6 +3859,7 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        struct soc_mixer_control *mixer =
                        (struct soc_mixer_control *)kc->private_value;
        int enable = ucontrol->value.integer.value[0];
+       struct wcd934x_slim_ch *ch, *c;
        int dai_id = widget->shift;
        int port_id = mixer->shift;
 
@@ -3822,17 +3867,32 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        if (enable == wcd->tx_port_value[port_id])
                return 0;
 
-       wcd->tx_port_value[port_id] = enable;
-
-       if (enable)
-               list_add_tail(&wcd->tx_chs[port_id].list,
-                             &wcd->dai[dai_id].slim_ch_list);
-       else
-               list_del_init(&wcd->tx_chs[port_id].list);
+       if (enable) {
+               if (list_empty(&wcd->tx_chs[port_id].list)) {
+                       list_add_tail(&wcd->tx_chs[port_id].list,
+                                     &wcd->dai[dai_id].slim_ch_list);
+               } else {
+                       dev_err(wcd->dev ,"SLIM_TX%d PORT is busy\n", port_id);
+                       return 0;
+               }
+        } else {
+               bool found = false;
+
+               list_for_each_entry_safe(ch, c, &wcd->dai[dai_id].slim_ch_list, list) {
+                       if (ch->port == port_id) {
+                               found = true;
+                               list_del_init(&wcd->tx_chs[port_id].list);
+                               break;
+                       }
+               }
+               if (!found)
+                       return 0;
+        }
 
+       wcd->tx_port_value[port_id] = enable;
        snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update);
 
-       return 0;
+       return 1;
 }
 
 static const struct snd_kcontrol_new aif1_slim_cap_mixer[] = {
index 2da4a5f..564b78f 100644 (file)
@@ -772,7 +772,8 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
 
                usleep_range(1000, 1010);
        }
-       return 0;
+
+       return 1;
 }
 
 static int wsa881x_get_port(struct snd_kcontrol *kcontrol,
@@ -816,15 +817,22 @@ static int wsa881x_set_port(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        int portidx = mixer->reg;
 
-       if (ucontrol->value.integer.value[0])
+       if (ucontrol->value.integer.value[0]) {
+               if (data->port_enable[portidx])
+                       return 0;
+
                data->port_enable[portidx] = true;
-       else
+       } else {
+               if (!data->port_enable[portidx])
+                       return 0;
+
                data->port_enable[portidx] = false;
+       }
 
        if (portidx == WSA881X_PORT_BOOST) /* Boost Switch */
                wsa881x_boost_ctrl(comp, data->port_enable[portidx]);
 
-       return 0;
+       return 1;
 }
 
 static const char * const smart_boost_lvl_text[] = {
index cd74681..928fd23 100644 (file)
@@ -498,14 +498,16 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
        struct session_data *session = &data->sessions[session_id];
 
        if (ucontrol->value.integer.value[0]) {
+               if (session->port_id == be_id)
+                       return 0;
+
                session->port_id = be_id;
                snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update);
        } else {
-               if (session->port_id == be_id) {
-                       session->port_id = -1;
+               if (session->port_id == -1 || session->port_id != be_id)
                        return 0;
-               }
 
+               session->port_id = -1;
                snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update);
        }
 
index 17b9b28..5f9cb5c 100644 (file)
@@ -95,6 +95,7 @@ struct rk_i2s_tdm_dev {
        spinlock_t lock; /* xfer lock */
        bool has_playback;
        bool has_capture;
+       struct snd_soc_dai_driver *dai;
 };
 
 static int to_ch_num(unsigned int val)
@@ -1310,19 +1311,14 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = {
        {},
 };
 
-static struct snd_soc_dai_driver i2s_tdm_dai = {
+static const struct snd_soc_dai_driver i2s_tdm_dai = {
        .probe = rockchip_i2s_tdm_dai_probe,
-       .playback = {
-               .stream_name  = "Playback",
-       },
-       .capture = {
-               .stream_name  = "Capture",
-       },
        .ops = &rockchip_i2s_tdm_dai_ops,
 };
 
-static void rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)
+static int rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)
 {
+       struct snd_soc_dai_driver *dai;
        struct property *dma_names;
        const char *dma_name;
        u64 formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
@@ -1337,19 +1333,33 @@ static void rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)
                        i2s_tdm->has_capture = true;
        }
 
+       dai = devm_kmemdup(i2s_tdm->dev, &i2s_tdm_dai,
+                          sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
        if (i2s_tdm->has_playback) {
-               i2s_tdm_dai.playback.channels_min = 2;
-               i2s_tdm_dai.playback.channels_max = 8;
-               i2s_tdm_dai.playback.rates = SNDRV_PCM_RATE_8000_192000;
-               i2s_tdm_dai.playback.formats = formats;
+               dai->playback.stream_name  = "Playback";
+               dai->playback.channels_min = 2;
+               dai->playback.channels_max = 8;
+               dai->playback.rates = SNDRV_PCM_RATE_8000_192000;
+               dai->playback.formats = formats;
        }
 
        if (i2s_tdm->has_capture) {
-               i2s_tdm_dai.capture.channels_min = 2;
-               i2s_tdm_dai.capture.channels_max = 8;
-               i2s_tdm_dai.capture.rates = SNDRV_PCM_RATE_8000_192000;
-               i2s_tdm_dai.capture.formats = formats;
+               dai->capture.stream_name  = "Capture";
+               dai->capture.channels_min = 2;
+               dai->capture.channels_max = 8;
+               dai->capture.rates = SNDRV_PCM_RATE_8000_192000;
+               dai->capture.formats = formats;
        }
+
+       if (i2s_tdm->clk_trcm != TRCM_TXRX)
+               dai->symmetric_rate = 1;
+
+       i2s_tdm->dai = dai;
+
+       return 0;
 }
 
 static int rockchip_i2s_tdm_path_check(struct rk_i2s_tdm_dev *i2s_tdm,
@@ -1541,8 +1551,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
        spin_lock_init(&i2s_tdm->lock);
        i2s_tdm->soc_data = (struct rk_i2s_soc_data *)of_id->data;
 
-       rockchip_i2s_tdm_init_dai(i2s_tdm);
-
        i2s_tdm->frame_width = 64;
 
        i2s_tdm->clk_trcm = TRCM_TXRX;
@@ -1555,8 +1563,10 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
                }
                i2s_tdm->clk_trcm = TRCM_RX;
        }
-       if (i2s_tdm->clk_trcm != TRCM_TXRX)
-               i2s_tdm_dai.symmetric_rate = 1;
+
+       ret = rockchip_i2s_tdm_init_dai(i2s_tdm);
+       if (ret)
+               return ret;
 
        i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
        if (IS_ERR(i2s_tdm->grf))
@@ -1678,7 +1688,7 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
 
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &rockchip_i2s_tdm_component,
-                                             &i2s_tdm_dai, 1);
+                                             i2s_tdm->dai, 1);
 
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI\n");
index 6744318..13cd96e 100644 (file)
@@ -22,6 +22,7 @@
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 #define IDISP_VID_INTEL        0x80860000
+#define CODEC_PROBE_RETRIES 3
 
 /* load the legacy HDA codec driver */
 static int request_codec_module(struct hda_codec *codec)
@@ -121,12 +122,15 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
        u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
                (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
        u32 resp = -1;
-       int ret;
+       int ret, retry = 0;
+
+       do {
+               mutex_lock(&hbus->core.cmd_mutex);
+               snd_hdac_bus_send_cmd(&hbus->core, hda_cmd);
+               snd_hdac_bus_get_response(&hbus->core, address, &resp);
+               mutex_unlock(&hbus->core.cmd_mutex);
+       } while (resp == -1 && retry++ < CODEC_PROBE_RETRIES);
 
-       mutex_lock(&hbus->core.cmd_mutex);
-       snd_hdac_bus_send_cmd(&hbus->core, hda_cmd);
-       snd_hdac_bus_get_response(&hbus->core, address, &resp);
-       mutex_unlock(&hbus->core.cmd_mutex);
        if (resp == -1)
                return -EIO;
        dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
index 933c450..3785cad 100644 (file)
@@ -514,8 +514,8 @@ static int tegra210_adx_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_adx_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
                           tegra210_adx_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_adx_driver = {
index 6895763..d064cc6 100644 (file)
@@ -583,8 +583,8 @@ static int tegra210_amx_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_amx_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
                           tegra210_amx_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_amx_driver = {
index 51d3755..16e679a 100644 (file)
@@ -666,8 +666,8 @@ static int tegra210_mixer_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_mixer_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
                           tegra210_mixer_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_mixer_driver = {
index 85b1558..acf5932 100644 (file)
@@ -164,7 +164,7 @@ static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol,
        if (err < 0)
                goto end;
 
-       return 1;
+       err = 1;
 
 end:
        pm_runtime_put(cmpnt->dev);
@@ -236,7 +236,7 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
                           TEGRA210_MVC_VOLUME_SWITCH_MASK,
                           TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
 
-       return 1;
+       err = 1;
 
 end:
        pm_runtime_put(cmpnt->dev);
@@ -639,8 +639,8 @@ static int tegra210_mvc_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_mvc_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend,
                           tegra210_mvc_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_mvc_driver = {
index 7a2227e..368f077 100644 (file)
@@ -3594,8 +3594,8 @@ static int tegra210_sfc_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_sfc_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend,
                           tegra210_sfc_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_sfc_driver = {
index d489c1d..823b6b8 100644 (file)
@@ -3016,11 +3016,11 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = {
 
 
 static const struct snd_djm_device snd_djm_devices[] = {
-       SND_DJM_DEVICE(250mk2),
-       SND_DJM_DEVICE(750),
-       SND_DJM_DEVICE(750mk2),
-       SND_DJM_DEVICE(850),
-       SND_DJM_DEVICE(900nxs2)
+       [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2),
+       [SND_DJM_750_IDX] = SND_DJM_DEVICE(750),
+       [SND_DJM_850_IDX] = SND_DJM_DEVICE(850),
+       [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2),
+       [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2),
 };
 
 
index a59cb0e..73409e2 100644 (file)
@@ -83,6 +83,7 @@ struct btf_id {
                int      cnt;
        };
        int              addr_cnt;
+       bool             is_set;
        Elf64_Addr       addr[ADDR_CNT];
 };
 
@@ -451,8 +452,10 @@ static int symbols_collect(struct object *obj)
                         * in symbol's size, together with 'cnt' field hence
                         * that - 1.
                         */
-                       if (id)
+                       if (id) {
                                id->cnt = sym.st_size / sizeof(int) - 1;
+                               id->is_set = true;
+                       }
                } else {
                        pr_err("FAILED unsupported prefix %s\n", prefix);
                        return -1;
@@ -568,9 +571,8 @@ static int id_patch(struct object *obj, struct btf_id *id)
        int *ptr = data->d_buf;
        int i;
 
-       if (!id->id) {
+       if (!id->id && !id->is_set)
                pr_err("WARN: resolve_btfids: unresolved symbol %s\n", id->name);
-       }
 
        for (i = 0; i < id->addr_cnt; i++) {
                unsigned long addr = id->addr[i];
index 45a9a59..ae61f46 100644 (file)
@@ -48,7 +48,6 @@ FEATURE_TESTS_BASIC :=                  \
         numa_num_possible_cpus          \
         libperl                         \
         libpython                       \
-        libpython-version               \
         libslang                        \
         libslang-include-subdir         \
         libtraceevent                   \
index 0a3244a..1480910 100644 (file)
@@ -32,7 +32,6 @@ FILES=                                          \
          test-numa_num_possible_cpus.bin        \
          test-libperl.bin                       \
          test-libpython.bin                     \
-         test-libpython-version.bin             \
          test-libslang.bin                      \
          test-libslang-include-subdir.bin       \
          test-libtraceevent.bin                 \
@@ -227,9 +226,6 @@ $(OUTPUT)test-libperl.bin:
 $(OUTPUT)test-libpython.bin:
        $(BUILD) $(FLAGS_PYTHON_EMBED)
 
-$(OUTPUT)test-libpython-version.bin:
-       $(BUILD)
-
 $(OUTPUT)test-libbfd.bin:
        $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
 
index 0b243ce..5ffafb9 100644 (file)
 # include "test-libpython.c"
 #undef main
 
-#define main main_test_libpython_version
-# include "test-libpython-version.c"
-#undef main
-
 #define main main_test_libperl
 # include "test-libperl.c"
 #undef main
 int main(int argc, char *argv[])
 {
        main_test_libpython();
-       main_test_libpython_version();
        main_test_libperl();
        main_test_hello();
        main_test_libelf();
diff --git a/tools/build/feature/test-libpython-version.c b/tools/build/feature/test-libpython-version.c
deleted file mode 100644 (file)
index 47714b9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <Python.h>
-
-#if PY_VERSION_HEX >= 0x03000000
-       #error
-#endif
-
-int main(void)
-{
-       return 0;
-}
diff --git a/tools/include/linux/debug_locks.h b/tools/include/linux/debug_locks.h
deleted file mode 100644 (file)
index 72d595c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LIBLOCKDEP_DEBUG_LOCKS_H_
-#define _LIBLOCKDEP_DEBUG_LOCKS_H_
-
-#include <stddef.h>
-#include <linux/compiler.h>
-#include <asm/bug.h>
-
-#define DEBUG_LOCKS_WARN_ON(x) WARN_ON(x)
-
-extern bool debug_locks;
-extern bool debug_locks_silent;
-
-#endif
diff --git a/tools/include/linux/hardirq.h b/tools/include/linux/hardirq.h
deleted file mode 100644 (file)
index b25580b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LIBLOCKDEP_LINUX_HARDIRQ_H_
-#define _LIBLOCKDEP_LINUX_HARDIRQ_H_
-
-#define SOFTIRQ_BITS   0UL
-#define HARDIRQ_BITS   0UL
-#define SOFTIRQ_SHIFT  0UL
-#define HARDIRQ_SHIFT  0UL
-#define hardirq_count()        0UL
-#define softirq_count()        0UL
-
-#endif
diff --git a/tools/include/linux/irqflags.h b/tools/include/linux/irqflags.h
deleted file mode 100644 (file)
index 501262a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
-#define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
-
-# define lockdep_hardirq_context()     0
-# define lockdep_softirq_context(p)    0
-# define lockdep_hardirqs_enabled()    0
-# define lockdep_softirqs_enabled(p)   0
-# define lockdep_hardirq_enter()       do { } while (0)
-# define lockdep_hardirq_exit()                do { } while (0)
-# define lockdep_softirq_enter()       do { } while (0)
-# define lockdep_softirq_exit()                do { } while (0)
-# define INIT_TRACE_IRQFLAGS
-
-# define stop_critical_timings() do { } while (0)
-# define start_critical_timings() do { } while (0)
-
-#define raw_local_irq_disable() do { } while (0)
-#define raw_local_irq_enable() do { } while (0)
-#define raw_local_irq_save(flags) ((flags) = 0)
-#define raw_local_irq_restore(flags) ((void)(flags))
-#define raw_local_save_flags(flags) ((flags) = 0)
-#define raw_irqs_disabled_flags(flags) ((void)(flags))
-#define raw_irqs_disabled() 0
-#define raw_safe_halt()
-
-#define local_irq_enable() do { } while (0)
-#define local_irq_disable() do { } while (0)
-#define local_irq_save(flags) ((flags) = 0)
-#define local_irq_restore(flags) ((void)(flags))
-#define local_save_flags(flags)        ((flags) = 0)
-#define irqs_disabled() (1)
-#define irqs_disabled_flags(flags) ((void)(flags), 0)
-#define safe_halt() do { } while (0)
-
-#define trace_lock_release(x, y)
-#define trace_lock_acquire(a, b, c, d, e, f, g)
-
-#endif
diff --git a/tools/include/linux/lockdep.h b/tools/include/linux/lockdep.h
deleted file mode 100644 (file)
index e569972..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LIBLOCKDEP_LOCKDEP_H_
-#define _LIBLOCKDEP_LOCKDEP_H_
-
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <string.h>
-#include <limits.h>
-#include <linux/utsname.h>
-#include <linux/compiler.h>
-#include <linux/export.h>
-#include <linux/kern_levels.h>
-#include <linux/err.h>
-#include <linux/rcu.h>
-#include <linux/list.h>
-#include <linux/hardirq.h>
-#include <unistd.h>
-
-#define MAX_LOCK_DEPTH 63UL
-
-#define asmlinkage
-#define __visible
-
-#include "../../../include/linux/lockdep.h"
-
-struct task_struct {
-       u64 curr_chain_key;
-       int lockdep_depth;
-       unsigned int lockdep_recursion;
-       struct held_lock held_locks[MAX_LOCK_DEPTH];
-       gfp_t lockdep_reclaim_gfp;
-       int pid;
-       int state;
-       char comm[17];
-};
-
-#define TASK_RUNNING 0
-
-extern struct task_struct *__curr(void);
-
-#define current (__curr())
-
-static inline int debug_locks_off(void)
-{
-       return 1;
-}
-
-#define task_pid_nr(tsk) ((tsk)->pid)
-
-#define KSYM_NAME_LEN 128
-#define printk(...) dprintf(STDOUT_FILENO, __VA_ARGS__)
-#define pr_err(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
-#define pr_warn pr_err
-#define pr_cont pr_err
-
-#define list_del_rcu list_del
-
-#define atomic_t unsigned long
-#define atomic_inc(x) ((*(x))++)
-
-#define print_tainted() ""
-#define static_obj(x) 1
-
-#define debug_show_all_locks()
-extern void debug_check_no_locks_held(void);
-
-static __used bool __is_kernel_percpu_address(unsigned long addr, void *can_addr)
-{
-       return false;
-}
-
-#endif
diff --git a/tools/include/linux/proc_fs.h b/tools/include/linux/proc_fs.h
deleted file mode 100644 (file)
index 8b3b03b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef _TOOLS_INCLUDE_LINUX_PROC_FS_H
-#define _TOOLS_INCLUDE_LINUX_PROC_FS_H
-
-#endif /* _TOOLS_INCLUDE_LINUX_PROC_FS_H */
index c934572..622266b 100644 (file)
@@ -37,6 +37,4 @@ static inline bool arch_spin_is_locked(arch_spinlock_t *mutex)
        return true;
 }
 
-#include <linux/lockdep.h>
-
 #endif
diff --git a/tools/include/linux/stacktrace.h b/tools/include/linux/stacktrace.h
deleted file mode 100644 (file)
index ae343ac..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LIBLOCKDEP_LINUX_STACKTRACE_H_
-#define _LIBLOCKDEP_LINUX_STACKTRACE_H_
-
-#include <execinfo.h>
-
-struct stack_trace {
-       unsigned int nr_entries, max_entries;
-       unsigned long *entries;
-       int skip;
-};
-
-static inline void print_stack_trace(struct stack_trace *trace, int spaces)
-{
-       backtrace_symbols_fd((void **)trace->entries, trace->nr_entries, 1);
-}
-
-#define save_stack_trace(trace)        \
-       ((trace)->nr_entries =  \
-               backtrace((void **)(trace)->entries, (trace)->max_entries))
-
-static inline int dump_stack(void)
-{
-       void *array[64];
-       size_t size;
-
-       size = backtrace(array, 64);
-       backtrace_symbols_fd(array, size, 1);
-
-       return 0;
-}
-
-#endif
index afd1447..3df74cf 100644 (file)
@@ -271,8 +271,6 @@ endif
 
 FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
 FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
-FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
-FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
 
 FEATURE_CHECK_LDFLAGS-libaio = -lrt
 
index 7bef917..15109af 100644 (file)
 446    common  landlock_restrict_self          sys_landlock_restrict_self
 # 447 reserved for memfd_secret
 448    common  process_mrelease                sys_process_mrelease
+449    common  futex_waitv                     sys_futex_waitv
index df5261e..ed9c5c2 100644 (file)
 446  common    landlock_restrict_self  sys_landlock_restrict_self      sys_landlock_restrict_self
 # 447 reserved for memfd_secret
 448  common    process_mrelease        sys_process_mrelease            sys_process_mrelease
+449  common    futex_waitv             sys_futex_waitv                 sys_futex_waitv
index fa0ff4c..488f6e6 100644 (file)
@@ -223,8 +223,6 @@ static unsigned int group(pthread_t *pth,
                snd_ctx->out_fds[i] = fds[1];
                if (!thread_mode)
                        close(fds[0]);
-
-               free(ctx);
        }
 
        /* Now we have all the fds, fork the senders */
@@ -241,8 +239,6 @@ static unsigned int group(pthread_t *pth,
                for (i = 0; i < num_fds; i++)
                        close(snd_ctx->out_fds[i]);
 
-       free(snd_ctx);
-
        /* Return number of children to reap */
        return num_fds * 2;
 }
index bc5259d..409b721 100644 (file)
@@ -755,12 +755,16 @@ static int parse_vm_time_correlation(const struct option *opt, const char *str,
        return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
 }
 
+static int output_fd(struct perf_inject *inject)
+{
+       return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
+}
+
 static int __cmd_inject(struct perf_inject *inject)
 {
        int ret = -EINVAL;
        struct perf_session *session = inject->session;
-       struct perf_data *data_out = &inject->output;
-       int fd = inject->in_place_update ? -1 : perf_data__fd(data_out);
+       int fd = output_fd(inject);
        u64 output_data_offset;
 
        signal(SIGINT, sig_handler);
@@ -820,7 +824,7 @@ static int __cmd_inject(struct perf_inject *inject)
                inject->tool.ordered_events = true;
                inject->tool.ordering_requires_timestamps = true;
                /* Allow space in the header for new attributes */
-               output_data_offset = 4096;
+               output_data_offset = roundup(8192 + session->header.data_offset, 4096);
                if (inject->strip)
                        strip_init(inject);
        }
@@ -1015,7 +1019,7 @@ int cmd_inject(int argc, const char **argv)
        }
 
        inject.session = __perf_session__new(&data, repipe,
-                                            perf_data__fd(&inject.output),
+                                            output_fd(&inject),
                                             &inject.tool);
        if (IS_ERR(inject.session)) {
                ret = PTR_ERR(inject.session);
@@ -1078,7 +1082,8 @@ out_delete:
        zstd_fini(&(inject.session->zstd_data));
        perf_session__delete(inject.session);
 out_close_output:
-       perf_data__close(&inject.output);
+       if (!inject.in_place_update)
+               perf_data__close(&inject.output);
        free(inject.itrace_synth_opts.vm_tm_corr_args);
        return ret;
 }
index c895de4..d54c537 100644 (file)
@@ -169,7 +169,9 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u
        TEST_ASSERT_VAL("#num_dies", expr__parse(&num_dies, ctx, "#num_dies") == 0);
        TEST_ASSERT_VAL("#num_cores >= #num_dies", num_cores >= num_dies);
        TEST_ASSERT_VAL("#num_packages", expr__parse(&num_packages, ctx, "#num_packages") == 0);
-       TEST_ASSERT_VAL("#num_dies >= #num_packages", num_dies >= num_packages);
+
+       if (num_dies) // Some platforms do not have CPU die support, for example s390
+               TEST_ASSERT_VAL("#num_dies >= #num_packages", num_dies >= num_packages);
 
        /*
         * Source count returns the number of events aggregating in a leader
index 574b7e4..07b6f4e 100644 (file)
@@ -109,6 +109,7 @@ static void load_runtime_stat(struct runtime_stat *st, struct evlist *evlist,
        struct evsel *evsel;
        u64 count;
 
+       perf_stat__reset_shadow_stats();
        evlist__for_each_entry(evlist, evsel) {
                count = find_value(evsel->name, vals);
                perf_stat__update_shadow_stats(evsel, count, 0, st);
diff --git a/tools/perf/util/bpf_skel/bperf.h b/tools/perf/util/bpf_skel/bperf.h
deleted file mode 100644 (file)
index 186a555..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-// Copyright (c) 2021 Facebook
-
-#ifndef __BPERF_STAT_H
-#define __BPERF_STAT_H
-
-typedef struct {
-       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
-       __uint(key_size, sizeof(__u32));
-       __uint(value_size, sizeof(struct bpf_perf_event_value));
-       __uint(max_entries, 1);
-} reading_map;
-
-#endif /* __BPERF_STAT_H */
index b8fa3cb..f193998 100644 (file)
@@ -1,14 +1,23 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 // Copyright (c) 2021 Facebook
-#include <linux/bpf.h>
-#include <linux/perf_event.h>
+#include "vmlinux.h"
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
-#include "bperf.h"
 #include "bperf_u.h"
 
-reading_map diff_readings SEC(".maps");
-reading_map accum_readings SEC(".maps");
+struct {
+       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+       __uint(key_size, sizeof(__u32));
+       __uint(value_size, sizeof(struct bpf_perf_event_value));
+       __uint(max_entries, 1);
+} diff_readings SEC(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+       __uint(key_size, sizeof(__u32));
+       __uint(value_size, sizeof(struct bpf_perf_event_value));
+       __uint(max_entries, 1);
+} accum_readings SEC(".maps");
 
 struct {
        __uint(type, BPF_MAP_TYPE_HASH);
index 4f70d14..e2a2d4c 100644 (file)
@@ -1,10 +1,8 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 // Copyright (c) 2021 Facebook
-#include <linux/bpf.h>
-#include <linux/perf_event.h>
+#include "vmlinux.h"
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
-#include "bperf.h"
 
 struct {
        __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
@@ -13,8 +11,19 @@ struct {
        __uint(map_flags, BPF_F_PRESERVE_ELEMS);
 } events SEC(".maps");
 
-reading_map prev_readings SEC(".maps");
-reading_map diff_readings SEC(".maps");
+struct {
+       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+       __uint(key_size, sizeof(__u32));
+       __uint(value_size, sizeof(struct bpf_perf_event_value));
+       __uint(max_entries, 1);
+} prev_readings SEC(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+       __uint(key_size, sizeof(__u32));
+       __uint(value_size, sizeof(struct bpf_perf_event_value));
+       __uint(max_entries, 1);
+} diff_readings SEC(".maps");
 
 SEC("raw_tp/sched_switch")
 int BPF_PROG(on_switch)
index ab12b4c..97037d3 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 // Copyright (c) 2020 Facebook
-#include <linux/bpf.h>
+#include "vmlinux.h"
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
 
index 95ffed6..c59331e 100644 (file)
@@ -44,13 +44,16 @@ struct perf_event_attr;
 /* perf sample has 16 bits size limit */
 #define PERF_SAMPLE_MAX_SIZE (1 << 16)
 
+/* number of register is bound by the number of bits in regs_dump::mask (64) */
+#define PERF_SAMPLE_REGS_CACHE_SIZE (8 * sizeof(u64))
+
 struct regs_dump {
        u64 abi;
        u64 mask;
        u64 *regs;
 
        /* Cached values/mask filled by first register access. */
-       u64 cache_regs[PERF_REGS_MAX];
+       u64 cache_regs[PERF_SAMPLE_REGS_CACHE_SIZE];
        u64 cache_mask;
 };
 
index 1d532b9..2546010 100644 (file)
@@ -12,6 +12,7 @@
 #include "expr-bison.h"
 #include "expr-flex.h"
 #include "smt.h"
+#include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/zalloc.h>
 #include <ctype.h>
@@ -299,6 +300,10 @@ struct expr_parse_ctx *expr__ctx_new(void)
                return NULL;
 
        ctx->ids = hashmap__new(key_hash, key_equal, NULL);
+       if (IS_ERR(ctx->ids)) {
+               free(ctx);
+               return NULL;
+       }
        ctx->runtime = 0;
 
        return ctx;
index 79cce21..e3c1a53 100644 (file)
@@ -2321,6 +2321,7 @@ out:
 #define FEAT_PROCESS_STR_FUN(__feat, __feat_env) \
 static int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \
 {\
+       free(ff->ph->env.__feat_env);                \
        ff->ph->env.__feat_env = do_read_string(ff); \
        return ff->ph->env.__feat_env ? 0 : -ENOMEM; \
 }
@@ -4124,6 +4125,7 @@ int perf_event__process_feature(struct perf_session *session,
        struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event;
        int type = fe->header.type;
        u64 feat = fe->feat_id;
+       int ret = 0;
 
        if (type < 0 || type >= PERF_RECORD_HEADER_MAX) {
                pr_warning("invalid record type %d in pipe-mode\n", type);
@@ -4141,11 +4143,13 @@ int perf_event__process_feature(struct perf_session *session,
        ff.size = event->header.size - sizeof(*fe);
        ff.ph = &session->header;
 
-       if (feat_ops[feat].process(&ff, NULL))
-               return -1;
+       if (feat_ops[feat].process(&ff, NULL)) {
+               ret = -1;
+               goto out;
+       }
 
        if (!feat_ops[feat].print || !tool->show_feat_hdr)
-               return 0;
+               goto out;
 
        if (!feat_ops[feat].full_only ||
            tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) {
@@ -4154,8 +4158,9 @@ int perf_event__process_feature(struct perf_session *session,
                fprintf(stdout, "# %s info available, use -I to display\n",
                        feat_ops[feat].name);
        }
-
-       return 0;
+out:
+       free_event_desc(ff.events);
+       return ret;
 }
 
 size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
index 5f83937..0e013c2 100644 (file)
@@ -1205,61 +1205,69 @@ out_no_progress:
 
 static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
 {
+       enum intel_pt_sample_type type = decoder->state.type;
        bool ret = false;
 
+       decoder->state.type &= ~INTEL_PT_BRANCH;
+
        if (decoder->set_fup_tx_flags) {
                decoder->set_fup_tx_flags = false;
                decoder->tx_flags = decoder->fup_tx_flags;
-               decoder->state.type = INTEL_PT_TRANSACTION;
+               decoder->state.type |= INTEL_PT_TRANSACTION;
                if (decoder->fup_tx_flags & INTEL_PT_ABORT_TX)
                        decoder->state.type |= INTEL_PT_BRANCH;
-               decoder->state.from_ip = decoder->ip;
-               decoder->state.to_ip = 0;
                decoder->state.flags = decoder->fup_tx_flags;
-               return true;
+               ret = true;
        }
        if (decoder->set_fup_ptw) {
                decoder->set_fup_ptw = false;
-               decoder->state.type = INTEL_PT_PTW;
+               decoder->state.type |= INTEL_PT_PTW;
                decoder->state.flags |= INTEL_PT_FUP_IP;
-               decoder->state.from_ip = decoder->ip;
-               decoder->state.to_ip = 0;
                decoder->state.ptw_payload = decoder->fup_ptw_payload;
-               return true;
+               ret = true;
        }
        if (decoder->set_fup_mwait) {
                decoder->set_fup_mwait = false;
-               decoder->state.type = INTEL_PT_MWAIT_OP;
-               decoder->state.from_ip = decoder->ip;
-               decoder->state.to_ip = 0;
+               decoder->state.type |= INTEL_PT_MWAIT_OP;
                decoder->state.mwait_payload = decoder->fup_mwait_payload;
                ret = true;
        }
        if (decoder->set_fup_pwre) {
                decoder->set_fup_pwre = false;
                decoder->state.type |= INTEL_PT_PWR_ENTRY;
-               decoder->state.type &= ~INTEL_PT_BRANCH;
-               decoder->state.from_ip = decoder->ip;
-               decoder->state.to_ip = 0;
                decoder->state.pwre_payload = decoder->fup_pwre_payload;
                ret = true;
        }
        if (decoder->set_fup_exstop) {
                decoder->set_fup_exstop = false;
                decoder->state.type |= INTEL_PT_EX_STOP;
-               decoder->state.type &= ~INTEL_PT_BRANCH;
                decoder->state.flags |= INTEL_PT_FUP_IP;
-               decoder->state.from_ip = decoder->ip;
-               decoder->state.to_ip = 0;
                ret = true;
        }
        if (decoder->set_fup_bep) {
                decoder->set_fup_bep = false;
                decoder->state.type |= INTEL_PT_BLK_ITEMS;
-               decoder->state.type &= ~INTEL_PT_BRANCH;
+               ret = true;
+       }
+       if (decoder->overflow) {
+               decoder->overflow = false;
+               if (!ret && !decoder->pge) {
+                       if (decoder->hop) {
+                               decoder->state.type = 0;
+                               decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
+                       }
+                       decoder->pge = true;
+                       decoder->state.type |= INTEL_PT_BRANCH | INTEL_PT_TRACE_BEGIN;
+                       decoder->state.from_ip = 0;
+                       decoder->state.to_ip = decoder->ip;
+                       return true;
+               }
+       }
+       if (ret) {
                decoder->state.from_ip = decoder->ip;
                decoder->state.to_ip = 0;
-               ret = true;
+       } else {
+               decoder->state.type = type;
        }
        return ret;
 }
@@ -1608,7 +1616,16 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder)
        intel_pt_clear_tx_flags(decoder);
        intel_pt_set_nr(decoder);
        decoder->timestamp_insn_cnt = 0;
-       decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
+       decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
+       decoder->state.from_ip = decoder->ip;
+       decoder->ip = 0;
+       decoder->pge = false;
+       decoder->set_fup_tx_flags = false;
+       decoder->set_fup_ptw = false;
+       decoder->set_fup_mwait = false;
+       decoder->set_fup_pwre = false;
+       decoder->set_fup_exstop = false;
+       decoder->set_fup_bep = false;
        decoder->overflow = true;
        return -EOVERFLOW;
 }
@@ -2666,6 +2683,8 @@ static int intel_pt_scan_for_psb(struct intel_pt_decoder *decoder);
 /* Hop mode: Ignore TNT, do not walk code, but get ip from FUPs and TIPs */
 static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, int *err)
 {
+       *err = 0;
+
        /* Leap from PSB to PSB, getting ip from FUP within PSB+ */
        if (decoder->leap && !decoder->in_psb && decoder->packet.type != INTEL_PT_PSB) {
                *err = intel_pt_scan_for_psb(decoder);
@@ -2678,6 +2697,7 @@ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, in
                return HOP_IGNORE;
 
        case INTEL_PT_TIP_PGD:
+               decoder->pge = false;
                if (!decoder->packet.count) {
                        intel_pt_set_nr(decoder);
                        return HOP_IGNORE;
@@ -2705,18 +2725,21 @@ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, in
                if (!decoder->packet.count)
                        return HOP_IGNORE;
                intel_pt_set_ip(decoder);
-               if (intel_pt_fup_event(decoder))
-                       return HOP_RETURN;
-               if (!decoder->branch_enable)
+               if (decoder->set_fup_mwait || decoder->set_fup_pwre)
+                       *no_tip = true;
+               if (!decoder->branch_enable || !decoder->pge)
                        *no_tip = true;
                if (*no_tip) {
                        decoder->state.type = INTEL_PT_INSTRUCTION;
                        decoder->state.from_ip = decoder->ip;
                        decoder->state.to_ip = 0;
+                       intel_pt_fup_event(decoder);
                        return HOP_RETURN;
                }
+               intel_pt_fup_event(decoder);
+               decoder->state.type |= INTEL_PT_INSTRUCTION | INTEL_PT_BRANCH;
                *err = intel_pt_walk_fup_tip(decoder);
-               if (!*err)
+               if (!*err && decoder->state.to_ip)
                        decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
                return HOP_RETURN;
 
@@ -2897,7 +2920,7 @@ static bool intel_pt_psb_with_fup(struct intel_pt_decoder *decoder, int *err)
 {
        struct intel_pt_psb_info data = { .fup = false };
 
-       if (!decoder->branch_enable || !decoder->pge)
+       if (!decoder->branch_enable)
                return false;
 
        intel_pt_pkt_lookahead(decoder, intel_pt_psb_lookahead_cb, &data);
@@ -2924,6 +2947,7 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
                if (err)
                        return err;
 next:
+               err = 0;
                if (decoder->cyc_threshold) {
                        if (decoder->sample_cyc && last_packet_type != INTEL_PT_CYC)
                                decoder->sample_cyc = false;
@@ -2962,6 +2986,7 @@ next:
 
                case INTEL_PT_TIP_PGE: {
                        decoder->pge = true;
+                       decoder->overflow = false;
                        intel_pt_mtc_cyc_cnt_pge(decoder);
                        intel_pt_set_nr(decoder);
                        if (decoder->packet.count == 0) {
@@ -2999,7 +3024,7 @@ next:
                                break;
                        }
                        intel_pt_set_last_ip(decoder);
-                       if (!decoder->branch_enable) {
+                       if (!decoder->branch_enable || !decoder->pge) {
                                decoder->ip = decoder->last_ip;
                                if (intel_pt_fup_event(decoder))
                                        return 0;
@@ -3467,10 +3492,10 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
        decoder->set_fup_pwre = false;
        decoder->set_fup_exstop = false;
        decoder->set_fup_bep = false;
+       decoder->overflow = false;
 
        if (!decoder->branch_enable) {
                decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
-               decoder->overflow = false;
                decoder->state.type = 0; /* Do not have a sample */
                return 0;
        }
@@ -3485,7 +3510,6 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
                decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
        else
                decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
-       decoder->overflow = false;
 
        decoder->state.from_ip = 0;
        decoder->state.to_ip = decoder->ip;
@@ -3607,7 +3631,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder)
        }
 
        decoder->have_last_ip = true;
-       decoder->pkt_state = INTEL_PT_STATE_NO_IP;
+       decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
 
        err = intel_pt_walk_psb(decoder);
        if (err)
@@ -3704,7 +3728,8 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
 
        if (err) {
                decoder->state.err = intel_pt_ext_err(err);
-               decoder->state.from_ip = decoder->ip;
+               if (err != -EOVERFLOW)
+                       decoder->state.from_ip = decoder->ip;
                intel_pt_update_sample_time(decoder);
                decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt;
                intel_pt_set_nr(decoder);
index 556a893..10c3187 100644 (file)
@@ -2565,6 +2565,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
                                ptq->sync_switch = false;
                                intel_pt_next_tid(pt, ptq);
                        }
+                       ptq->timestamp = state->est_timestamp;
                        if (pt->synth_opts.errors) {
                                err = intel_ptq_synth_error(ptq, state);
                                if (err)
index 5ee47ae..06a7461 100644 (file)
@@ -25,6 +25,9 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
        int i, idx = 0;
        u64 mask = regs->mask;
 
+       if ((u64)id >= PERF_SAMPLE_REGS_CACHE_SIZE)
+               return -EINVAL;
+
        if (regs->cache_mask & (1ULL << id))
                goto out;
 
index 563a9ba..7f782a3 100644 (file)
@@ -461,7 +461,7 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
                struct tep_event *tp_format;
 
                tp_format = trace_event__tp_format_id(evsel->core.attr.config);
-               if (!tp_format)
+               if (IS_ERR_OR_NULL(tp_format))
                        return NULL;
 
                evsel->tp_format = tp_format;
index 20bacd5..34f1b1b 100644 (file)
@@ -15,7 +15,7 @@ int smt_on(void)
        if (cached)
                return cached_result;
 
-       if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) > 0)
+       if (sysfs__read_int("devices/system/cpu/smt/active", &cached_result) >= 0)
                goto done;
 
        ncpu = sysconf(_SC_NPROCESSORS_CONF);
index 331f6d3..cd71068 100644 (file)
@@ -69,6 +69,7 @@ KERNEL_INCLUDE := $(OUTPUT)include
 ACPICA_INCLUDE := $(srctree)/../../../drivers/acpi/acpica
 CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE)
 CFLAGS += $(WARNINGS)
+MKDIR = mkdir
 
 ifeq ($(strip $(V)),false)
        QUIET=@
index 2a6c170..1d7616f 100644 (file)
@@ -21,6 +21,7 @@ $(KERNEL_INCLUDE):
 
 $(objdir)%.o: %.c $(KERNEL_INCLUDE)
        $(ECHO) "  CC      " $(subst $(OUTPUT),,$@)
+       $(QUIET) $(MKDIR) -p $(objdir) 2>/dev/null
        $(QUIET) $(CC) -c $(CFLAGS) -o $@ $<
 
 all: $(OUTPUT)$(TOOL)
index 5d52ea2..df3b292 100644 (file)
@@ -33,6 +33,22 @@ noinline int bpf_testmod_loop_test(int n)
        return sum;
 }
 
+__weak noinline struct file *bpf_testmod_return_ptr(int arg)
+{
+       static struct file f = {};
+
+       switch (arg) {
+       case 1: return (void *)EINVAL;          /* user addr */
+       case 2: return (void *)0xcafe4a11;      /* user addr */
+       case 3: return (void *)-EINVAL;         /* canonical, but invalid */
+       case 4: return (void *)(1ull << 60);    /* non-canonical and invalid */
+       case 5: return (void *)~(1ull << 30);   /* trigger extable */
+       case 6: return &f;                      /* valid addr */
+       case 7: return (void *)((long)&f | 1);  /* kernel tricks */
+       default: return NULL;
+       }
+}
+
 noinline ssize_t
 bpf_testmod_test_read(struct file *file, struct kobject *kobj,
                      struct bin_attribute *bin_attr,
@@ -43,6 +59,10 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
                .off = off,
                .len = len,
        };
+       int i = 1;
+
+       while (bpf_testmod_return_ptr(i))
+               i++;
 
        /* This is always true. Use the check to make sure the compiler
         * doesn't remove bpf_testmod_loop_test.
index 762f6a9..664ffc0 100644 (file)
@@ -90,7 +90,7 @@ static void print_err_line(void)
 
 static void test_conn(void)
 {
-       int listen_fd = -1, cli_fd = -1, err;
+       int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
        socklen_t addrlen = sizeof(srv_sa6);
        int srv_port;
 
@@ -112,6 +112,10 @@ static void test_conn(void)
        if (CHECK_FAIL(cli_fd == -1))
                goto done;
 
+       srv_fd = accept(listen_fd, NULL, NULL);
+       if (CHECK_FAIL(srv_fd == -1))
+               goto done;
+
        if (CHECK(skel->bss->listen_tp_sport != srv_port ||
                  skel->bss->req_sk_sport != srv_port,
                  "Unexpected sk src port",
@@ -134,11 +138,13 @@ done:
                close(listen_fd);
        if (cli_fd != -1)
                close(cli_fd);
+       if (srv_fd != -1)
+               close(srv_fd);
 }
 
 static void test_syncookie(void)
 {
-       int listen_fd = -1, cli_fd = -1, err;
+       int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
        socklen_t addrlen = sizeof(srv_sa6);
        int srv_port;
 
@@ -161,6 +167,10 @@ static void test_syncookie(void)
        if (CHECK_FAIL(cli_fd == -1))
                goto done;
 
+       srv_fd = accept(listen_fd, NULL, NULL);
+       if (CHECK_FAIL(srv_fd == -1))
+               goto done;
+
        if (CHECK(skel->bss->listen_tp_sport != srv_port,
                  "Unexpected tp src port",
                  "listen_tp_sport:%u expected:%u\n",
@@ -188,6 +198,8 @@ done:
                close(listen_fd);
        if (cli_fd != -1)
                close(cli_fd);
+       if (srv_fd != -1)
+               close(srv_fd);
 }
 
 struct test {
index b368570..50ce16d 100644 (file)
@@ -87,6 +87,18 @@ int BPF_PROG(handle_fexit,
        return 0;
 }
 
+SEC("fexit/bpf_testmod_return_ptr")
+int BPF_PROG(handle_fexit_ret, int arg, struct file *ret)
+{
+       long buf = 0;
+
+       bpf_probe_read_kernel(&buf, 8, ret);
+       bpf_probe_read_kernel(&buf, 8, (char *)ret + 256);
+       *(volatile long long *)ret;
+       *(volatile int *)&ret->f_mode;
+       return 0;
+}
+
 __u32 fmod_ret_read_sz = 0;
 
 SEC("fmod_ret/bpf_testmod_test_read")
index 465ef3f..d3bf83d 100644 (file)
@@ -54,7 +54,7 @@
 #define MAX_INSNS      BPF_MAXINSNS
 #define MAX_TEST_INSNS 1000000
 #define MAX_FIXUPS     8
-#define MAX_NR_MAPS    21
+#define MAX_NR_MAPS    22
 #define MAX_TEST_RUNS  8
 #define POINTER_VALUE  0xcafe4all
 #define TEST_DATA_LEN  64
index c22dc83..b39665f 100644 (file)
                BPF_EXIT_INSN(),
        },
        .result = ACCEPT,
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R0 leaks addr into mem",
 },
 {
        "Dest pointer in r0 - succeed",
                BPF_EXIT_INSN(),
        },
        .result = ACCEPT,
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R0 leaks addr into mem",
+},
+{
+       "Dest pointer in r0 - succeed, check 2",
+       .insns = {
+               /* r0 = &val */
+               BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
+               /* val = r0; */
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
+               /* r5 = &val */
+               BPF_MOV64_REG(BPF_REG_5, BPF_REG_10),
+               /* r0 = atomic_cmpxchg(&val, r0, r5); */
+               BPF_ATOMIC_OP(BPF_DW, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
+               /* r1 = *r0 */
+               BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8),
+               /* exit(0); */
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R0 leaks addr into mem",
+},
+{
+       "Dest pointer in r0 - succeed, check 3",
+       .insns = {
+               /* r0 = &val */
+               BPF_MOV64_REG(BPF_REG_0, BPF_REG_10),
+               /* val = r0; */
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
+               /* r5 = &val */
+               BPF_MOV64_REG(BPF_REG_5, BPF_REG_10),
+               /* r0 = atomic_cmpxchg(&val, r0, r5); */
+               BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
+               /* exit(0); */
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = REJECT,
+       .errstr = "invalid size of register fill",
+       .errstr_unpriv = "R0 leaks addr into mem",
+},
+{
+       "Dest pointer in r0 - succeed, check 4",
+       .insns = {
+               /* r0 = &val */
+               BPF_MOV32_REG(BPF_REG_0, BPF_REG_10),
+               /* val = r0; */
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -8),
+               /* r5 = &val */
+               BPF_MOV32_REG(BPF_REG_5, BPF_REG_10),
+               /* r0 = atomic_cmpxchg(&val, r0, r5); */
+               BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
+               /* r1 = *r10 */
+               BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_10, -8),
+               /* exit(0); */
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "R10 partial copy of pointer",
+},
+{
+       "Dest pointer in r0 - succeed, check 5",
+       .insns = {
+               /* r0 = &val */
+               BPF_MOV32_REG(BPF_REG_0, BPF_REG_10),
+               /* val = r0; */
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -8),
+               /* r5 = &val */
+               BPF_MOV32_REG(BPF_REG_5, BPF_REG_10),
+               /* r0 = atomic_cmpxchg(&val, r0, r5); */
+               BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_5, -8),
+               /* r1 = *r0 */
+               BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -8),
+               /* exit(0); */
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = REJECT,
+       .errstr = "R0 invalid mem access",
+       .errstr_unpriv = "R10 partial copy of pointer",
 },
index 3bc9ff7..5bf03fb 100644 (file)
@@ -1,3 +1,97 @@
+{
+       "atomic dw/fetch and address leakage of (map ptr & -1) via stack slot",
+       .insns = {
+               BPF_LD_IMM64(BPF_REG_1, -1),
+               BPF_LD_MAP_FD(BPF_REG_8, 0),
+               BPF_LD_MAP_FD(BPF_REG_9, 0),
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+               BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_9, 0),
+               BPF_ATOMIC_OP(BPF_DW, BPF_AND | BPF_FETCH, BPF_REG_2, BPF_REG_1, 0),
+               BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_2, 0),
+               BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
+               BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_9, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .fixup_map_array_48b = { 2, 4 },
+       .result = ACCEPT,
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "leaking pointer from stack off -8",
+},
+{
+       "atomic dw/fetch and address leakage of (map ptr & -1) via returned value",
+       .insns = {
+               BPF_LD_IMM64(BPF_REG_1, -1),
+               BPF_LD_MAP_FD(BPF_REG_8, 0),
+               BPF_LD_MAP_FD(BPF_REG_9, 0),
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+               BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_9, 0),
+               BPF_ATOMIC_OP(BPF_DW, BPF_AND | BPF_FETCH, BPF_REG_2, BPF_REG_1, 0),
+               BPF_MOV64_REG(BPF_REG_9, BPF_REG_1),
+               BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
+               BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_9, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .fixup_map_array_48b = { 2, 4 },
+       .result = ACCEPT,
+       .result_unpriv = REJECT,
+       .errstr_unpriv = "leaking pointer from stack off -8",
+},
+{
+       "atomic w/fetch and address leakage of (map ptr & -1) via stack slot",
+       .insns = {
+               BPF_LD_IMM64(BPF_REG_1, -1),
+               BPF_LD_MAP_FD(BPF_REG_8, 0),
+               BPF_LD_MAP_FD(BPF_REG_9, 0),
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+               BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_9, 0),
+               BPF_ATOMIC_OP(BPF_W, BPF_AND | BPF_FETCH, BPF_REG_2, BPF_REG_1, 0),
+               BPF_LDX_MEM(BPF_DW, BPF_REG_9, BPF_REG_2, 0),
+               BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
+               BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_9, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .fixup_map_array_48b = { 2, 4 },
+       .result = REJECT,
+       .errstr = "invalid size of register fill",
+},
+{
+       "atomic w/fetch and address leakage of (map ptr & -1) via returned value",
+       .insns = {
+               BPF_LD_IMM64(BPF_REG_1, -1),
+               BPF_LD_MAP_FD(BPF_REG_8, 0),
+               BPF_LD_MAP_FD(BPF_REG_9, 0),
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+               BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_9, 0),
+               BPF_ATOMIC_OP(BPF_W, BPF_AND | BPF_FETCH, BPF_REG_2, BPF_REG_1, 0),
+               BPF_MOV64_REG(BPF_REG_9, BPF_REG_1),
+               BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
+               BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
+               BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_9, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .fixup_map_array_48b = { 2, 4 },
+       .result = REJECT,
+       .errstr = "invalid size of register fill",
+},
 #define __ATOMIC_FETCH_OP_TEST(src_reg, dst_reg, operand1, op, operand2, expect) \
        {                                                               \
                "atomic fetch " #op ", src=" #dst_reg " dst=" #dst_reg, \
index 7e50cb8..6825197 100644 (file)
        .prog_type = BPF_PROG_TYPE_TRACEPOINT,
 },
 {
+       "precision tracking for u32 spill/fill",
+       .insns = {
+               BPF_MOV64_REG(BPF_REG_7, BPF_REG_1),
+               BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
+               BPF_MOV32_IMM(BPF_REG_6, 32),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_MOV32_IMM(BPF_REG_6, 4),
+               /* Additional insns to introduce a pruning point. */
+               BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
+               BPF_MOV64_IMM(BPF_REG_3, 0),
+               BPF_MOV64_IMM(BPF_REG_3, 0),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_MOV64_IMM(BPF_REG_3, 0),
+               /* u32 spill/fill */
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_6, -8),
+               BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_10, -8),
+               /* out-of-bound map value access for r6=32 */
+               BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16),
+               BPF_LD_MAP_FD(BPF_REG_1, 0),
+               BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+               BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8),
+               BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .fixup_map_hash_8b = { 15 },
+       .result = REJECT,
+       .errstr = "R0 min value is outside of the allowed memory range",
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+},
+{
+       "precision tracking for u32 spills, u64 fill",
+       .insns = {
+               BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
+               BPF_MOV64_REG(BPF_REG_6, BPF_REG_0),
+               BPF_MOV32_IMM(BPF_REG_7, 0xffffffff),
+               /* Additional insns to introduce a pruning point. */
+               BPF_MOV64_IMM(BPF_REG_3, 1),
+               BPF_MOV64_IMM(BPF_REG_3, 1),
+               BPF_MOV64_IMM(BPF_REG_3, 1),
+               BPF_MOV64_IMM(BPF_REG_3, 1),
+               BPF_EMIT_CALL(BPF_FUNC_get_prandom_u32),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+               BPF_MOV64_IMM(BPF_REG_3, 1),
+               BPF_ALU32_IMM(BPF_DIV, BPF_REG_3, 0),
+               /* u32 spills, u64 fill */
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_6, -4),
+               BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7, -8),
+               BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_10, -8),
+               /* if r8 != X goto pc+1  r8 known in fallthrough branch */
+               BPF_JMP_IMM(BPF_JNE, BPF_REG_8, 0xffffffff, 1),
+               BPF_MOV64_IMM(BPF_REG_3, 1),
+               /* if r8 == X goto pc+1  condition always true on first
+                * traversal, so starts backtracking to mark r8 as requiring
+                * precision. r7 marked as needing precision. r6 not marked
+                * since it's not tracked.
+                */
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 0xffffffff, 1),
+               /* fails if r8 correctly marked unknown after fill. */
+               BPF_ALU32_IMM(BPF_DIV, BPF_REG_3, 0),
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = REJECT,
+       .errstr = "div by zero",
+       .prog_type = BPF_PROG_TYPE_TRACEPOINT,
+},
+{
        "allocated_stack",
        .insns = {
                BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_1),
index 7ab3de1..6c90714 100644 (file)
        .prog_type = BPF_PROG_TYPE_SCHED_CLS,
 },
 {
+       "Spill u32 const scalars.  Refill as u64.  Offset to skb->data",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct __sk_buff, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct __sk_buff, data_end)),
+       /* r6 = 0 */
+       BPF_MOV32_IMM(BPF_REG_6, 0),
+       /* r7 = 20 */
+       BPF_MOV32_IMM(BPF_REG_7, 20),
+       /* *(u32 *)(r10 -4) = r6 */
+       BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_6, -4),
+       /* *(u32 *)(r10 -8) = r7 */
+       BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_7, -8),
+       /* r4 = *(u64 *)(r10 -8) */
+       BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_10, -8),
+       /* r0 = r2 */
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
+       /* r0 += r4 R0=pkt R2=pkt R3=pkt_end R4=inv,umax=65535 */
+       BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_4),
+       /* if (r0 > r3) R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=inv,umax=65535 */
+       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
+       /* r0 = *(u32 *)r2 R0=pkt,umax=65535 R2=pkt R3=pkt_end R4=inv20 */
+       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = REJECT,
+       .errstr = "invalid access to packet",
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+},
+{
        "Spill a u32 const scalar.  Refill as u16 from fp-6.  Offset to skb->data",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
index 2debba4..4d347bc 100644 (file)
        .errstr_unpriv = "R0 pointer -= pointer prohibited",
 },
 {
+       "map access: trying to leak tained dst reg",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+       BPF_LD_MAP_FD(BPF_REG_1, 0),
+       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_REG(BPF_REG_2, BPF_REG_0),
+       BPF_MOV32_IMM(BPF_REG_1, 0xFFFFFFFF),
+       BPF_MOV32_REG(BPF_REG_1, BPF_REG_1),
+       BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
+       BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .fixup_map_array_48b = { 4 },
+       .result = REJECT,
+       .errstr = "math between map_value pointer and 4294967295 is not allowed",
+},
+{
        "32bit pkt_ptr -= scalar",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_1,
index bfb9738..b4ec228 100644 (file)
@@ -35,7 +35,7 @@
        .prog_type = BPF_PROG_TYPE_XDP,
 },
 {
-       "XDP pkt read, pkt_data' > pkt_end, good access",
+       "XDP pkt read, pkt_data' > pkt_end, corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_data' > pkt_end, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data' > pkt_end, corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_end > pkt_data', good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_end > pkt_data', bad access 1",
+       "XDP pkt read, pkt_end > pkt_data', corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
                    offsetof(struct xdp_md, data_end)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
        BPF_JMP_IMM(BPF_JA, 0, 0, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_end > pkt_data', corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_end > pkt_data', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_data' < pkt_end, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data' < pkt_end, bad access 1",
+       "XDP pkt read, pkt_data' < pkt_end, corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
                    offsetof(struct xdp_md, data_end)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
        BPF_JMP_IMM(BPF_JA, 0, 0, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_end < pkt_data', good access",
+       "XDP pkt read, pkt_data' < pkt_end, corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data' < pkt_end, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_end < pkt_data', corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_end < pkt_data', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_end < pkt_data', corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_data' >= pkt_end, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data' >= pkt_end, bad access 1",
+       "XDP pkt read, pkt_data' >= pkt_end, corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
                    offsetof(struct xdp_md, data_end)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_end >= pkt_data', good access",
+       "XDP pkt read, pkt_data' >= pkt_end, corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data' >= pkt_end, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_end >= pkt_data', corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data' <= pkt_end, good access",
+       "XDP pkt read, pkt_end >= pkt_data', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_end >= pkt_data', corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data' <= pkt_end, corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_data' <= pkt_end, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data' <= pkt_end, corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_end <= pkt_data', good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_end <= pkt_data', bad access 1",
+       "XDP pkt read, pkt_end <= pkt_data', corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
                    offsetof(struct xdp_md, data_end)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_meta' > pkt_data, good access",
+       "XDP pkt read, pkt_end <= pkt_data', corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_end <= pkt_data', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                   offsetof(struct xdp_md, data_end)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_meta' > pkt_data, corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_meta' > pkt_data, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_meta' > pkt_data, corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_data > pkt_meta', good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data > pkt_meta', bad access 1",
+       "XDP pkt read, pkt_data > pkt_meta', corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
        BPF_JMP_IMM(BPF_JA, 0, 0, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_data > pkt_meta', corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data > pkt_meta', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JGT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_meta' < pkt_data, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_meta' < pkt_data, bad access 1",
+       "XDP pkt read, pkt_meta' < pkt_data, corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
        BPF_JMP_IMM(BPF_JA, 0, 0, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data < pkt_meta', good access",
+       "XDP pkt read, pkt_meta' < pkt_data, corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_meta' < pkt_data, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data < pkt_meta', corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_data < pkt_meta', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data < pkt_meta', corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLT, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_meta' >= pkt_data, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_meta' >= pkt_data, bad access 1",
+       "XDP pkt read, pkt_meta' >= pkt_data, corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data >= pkt_meta', good access",
+       "XDP pkt read, pkt_meta' >= pkt_data, corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_meta' >= pkt_data, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data >= pkt_meta', corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_meta' <= pkt_data, good access",
+       "XDP pkt read, pkt_data >= pkt_meta', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data >= pkt_meta', corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_meta' <= pkt_data, corner case, good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "XDP pkt read, pkt_meta' <= pkt_data, corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 9),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -9),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_meta' <= pkt_data, corner case -1, bad access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_1, BPF_REG_3, 1),
+       BPF_JMP_IMM(BPF_JA, 0, 0, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .errstr = "R1 offset is outside of the packet",
+       .result = REJECT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
        "XDP pkt read, pkt_data <= pkt_meta', good access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
-       "XDP pkt read, pkt_data <= pkt_meta', bad access 1",
+       "XDP pkt read, pkt_data <= pkt_meta', corner case -1, bad access",
        .insns = {
        BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
                    offsetof(struct xdp_md, data_meta)),
        BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
        BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
-       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
        BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
-       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -6),
        BPF_MOV64_IMM(BPF_REG_0, 0),
        BPF_EXIT_INSN(),
        },
        .prog_type = BPF_PROG_TYPE_XDP,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
+{
+       "XDP pkt read, pkt_data <= pkt_meta', corner case, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 7),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -7),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
+{
+       "XDP pkt read, pkt_data <= pkt_meta', corner case +1, good access",
+       .insns = {
+       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                   offsetof(struct xdp_md, data_meta)),
+       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, offsetof(struct xdp_md, data)),
+       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+       BPF_JMP_REG(BPF_JLE, BPF_REG_3, BPF_REG_1, 1),
+       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8),
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .prog_type = BPF_PROG_TYPE_XDP,
+       .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
+},
diff --git a/tools/testing/selftests/damon/.gitignore b/tools/testing/selftests/damon/.gitignore
new file mode 100644 (file)
index 0000000..c6c2965
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+huge_count_read_write
index 8a3f2cd..937d36a 100644 (file)
@@ -1,7 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for damon selftests
 
-TEST_FILES = _chk_dependency.sh
-TEST_PROGS = debugfs_attrs.sh
+TEST_GEN_FILES += huge_count_read_write
+
+TEST_FILES = _chk_dependency.sh _debugfs_common.sh
+TEST_PROGS = debugfs_attrs.sh debugfs_schemes.sh debugfs_target_ids.sh
+TEST_PROGS += debugfs_empty_targets.sh debugfs_huge_count_read_write.sh
 
 include ../lib.mk
diff --git a/tools/testing/selftests/damon/_debugfs_common.sh b/tools/testing/selftests/damon/_debugfs_common.sh
new file mode 100644 (file)
index 0000000..48989d4
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+test_write_result() {
+       file=$1
+       content=$2
+       orig_content=$3
+       expect_reason=$4
+       expected=$5
+
+       echo "$content" > "$file"
+       if [ $? -ne "$expected" ]
+       then
+               echo "writing $content to $file doesn't return $expected"
+               echo "expected because: $expect_reason"
+               echo "$orig_content" > "$file"
+               exit 1
+       fi
+}
+
+test_write_succ() {
+       test_write_result "$1" "$2" "$3" "$4" 0
+}
+
+test_write_fail() {
+       test_write_result "$1" "$2" "$3" "$4" 1
+}
+
+test_content() {
+       file=$1
+       orig_content=$2
+       expected=$3
+       expect_reason=$4
+
+       content=$(cat "$file")
+       if [ "$content" != "$expected" ]
+       then
+               echo "reading $file expected $expected but $content"
+               echo "expected because: $expect_reason"
+               echo "$orig_content" > "$file"
+               exit 1
+       fi
+}
+
+source ./_chk_dependency.sh
+
+damon_onoff="$DBGFS/monitor_on"
+if [ $(cat "$damon_onoff") = "on" ]
+then
+       echo "monitoring is on"
+       exit $ksft_skip
+fi
index 196b664..902e312 100644 (file)
@@ -1,48 +1,7 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
-test_write_result() {
-       file=$1
-       content=$2
-       orig_content=$3
-       expect_reason=$4
-       expected=$5
-
-       echo "$content" > "$file"
-       if [ $? -ne "$expected" ]
-       then
-               echo "writing $content to $file doesn't return $expected"
-               echo "expected because: $expect_reason"
-               echo "$orig_content" > "$file"
-               exit 1
-       fi
-}
-
-test_write_succ() {
-       test_write_result "$1" "$2" "$3" "$4" 0
-}
-
-test_write_fail() {
-       test_write_result "$1" "$2" "$3" "$4" 1
-}
-
-test_content() {
-       file=$1
-       orig_content=$2
-       expected=$3
-       expect_reason=$4
-
-       content=$(cat "$file")
-       if [ "$content" != "$expected" ]
-       then
-               echo "reading $file expected $expected but $content"
-               echo "expected because: $expect_reason"
-               echo "$orig_content" > "$file"
-               exit 1
-       fi
-}
-
-source ./_chk_dependency.sh
+source _debugfs_common.sh
 
 # Test attrs file
 # ===============
@@ -56,33 +15,3 @@ test_write_fail "$file" "1 2 3 5 4" "$orig_content" \
        "min_nr_regions > max_nr_regions"
 test_content "$file" "$orig_content" "1 2 3 4 5" "successfully written"
 echo "$orig_content" > "$file"
-
-# Test schemes file
-# =================
-
-file="$DBGFS/schemes"
-orig_content=$(cat "$file")
-
-test_write_succ "$file" "1 2 3 4 5 6 4 0 0 0 1 2 3 1 100 3 2 1" \
-       "$orig_content" "valid input"
-test_write_fail "$file" "1 2
-3 4 5 6 3 0 0 0 1 2 3 1 100 3 2 1" "$orig_content" "multi lines"
-test_write_succ "$file" "" "$orig_content" "disabling"
-echo "$orig_content" > "$file"
-
-# Test target_ids file
-# ====================
-
-file="$DBGFS/target_ids"
-orig_content=$(cat "$file")
-
-test_write_succ "$file" "1 2 3 4" "$orig_content" "valid input"
-test_write_succ "$file" "1 2 abc 4" "$orig_content" "still valid input"
-test_content "$file" "$orig_content" "1 2" "non-integer was there"
-test_write_succ "$file" "abc 2 3" "$orig_content" "the file allows wrong input"
-test_content "$file" "$orig_content" "" "wrong input written"
-test_write_succ "$file" "" "$orig_content" "empty input"
-test_content "$file" "$orig_content" "" "empty input written"
-echo "$orig_content" > "$file"
-
-echo "PASS"
diff --git a/tools/testing/selftests/damon/debugfs_empty_targets.sh b/tools/testing/selftests/damon/debugfs_empty_targets.sh
new file mode 100644 (file)
index 0000000..87aff80
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+source _debugfs_common.sh
+
+# Test empty targets case
+# =======================
+
+orig_target_ids=$(cat "$DBGFS/target_ids")
+echo "" > "$DBGFS/target_ids"
+orig_monitor_on=$(cat "$DBGFS/monitor_on")
+test_write_fail "$DBGFS/monitor_on" "on" "orig_monitor_on" "empty target ids"
+echo "$orig_target_ids" > "$DBGFS/target_ids"
diff --git a/tools/testing/selftests/damon/debugfs_huge_count_read_write.sh b/tools/testing/selftests/damon/debugfs_huge_count_read_write.sh
new file mode 100644 (file)
index 0000000..922cada
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+source _debugfs_common.sh
+
+# Test huge count read write
+# ==========================
+
+dmesg -C
+
+for file in "$DBGFS/"*
+do
+       ./huge_count_read_write "$file"
+done
+
+if dmesg | grep -q WARNING
+then
+       dmesg
+       exit 1
+else
+       exit 0
+fi
diff --git a/tools/testing/selftests/damon/debugfs_schemes.sh b/tools/testing/selftests/damon/debugfs_schemes.sh
new file mode 100644 (file)
index 0000000..5b39ab4
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+source _debugfs_common.sh
+
+# Test schemes file
+# =================
+
+file="$DBGFS/schemes"
+orig_content=$(cat "$file")
+
+test_write_succ "$file" "1 2 3 4 5 6 4 0 0 0 1 2 3 1 100 3 2 1" \
+       "$orig_content" "valid input"
+test_write_fail "$file" "1 2
+3 4 5 6 3 0 0 0 1 2 3 1 100 3 2 1" "$orig_content" "multi lines"
+test_write_succ "$file" "" "$orig_content" "disabling"
+test_write_fail "$file" "2 1 2 1 10 1 3 10 1 1 1 1 1 1 1 1 2 3" \
+       "$orig_content" "wrong condition ranges"
+echo "$orig_content" > "$file"
diff --git a/tools/testing/selftests/damon/debugfs_target_ids.sh b/tools/testing/selftests/damon/debugfs_target_ids.sh
new file mode 100644 (file)
index 0000000..49aeabd
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+source _debugfs_common.sh
+
+# Test target_ids file
+# ====================
+
+file="$DBGFS/target_ids"
+orig_content=$(cat "$file")
+
+test_write_succ "$file" "1 2 3 4" "$orig_content" "valid input"
+test_write_succ "$file" "1 2 abc 4" "$orig_content" "still valid input"
+test_content "$file" "$orig_content" "1 2" "non-integer was there"
+test_write_succ "$file" "abc 2 3" "$orig_content" "the file allows wrong input"
+test_content "$file" "$orig_content" "" "wrong input written"
+test_write_succ "$file" "" "$orig_content" "empty input"
+test_content "$file" "$orig_content" "" "empty input written"
+echo "$orig_content" > "$file"
diff --git a/tools/testing/selftests/damon/huge_count_read_write.c b/tools/testing/selftests/damon/huge_count_read_write.c
new file mode 100644 (file)
index 0000000..ad7a6b4
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: SeongJae Park <sj@kernel.org>
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+void write_read_with_huge_count(char *file)
+{
+       int filedesc = open(file, O_RDWR);
+       char buf[25];
+       int ret;
+
+       printf("%s %s\n", __func__, file);
+       if (filedesc < 0) {
+               fprintf(stderr, "failed opening %s\n", file);
+               exit(1);
+       }
+
+       write(filedesc, "", 0xfffffffful);
+       perror("after write: ");
+       ret = read(filedesc, buf, 0xfffffffful);
+       perror("after read: ");
+       close(filedesc);
+}
+
+int main(int argc, char *argv[])
+{
+       if (argc != 2) {
+               fprintf(stderr, "Usage: %s <file>\n", argv[0]);
+               exit(1);
+       }
+       write_read_with_huge_count(argv[1]);
+
+       return 0;
+}
index b513f64..026a126 100755 (executable)
@@ -72,6 +72,35 @@ rif_mac_profile_replacement_test()
        ip link set $h1.10 address $h1_10_mac
 }
 
+rif_mac_profile_consolidation_test()
+{
+       local count=$1; shift
+       local h1_20_mac
+
+       RET=0
+
+       if [[ $count -eq 1 ]]; then
+               return
+       fi
+
+       h1_20_mac=$(mac_get $h1.20)
+
+       # Set the MAC of $h1.20 to that of $h1.10 and confirm that they are
+       # using the same MAC profile.
+       ip link set $h1.20 address 00:11:11:11:11:11
+       check_err $?
+
+       occ=$(devlink -j resource show $DEVLINK_DEV \
+             | jq '.[][][] | select(.name=="rif_mac_profiles") |.["occ"]')
+
+       [[ $occ -eq $((count - 1)) ]]
+       check_err $? "MAC profile occupancy did not decrease"
+
+       log_test "RIF MAC profile consolidation"
+
+       ip link set $h1.20 address $h1_20_mac
+}
+
 rif_mac_profile_shared_replacement_test()
 {
        local count=$1; shift
@@ -104,6 +133,7 @@ rif_mac_profile_edit_test()
        create_max_rif_mac_profiles $count
 
        rif_mac_profile_replacement_test
+       rif_mac_profile_consolidation_test $count
        rif_mac_profile_shared_replacement_test $count
 }
 
index 3763105..00814c0 100644 (file)
@@ -30,6 +30,7 @@
 /x86_64/svm_int_ctl_test
 /x86_64/sync_regs_test
 /x86_64/tsc_msrs_test
+/x86_64/userspace_io_test
 /x86_64/userspace_msr_exit_test
 /x86_64/vmx_apic_access_test
 /x86_64/vmx_close_while_nested_test
index c4e3471..f307c9f 100644 (file)
@@ -59,6 +59,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test
 TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test
 TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test
 TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test
+TEST_GEN_PROGS_x86_64 += x86_64/userspace_io_test
 TEST_GEN_PROGS_x86_64 += x86_64/userspace_msr_exit_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
index 6a1a37f..da2b702 100644 (file)
@@ -71,6 +71,15 @@ enum vm_guest_mode {
 
 #endif
 
+#if defined(__x86_64__)
+unsigned long vm_compute_max_gfn(struct kvm_vm *vm);
+#else
+static inline unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
+{
+       return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
+}
+#endif
+
 #define MIN_PAGE_SIZE          (1U << MIN_PAGE_SHIFT)
 #define PTES_PER_MIN_PAGE      ptes_per_page(MIN_PAGE_SIZE)
 
index 8f2e0bb..daf6fdb 100644 (file)
@@ -302,7 +302,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm)
                (1ULL << (vm->va_bits - 1)) >> vm->page_shift);
 
        /* Limit physical addresses to PA-bits. */
-       vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
+       vm->max_gfn = vm_compute_max_gfn(vm);
 
        /* Allocate and setup memory for guest. */
        vm->vpages_mapped = sparsebit_alloc();
index 82c39db..eef7b34 100644 (file)
@@ -1431,3 +1431,71 @@ struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpui
 
        return cpuid;
 }
+
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163
+#define X86EMUL_CPUID_VENDOR_AuthenticAMD_edx 0x69746e65
+
+static inline unsigned x86_family(unsigned int eax)
+{
+        unsigned int x86;
+
+        x86 = (eax >> 8) & 0xf;
+
+        if (x86 == 0xf)
+                x86 += (eax >> 20) & 0xff;
+
+        return x86;
+}
+
+unsigned long vm_compute_max_gfn(struct kvm_vm *vm)
+{
+       const unsigned long num_ht_pages = 12 << (30 - vm->page_shift); /* 12 GiB */
+       unsigned long ht_gfn, max_gfn, max_pfn;
+       uint32_t eax, ebx, ecx, edx, max_ext_leaf;
+
+       max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1;
+
+       /* Avoid reserved HyperTransport region on AMD processors.  */
+       eax = ecx = 0;
+       cpuid(&eax, &ebx, &ecx, &edx);
+       if (ebx != X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx ||
+           ecx != X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx ||
+           edx != X86EMUL_CPUID_VENDOR_AuthenticAMD_edx)
+               return max_gfn;
+
+       /* On parts with <40 physical address bits, the area is fully hidden */
+       if (vm->pa_bits < 40)
+               return max_gfn;
+
+       /* Before family 17h, the HyperTransport area is just below 1T.  */
+       ht_gfn = (1 << 28) - num_ht_pages;
+       eax = 1;
+       cpuid(&eax, &ebx, &ecx, &edx);
+       if (x86_family(eax) < 0x17)
+               goto done;
+
+       /*
+        * Otherwise it's at the top of the physical address space, possibly
+        * reduced due to SME by bits 11:6 of CPUID[0x8000001f].EBX.  Use
+        * the old conservative value if MAXPHYADDR is not enumerated.
+        */
+       eax = 0x80000000;
+       cpuid(&eax, &ebx, &ecx, &edx);
+       max_ext_leaf = eax;
+       if (max_ext_leaf < 0x80000008)
+               goto done;
+
+       eax = 0x80000008;
+       cpuid(&eax, &ebx, &ecx, &edx);
+       max_pfn = (1ULL << ((eax & 0xff) - vm->page_shift)) - 1;
+       if (max_ext_leaf >= 0x8000001f) {
+               eax = 0x8000001f;
+               cpuid(&eax, &ebx, &ecx, &edx);
+               max_pfn >>= (ebx >> 6) & 0x3f;
+       }
+
+       ht_gfn = max_pfn - num_ht_pages;
+done:
+       return min(max_gfn, ht_gfn - 1);
+}
index df04f56..30a8103 100644 (file)
@@ -75,7 +75,7 @@ static void l1_guest_code(struct svm_test_data *svm)
        vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
 
        /* No intercepts for real and virtual interrupts */
-       vmcb->control.intercept &= ~(1ULL << INTERCEPT_INTR | INTERCEPT_VINTR);
+       vmcb->control.intercept &= ~(BIT(INTERCEPT_INTR) | BIT(INTERCEPT_VINTR));
 
        /* Make a virtual interrupt VINTR_IRQ_NUMBER pending */
        vmcb->control.int_ctl |= V_IRQ_MASK | (0x1 << V_INTR_PRIO_SHIFT);
diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c
new file mode 100644 (file)
index 0000000..e4bef2e
--- /dev/null
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+
+#include "kvm_util.h"
+#include "processor.h"
+
+#define VCPU_ID                        1
+
+static void guest_ins_port80(uint8_t *buffer, unsigned int count)
+{
+       unsigned long end;
+
+       if (count == 2)
+               end = (unsigned long)buffer + 1;
+       else
+               end = (unsigned long)buffer + 8192;
+
+       asm volatile("cld; rep; insb" : "+D"(buffer), "+c"(count) : "d"(0x80) : "memory");
+       GUEST_ASSERT_1(count == 0, count);
+       GUEST_ASSERT_2((unsigned long)buffer == end, buffer, end);
+}
+
+static void guest_code(void)
+{
+       uint8_t buffer[8192];
+       int i;
+
+       /*
+        * Special case tests.  main() will adjust RCX 2 => 1 and 3 => 8192 to
+        * test that KVM doesn't explode when userspace modifies the "count" on
+        * a userspace I/O exit.  KVM isn't required to play nice with the I/O
+        * itself as KVM doesn't support manipulating the count, it just needs
+        * to not explode or overflow a buffer.
+        */
+       guest_ins_port80(buffer, 2);
+       guest_ins_port80(buffer, 3);
+
+       /* Verify KVM fills the buffer correctly when not stuffing RCX. */
+       memset(buffer, 0, sizeof(buffer));
+       guest_ins_port80(buffer, 8192);
+       for (i = 0; i < 8192; i++)
+               GUEST_ASSERT_2(buffer[i] == 0xaa, i, buffer[i]);
+
+       GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+       struct kvm_regs regs;
+       struct kvm_run *run;
+       struct kvm_vm *vm;
+       struct ucall uc;
+       int rc;
+
+       /* Tell stdout not to buffer its content */
+       setbuf(stdout, NULL);
+
+       /* Create VM */
+       vm = vm_create_default(VCPU_ID, 0, guest_code);
+       run = vcpu_state(vm, VCPU_ID);
+
+       memset(&regs, 0, sizeof(regs));
+
+       while (1) {
+               rc = _vcpu_run(vm, VCPU_ID);
+
+               TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc);
+               TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                           "Unexpected exit reason: %u (%s),\n",
+                           run->exit_reason,
+                           exit_reason_str(run->exit_reason));
+
+               if (get_ucall(vm, VCPU_ID, &uc))
+                       break;
+
+               TEST_ASSERT(run->io.port == 0x80,
+                           "Expected I/O at port 0x80, got port 0x%x\n", run->io.port);
+
+               /*
+                * Modify the rep string count in RCX: 2 => 1 and 3 => 8192.
+                * Note, this abuses KVM's batching of rep string I/O to avoid
+                * getting stuck in an infinite loop.  That behavior isn't in
+                * scope from a testing perspective as it's not ABI in any way,
+                * i.e. it really is abusing internal KVM knowledge.
+                */
+               vcpu_regs_get(vm, VCPU_ID, &regs);
+               if (regs.rcx == 2)
+                       regs.rcx = 1;
+               if (regs.rcx == 3)
+                       regs.rcx = 8192;
+               memset((void *)run + run->io.data_offset, 0xaa, 4096);
+               vcpu_regs_set(vm, VCPU_ID, &regs);
+       }
+
+       switch (uc.cmd) {
+       case UCALL_DONE:
+               break;
+       case UCALL_ABORT:
+               TEST_FAIL("%s at %s:%ld : argN+1 = 0x%lx, argN+2 = 0x%lx",
+                         (const char *)uc.args[0], __FILE__, uc.args[1],
+                         uc.args[2], uc.args[3]);
+       default:
+               TEST_FAIL("Unknown ucall %lu", uc.cmd);
+       }
+
+       kvm_vm_free(vm);
+       return 0;
+}
index 23051d8..2454a1f 100644 (file)
@@ -110,22 +110,5 @@ int main(int argc, char *argv[])
        ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
        TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");
 
-       /* testcase 4, set capabilities when we don't have PDCM bit */
-       entry_1_0->ecx &= ~X86_FEATURE_PDCM;
-       vcpu_set_cpuid(vm, VCPU_ID, cpuid);
-       ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
-       TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");
-
-       /* testcase 5, set capabilities when we don't have PMU version bits */
-       entry_1_0->ecx |= X86_FEATURE_PDCM;
-       eax.split.version_id = 0;
-       entry_1_0->ecx = eax.full;
-       vcpu_set_cpuid(vm, VCPU_ID, cpuid);
-       ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
-       TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");
-
-       vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0);
-       ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), 0);
-
        kvm_vm_free(vm);
 }
index 7f5b265..ad2982b 100755 (executable)
@@ -455,6 +455,22 @@ cleanup()
        ip netns del ${NSC} >/dev/null 2>&1
 }
 
+cleanup_vrf_dup()
+{
+       ip link del ${NSA_DEV2} >/dev/null 2>&1
+       ip netns pids ${NSC} | xargs kill 2>/dev/null
+       ip netns del ${NSC} >/dev/null 2>&1
+}
+
+setup_vrf_dup()
+{
+       # some VRF tests use ns-C which has the same config as
+       # ns-B but for a device NOT in the VRF
+       create_ns ${NSC} "-" "-"
+       connect_ns ${NSA} ${NSA_DEV2} ${NSA_IP}/24 ${NSA_IP6}/64 \
+                  ${NSC} ${NSC_DEV} ${NSB_IP}/24 ${NSB_IP6}/64
+}
+
 setup()
 {
        local with_vrf=${1}
@@ -484,12 +500,6 @@ setup()
 
                ip -netns ${NSB} ro add ${VRF_IP}/32 via ${NSA_IP} dev ${NSB_DEV}
                ip -netns ${NSB} -6 ro add ${VRF_IP6}/128 via ${NSA_IP6} dev ${NSB_DEV}
-
-               # some VRF tests use ns-C which has the same config as
-               # ns-B but for a device NOT in the VRF
-               create_ns ${NSC} "-" "-"
-               connect_ns ${NSA} ${NSA_DEV2} ${NSA_IP}/24 ${NSA_IP6}/64 \
-                          ${NSC} ${NSC_DEV} ${NSB_IP}/24 ${NSB_IP6}/64
        else
                ip -netns ${NSA} ro add ${NSB_LO_IP}/32 via ${NSB_IP} dev ${NSA_DEV}
                ip -netns ${NSA} ro add ${NSB_LO_IP6}/128 via ${NSB_IP6} dev ${NSA_DEV}
@@ -1240,7 +1250,9 @@ ipv4_tcp_vrf()
        log_test_addr ${a} $? 1 "Global server, local connection"
 
        # run MD5 tests
+       setup_vrf_dup
        ipv4_tcp_md5
+       cleanup_vrf_dup
 
        #
        # enable VRF global server
@@ -1798,8 +1810,9 @@ ipv4_addr_bind_vrf()
        for a in ${NSA_IP} ${VRF_IP}
        do
                log_start
+               show_hint "Socket not bound to VRF, but address is in VRF"
                run_cmd nettest -s -R -P icmp -l ${a} -b
-               log_test_addr ${a} $? 0 "Raw socket bind to local address"
+               log_test_addr ${a} $? 1 "Raw socket bind to local address"
 
                log_start
                run_cmd nettest -s -R -P icmp -l ${a} -I ${NSA_DEV} -b
@@ -2191,7 +2204,7 @@ ipv6_ping_vrf()
                log_start
                show_hint "Fails since VRF device does not support linklocal or multicast"
                run_cmd ${ping6} -c1 -w1 ${a}
-               log_test_addr ${a} $? 2 "ping out, VRF bind"
+               log_test_addr ${a} $? 1 "ping out, VRF bind"
        done
 
        for a in ${NSB_IP6} ${NSB_LO_IP6} ${NSB_LINKIP6}%${NSA_DEV} ${MCAST}%${NSA_DEV}
@@ -2719,7 +2732,9 @@ ipv6_tcp_vrf()
        log_test_addr ${a} $? 1 "Global server, local connection"
 
        # run MD5 tests
+       setup_vrf_dup
        ipv6_tcp_md5
+       cleanup_vrf_dup
 
        #
        # enable VRF global server
@@ -3414,11 +3429,14 @@ ipv6_addr_bind_novrf()
        run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
        log_test_addr ${a} $? 0 "TCP socket bind to local address after device bind"
 
+       # Sadly, the kernel allows binding a socket to a device and then
+       # binding to an address not on the device. So this test passes
+       # when it really should not
        a=${NSA_LO_IP6}
        log_start
-       show_hint "Should fail with 'Cannot assign requested address'"
+       show_hint "Tecnically should fail since address is not on device but kernel allows"
        run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
-       log_test_addr ${a} $? 1 "TCP socket bind to out of scope local address"
+       log_test_addr ${a} $? 0 "TCP socket bind to out of scope local address"
 }
 
 ipv6_addr_bind_vrf()
@@ -3459,10 +3477,15 @@ ipv6_addr_bind_vrf()
        run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
        log_test_addr ${a} $? 0 "TCP socket bind to local address with device bind"
 
+       # Sadly, the kernel allows binding a socket to a device and then
+       # binding to an address not on the device. The only restriction
+       # is that the address is valid in the L3 domain. So this test
+       # passes when it really should not
        a=${VRF_IP6}
        log_start
+       show_hint "Tecnically should fail since address is not on device but kernel allows"
        run_cmd nettest -6 -s -l ${a} -I ${NSA_DEV} -t1 -b
-       log_test_addr ${a} $? 1 "TCP socket bind to VRF address with device bind"
+       log_test_addr ${a} $? 0 "TCP socket bind to VRF address with device bind"
 
        a=${NSA_LO_IP6}
        log_start
@@ -4077,3 +4100,11 @@ cleanup 2>/dev/null
 
 printf "\nTests passed: %3d\n" ${nsuccess}
 printf "Tests failed: %3d\n"   ${nfail}
+
+if [ $nfail -ne 0 ]; then
+       exit 1 # KSFT_FAIL
+elif [ $nsuccess -eq 0 ]; then
+       exit $ksft_skip
+fi
+
+exit 0 # KSFT_PASS
index 5abe92d..996af1a 100755 (executable)
@@ -444,24 +444,63 @@ fib_rp_filter_test()
        setup
 
        set -e
+       ip netns add ns2
+       ip netns set ns2 auto
+
+       ip -netns ns2 link set dev lo up
+
+       $IP link add name veth1 type veth peer name veth2
+       $IP link set dev veth2 netns ns2
+       $IP address add 192.0.2.1/24 dev veth1
+       ip -netns ns2 address add 192.0.2.1/24 dev veth2
+       $IP link set dev veth1 up
+       ip -netns ns2 link set dev veth2 up
+
        $IP link set dev lo address 52:54:00:6a:c7:5e
-       $IP link set dummy0 address 52:54:00:6a:c7:5e
-       $IP link add dummy1 type dummy
-       $IP link set dummy1 address 52:54:00:6a:c7:5e
-       $IP link set dev dummy1 up
+       $IP link set dev veth1 address 52:54:00:6a:c7:5e
+       ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
+       ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
+
+       # 1. (ns2) redirect lo's egress to veth2's egress
+       ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
+       ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
+               action mirred egress redirect dev veth2
+       ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
+               action mirred egress redirect dev veth2
+
+       # 2. (ns1) redirect veth1's ingress to lo's ingress
+       $NS_EXEC tc qdisc add dev veth1 ingress
+       $NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
+               action mirred ingress redirect dev lo
+       $NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
+               action mirred ingress redirect dev lo
+
+       # 3. (ns1) redirect lo's egress to veth1's egress
+       $NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
+       $NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
+               action mirred egress redirect dev veth1
+       $NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
+               action mirred egress redirect dev veth1
+
+       # 4. (ns2) redirect veth2's ingress to lo's ingress
+       ip netns exec ns2 tc qdisc add dev veth2 ingress
+       ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
+               action mirred ingress redirect dev lo
+       ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
+               action mirred ingress redirect dev lo
+
        $NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
        $NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
        $NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
-
-       $NS_EXEC tc qd add dev dummy1 parent root handle 1: fq_codel
-       $NS_EXEC tc filter add dev dummy1 parent 1: protocol arp basic action mirred egress redirect dev lo
-       $NS_EXEC tc filter add dev dummy1 parent 1: protocol ip basic action mirred egress redirect dev lo
+       ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
+       ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
+       ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
        set +e
 
-       run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 198.51.100.1"
+       run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
        log_test $? 0 "rp_filter passes local packets"
 
-       run_cmd "ip netns exec ns1 ping -I dummy1 -w1 -c1 127.0.0.1"
+       run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
        log_test $? 0 "rp_filter passes loopback packets"
 
        cleanup
index bf17e48..b0980a2 100644 (file)
@@ -13,6 +13,8 @@ NETIFS[p5]=veth4
 NETIFS[p6]=veth5
 NETIFS[p7]=veth6
 NETIFS[p8]=veth7
+NETIFS[p9]=veth8
+NETIFS[p10]=veth9
 
 # Port that does not have a cable connected.
 NETIF_NO_CABLE=eth8
index ecbf57f..7b9d6e3 100755 (executable)
@@ -311,7 +311,7 @@ check_exception()
                ip -netns h1 ro get ${H1_VRF_ARG} ${H2_N2_IP} | \
                grep -E -v 'mtu|redirected' | grep -q "cache"
        fi
-       log_test $? 0 "IPv4: ${desc}"
+       log_test $? 0 "IPv4: ${desc}" 0
 
        # No PMTU info for test "redirect" and "mtu exception plus redirect"
        if [ "$with_redirect" = "yes" ] && [ "$desc" != "redirect exception plus mtu" ]; then
index 8a22db0..6e468e0 100644 (file)
@@ -31,6 +31,8 @@ struct tls_crypto_info_keys {
                struct tls12_crypto_info_chacha20_poly1305 chacha20;
                struct tls12_crypto_info_sm4_gcm sm4gcm;
                struct tls12_crypto_info_sm4_ccm sm4ccm;
+               struct tls12_crypto_info_aes_ccm_128 aesccm128;
+               struct tls12_crypto_info_aes_gcm_256 aesgcm256;
        };
        size_t len;
 };
@@ -61,6 +63,16 @@ static void tls_crypto_info_init(uint16_t tls_version, uint16_t cipher_type,
                tls12->sm4ccm.info.version = tls_version;
                tls12->sm4ccm.info.cipher_type = cipher_type;
                break;
+       case TLS_CIPHER_AES_CCM_128:
+               tls12->len = sizeof(struct tls12_crypto_info_aes_ccm_128);
+               tls12->aesccm128.info.version = tls_version;
+               tls12->aesccm128.info.cipher_type = cipher_type;
+               break;
+       case TLS_CIPHER_AES_GCM_256:
+               tls12->len = sizeof(struct tls12_crypto_info_aes_gcm_256);
+               tls12->aesgcm256.info.version = tls_version;
+               tls12->aesgcm256.info.cipher_type = cipher_type;
+               break;
        default:
                break;
        }
@@ -261,6 +273,30 @@ FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm)
        .cipher_type = TLS_CIPHER_SM4_CCM,
 };
 
+FIXTURE_VARIANT_ADD(tls, 12_aes_ccm)
+{
+       .tls_version = TLS_1_2_VERSION,
+       .cipher_type = TLS_CIPHER_AES_CCM_128,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_aes_ccm)
+{
+       .tls_version = TLS_1_3_VERSION,
+       .cipher_type = TLS_CIPHER_AES_CCM_128,
+};
+
+FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_256)
+{
+       .tls_version = TLS_1_2_VERSION,
+       .cipher_type = TLS_CIPHER_AES_GCM_256,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_256)
+{
+       .tls_version = TLS_1_3_VERSION,
+       .cipher_type = TLS_CIPHER_AES_GCM_256,
+};
+
 FIXTURE_SETUP(tls)
 {
        struct tls_crypto_info_keys tls12;
index 710ac95..c548934 100644 (file)
@@ -498,7 +498,7 @@ static void parse_opts(int argc, char **argv)
        bool have_toeplitz = false;
        int index, c;
 
-       while ((c = getopt_long(argc, argv, "46C:d:i:k:r:stT:u:v", long_options, &index)) != -1) {
+       while ((c = getopt_long(argc, argv, "46C:d:i:k:r:stT:uv", long_options, &index)) != -1) {
                switch (c) {
                case '4':
                        cfg_family = AF_INET;
index 91f3ef0..8b5ea92 100755 (executable)
@@ -150,11 +150,27 @@ EOF
 # oifname is the vrf device.
 test_masquerade_vrf()
 {
+       local qdisc=$1
+
+       if [ "$qdisc" != "default" ]; then
+               tc -net $ns0 qdisc add dev tvrf root $qdisc
+       fi
+
        ip netns exec $ns0 conntrack -F 2>/dev/null
 
 ip netns exec $ns0 nft -f - <<EOF
 flush ruleset
 table ip nat {
+       chain rawout {
+               type filter hook output priority raw;
+
+               oif tvrf ct state untracked counter
+       }
+       chain postrouting2 {
+               type filter hook postrouting priority mangle;
+
+               oif tvrf ct state untracked counter
+       }
        chain postrouting {
                type nat hook postrouting priority 0;
                # NB: masquerade should always be combined with 'oif(name) bla',
@@ -171,13 +187,18 @@ EOF
        fi
 
        # must also check that nat table was evaluated on second (lower device) iteration.
-       ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2'
+       ip netns exec $ns0 nft list table ip nat |grep -q 'counter packets 2' &&
+       ip netns exec $ns0 nft list table ip nat |grep -q 'untracked counter packets [1-9]'
        if [ $? -eq 0 ]; then
-               echo "PASS: iperf3 connect with masquerade + sport rewrite on vrf device"
+               echo "PASS: iperf3 connect with masquerade + sport rewrite on vrf device ($qdisc qdisc)"
        else
-               echo "FAIL: vrf masq rule has unexpected counter value"
+               echo "FAIL: vrf rules have unexpected counter value"
                ret=1
        fi
+
+       if [ "$qdisc" != "default" ]; then
+               tc -net $ns0 qdisc del dev tvrf root
+       fi
 }
 
 # add masq rule that gets evaluated w. outif set to veth device.
@@ -213,7 +234,8 @@ EOF
 }
 
 test_ct_zone_in
-test_masquerade_vrf
+test_masquerade_vrf "default"
+test_masquerade_vrf "pfifo"
 test_masquerade_veth
 
 exit $ret
index 5a4938d..ed61f6c 100755 (executable)
@@ -23,8 +23,8 @@ TESTS="reported_issues correctness concurrency timeout"
 
 # Set types, defined by TYPE_ variables below
 TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
-       net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port
-       net_port_mac_proto_net"
+       net_port_net net_mac mac_net net_mac_icmp net6_mac_icmp
+       net6_port_net6_port net_port_mac_proto_net"
 
 # Reported bugs, also described by TYPE_ variables below
 BUGS="flush_remove_add"
@@ -277,6 +277,23 @@ perf_entries       1000
 perf_proto     ipv4
 "
 
+TYPE_mac_net="
+display                mac,net
+type_spec      ether_addr . ipv4_addr
+chain_spec     ether saddr . ip saddr
+dst             
+src            mac addr4
+start          1
+count          5
+src_delta      2000
+tools          sendip nc bash
+proto          udp
+
+race_repeat    0
+
+perf_duration  0
+"
+
 TYPE_net_mac_icmp="
 display                net,mac - ICMP
 type_spec      ipv4_addr . ether_addr
@@ -984,7 +1001,8 @@ format() {
                fi
        done
        for f in ${src}; do
-               __expr="${__expr} . "
+               [ "${__expr}" != "{ " ] && __expr="${__expr} . "
+
                __start="$(eval format_"${f}" "${srcstart}")"
                __end="$(eval format_"${f}" "${srcend}")"
 
index ac64637..0463311 100755 (executable)
@@ -18,11 +18,17 @@ cleanup()
        ip netns del $ns
 }
 
-ip netns add $ns
-if [ $? -ne 0 ];then
-       echo "SKIP: Could not create net namespace $gw"
-       exit $ksft_skip
-fi
+checktool (){
+       if ! $1 > /dev/null 2>&1; then
+               echo "SKIP: Could not $2"
+               exit $ksft_skip
+       fi
+}
+
+checktool "nft --version" "run test without nft tool"
+checktool "ip -Version" "run test without ip tool"
+checktool "socat -V" "run test without socat tool"
+checktool "ip netns add $ns" "create net namespace"
 
 trap cleanup EXIT
 
@@ -71,7 +77,8 @@ EOF
                local start=$(date +%s%3N)
                i=$((i + 10000))
                j=$((j + 1))
-               dd if=/dev/zero of=/dev/stdout bs=8k count=10000 2>/dev/null | ip netns exec "$ns" nc -w 1 -q 1 -u -p 12345 127.0.0.1 12345 > /dev/null
+               # nft rule in output places each packet in a different zone.
+               dd if=/dev/zero of=/dev/stdout bs=8k count=10000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
                if [ $? -ne 0 ] ;then
                        ret=1
                        break
index b71828d..a3239d5 100644 (file)
@@ -60,6 +60,8 @@ CONFIG_NET_IFE_SKBTCINDEX=m
 CONFIG_NET_SCH_FIFO=y
 CONFIG_NET_SCH_ETS=m
 CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_FQ_PIE=m
+CONFIG_NETDEVSIM=m
 
 #
 ## Network testing
index a3e4318..ee22e34 100755 (executable)
@@ -716,6 +716,7 @@ def set_operation_mode(pm, parser, args, remaining):
         list_test_cases(alltests)
         exit(0)
 
+    exit_code = 0 # KSFT_PASS
     if len(alltests):
         req_plugins = pm.get_required_plugins(alltests)
         try:
@@ -724,6 +725,8 @@ def set_operation_mode(pm, parser, args, remaining):
             print('The following plugins were not found:')
             print('{}'.format(pde.missing_pg))
         catresults = test_runner(pm, args, alltests)
+        if catresults.count_failures() != 0:
+            exit_code = 1 # KSFT_FAIL
         if args.format == 'none':
             print('Test results output suppression requested\n')
         else:
@@ -748,6 +751,8 @@ def set_operation_mode(pm, parser, args, remaining):
                         gid=int(os.getenv('SUDO_GID')))
     else:
         print('No tests found\n')
+        exit_code = 4 # KSFT_SKIP
+    exit(exit_code)
 
 def main():
     """
@@ -767,8 +772,5 @@ def main():
 
     set_operation_mode(pm, parser, args, remaining)
 
-    exit(0)
-
-
 if __name__ == "__main__":
     main()
index 7fe38c7..afb0cd8 100755 (executable)
@@ -1,5 +1,6 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-2.0
 
+modprobe netdevsim
 ./tdc.py -c actions --nobuildebpf
 ./tdc.py -c qdisc