summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMaxime Ripard <mripard@kernel.org>2026-04-23 14:43:06 +0200
committerMaxime Ripard <mripard@kernel.org>2026-04-23 14:43:06 +0200
commitd13e855ee923c2ae78307bf6c354305f1406b9e2 (patch)
tree07313514d19864c9e269993220dbcc5070df4504 /drivers
parent0b13173d27fa15679463b62a10cfa8b3d6c3a71c (diff)
parent028ef9c96e96197026887c0f092424679298aae8 (diff)
Merge drm/drm-fixes into drm-misc-fixes
Tomi needs 7.0 to apply a patch from drm-misc-fixes. Signed-off-by: Maxime Ripard <mripard@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig1
-rw-r--r--drivers/acpi/acpi_platform.c2
-rw-r--r--drivers/acpi/acpi_processor.c15
-rw-r--r--drivers/acpi/acpi_video.c45
-rw-r--r--drivers/acpi/acpica/acpredef.h7
-rw-r--r--drivers/acpi/bus.c3
-rw-r--r--drivers/acpi/device_pm.c9
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/acpi/osi.c13
-rw-r--r--drivers/acpi/osl.c2
-rw-r--r--drivers/acpi/riscv/rimt.c7
-rw-r--r--drivers/acpi/scan.c45
-rw-r--r--drivers/acpi/sleep.c8
-rw-r--r--drivers/android/binder/page_range.rs86
-rw-r--r--drivers/android/binder/process.rs3
-rw-r--r--drivers/android/binder/range_alloc/array.rs35
-rw-r--r--drivers/android/binder/range_alloc/mod.rs4
-rw-r--r--drivers/android/binder/range_alloc/tree.rs18
-rw-r--r--drivers/android/binder/rust_binder_main.rs2
-rw-r--r--drivers/android/binder/thread.rs17
-rw-r--r--drivers/ata/ahci.c14
-rw-r--r--drivers/ata/libata-core.c13
-rw-r--r--drivers/ata/libata-eh.c23
-rw-r--r--drivers/ata/libata-scsi.c3
-rw-r--r--drivers/auxdisplay/lcd2s.c15
-rw-r--r--drivers/auxdisplay/line-display.c2
-rw-r--r--drivers/base/base.h11
-rw-r--r--drivers/base/bus.c43
-rw-r--r--drivers/base/class.c4
-rw-r--r--drivers/base/core.c9
-rw-r--r--drivers/base/dd.c62
-rw-r--r--drivers/base/platform.c37
-rw-r--r--drivers/base/power/runtime.c1
-rw-r--r--drivers/base/property.c27
-rw-r--r--drivers/base/regmap/regmap.c30
-rw-r--r--drivers/block/drbd/drbd_actlog.c53
-rw-r--r--drivers/block/drbd/drbd_interval.h5
-rw-r--r--drivers/block/drbd/drbd_main.c14
-rw-r--r--drivers/block/drbd/drbd_receiver.c4
-rw-r--r--drivers/block/drbd/drbd_req.c3
-rw-r--r--drivers/block/ublk_drv.c16
-rw-r--r--drivers/block/zloop.c31
-rw-r--r--drivers/block/zram/zram_drv.c59
-rw-r--r--drivers/block/zram/zram_drv.h2
-rw-r--r--drivers/bluetooth/btintel.c11
-rw-r--r--drivers/bluetooth/btqca.c2
-rw-r--r--drivers/bluetooth/btusb.c5
-rw-r--r--drivers/bluetooth/hci_h4.c3
-rw-r--r--drivers/bluetooth/hci_ll.c2
-rw-r--r--drivers/bluetooth/hci_qca.c24
-rw-r--r--drivers/bus/simple-pm-bus.c4
-rw-r--r--drivers/cache/ax45mp_cache.c4
-rw-r--r--drivers/cache/starfive_starlink_cache.c4
-rw-r--r--drivers/char/ipmi/ipmi_ipmb.c5
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c141
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c37
-rw-r--r--drivers/char/ipmi/ipmi_si_ls2k.c2
-rw-r--r--drivers/char/random.c12
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c24
-rw-r--r--drivers/clk/imx/clk-scu.c15
-rw-r--r--drivers/clk/imx/clk-scu.h2
-rw-r--r--drivers/comedi/comedi_fops.c8
-rw-r--r--drivers/comedi/drivers.c8
-rw-r--r--drivers/comedi/drivers/dt2815.c12
-rw-r--r--drivers/comedi/drivers/me4000.c16
-rw-r--r--drivers/comedi/drivers/me_daq.c35
-rw-r--r--drivers/comedi/drivers/ni_atmio16d.c3
-rw-r--r--drivers/counter/rz-mtu3-cnt.c67
-rw-r--r--drivers/cpufreq/cpufreq.c9
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c12
-rw-r--r--drivers/cpufreq/cpufreq_governor.c9
-rw-r--r--drivers/cpufreq/cpufreq_governor.h1
-rw-r--r--drivers/cpufreq/freq_table.c4
-rw-r--r--drivers/cpufreq/intel_pstate.c14
-rw-r--r--drivers/cpuidle/cpuidle.c10
-rw-r--r--drivers/crypto/atmel-sha204a.c5
-rw-r--r--drivers/crypto/caam/caamalg_qi2.c3
-rw-r--r--drivers/crypto/caam/caamhash.c3
-rw-r--r--drivers/crypto/ccp/sev-dev-tsm.c2
-rw-r--r--drivers/crypto/ccp/sev-dev.c14
-rw-r--r--drivers/crypto/padlock-sha.c7
-rw-r--r--drivers/crypto/tegra/tegra-se-aes.c11
-rw-r--r--drivers/crypto/tegra/tegra-se-hash.c30
-rw-r--r--drivers/cxl/Kconfig1
-rw-r--r--drivers/cxl/core/core.h18
-rw-r--r--drivers/cxl/core/hdm.c27
-rw-r--r--drivers/cxl/core/mbox.c13
-rw-r--r--drivers/cxl/core/memdev.c13
-rw-r--r--drivers/cxl/core/pmem.c42
-rw-r--r--drivers/cxl/core/port.c60
-rw-r--r--drivers/cxl/core/region.c8
-rw-r--r--drivers/cxl/cxl.h7
-rw-r--r--drivers/cxl/pmem.c24
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.c8
-rw-r--r--drivers/dma/dw-edma/dw-hdma-v0-core.c6
-rw-r--r--drivers/dma/fsl-edma-main.c26
-rw-r--r--drivers/dma/idxd/cdev.c8
-rw-r--r--drivers/dma/idxd/device.c45
-rw-r--r--drivers/dma/idxd/dma.c18
-rw-r--r--drivers/dma/idxd/idxd.h1
-rw-r--r--drivers/dma/idxd/init.c14
-rw-r--r--drivers/dma/idxd/irq.c16
-rw-r--r--drivers/dma/idxd/submit.c2
-rw-r--r--drivers/dma/idxd/sysfs.c1
-rw-r--r--drivers/dma/sh/rz-dmac.c66
-rw-r--r--drivers/dma/xilinx/xdma.c4
-rw-r--r--drivers/dma/xilinx/xilinx_dma.c46
-rw-r--r--drivers/dpll/zl3073x/core.c7
-rw-r--r--drivers/dpll/zl3073x/core.h28
-rw-r--r--drivers/dpll/zl3073x/dpll.c7
-rw-r--r--drivers/dpll/zl3073x/ref.c25
-rw-r--r--drivers/dpll/zl3073x/regs.h1
-rw-r--r--drivers/edac/edac_mc.c6
-rw-r--r--drivers/firewire/net.c5
-rw-r--r--drivers/firewire/ohci.c2
-rw-r--r--drivers/firmware/arm_ffa/driver.c8
-rw-r--r--drivers/firmware/arm_scmi/notify.c4
-rw-r--r--drivers/firmware/arm_scmi/protocols.h4
-rw-r--r--drivers/firmware/arm_scpi.c5
-rw-r--r--drivers/firmware/cirrus/cs_dsp.c24
-rw-r--r--drivers/firmware/efi/efi-init.c2
-rw-r--r--drivers/firmware/efi/mokvar-table.c2
-rw-r--r--drivers/firmware/microchip/mpfs-auto-update.c10
-rw-r--r--drivers/firmware/stratix10-rsu.c2
-rw-r--r--drivers/firmware/stratix10-svc.c228
-rw-r--r--drivers/firmware/thead,th1520-aon.c7
-rw-r--r--drivers/gpib/Kconfig1
-rw-r--r--drivers/gpib/common/gpib_os.c96
-rw-r--r--drivers/gpib/include/gpib_types.h8
-rw-r--r--drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c11
-rw-r--r--drivers/gpio/gpio-bd72720.c2
-rw-r--r--drivers/gpio/gpio-mxc.c10
-rw-r--r--drivers/gpio/gpio-qixis-fpga.c4
-rw-r--r--drivers/gpio/gpio-tegra.c4
-rw-r--r--drivers/gpio/gpiolib-shared.c63
-rw-r--r--drivers/gpio/gpiolib-shared.h11
-rw-r--r--drivers/gpio/gpiolib.c121
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c44
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c44
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c48
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c123
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c64
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_userqueue.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v11_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v12_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v11_0.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v15_0.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc21.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c6
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c23
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_queue.c11
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c16
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c9
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c16
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c23
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c41
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c42
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c41
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c34
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c42
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c42
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c41
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c41
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c40
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c40
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c40
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c40
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c46
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c43
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c43
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c43
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c43
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h18
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c44
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c21
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c39
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c36
-rw-r--r--drivers/gpu/drm/drm_pagemap.c14
-rw-r--r--drivers/gpu/drm/i915/display/g4x_dp.c2
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_alpm.c13
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c54
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c9
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_well.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.c20
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.h11
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c102
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.c23
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.h3
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc_regs.h12
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.c14
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shmem.c12
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_cs.c3
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c26
-rw-r--r--drivers/gpu/drm/i915/i915_wait_util.h2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c9
-rw-r--r--drivers/gpu/drm/msm/adreno/a2xx_gpummu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_catalog.c3
-rw-r--r--drivers/gpu/drm/msm/adreno/a8xx_gpu.c14
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c1
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h4
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c2
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c4
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c52
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c43
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c22
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c4
-rw-r--r--drivers/gpu/drm/xe/regs/xe_engine_regs.h6
-rw-r--r--drivers/gpu/drm/xe/regs/xe_gt_regs.h1
-rw-r--r--drivers/gpu/drm/xe/xe_configfs.c1
-rw-r--r--drivers/gpu/drm/xe/xe_device.c27
-rw-r--r--drivers/gpu/drm/xe/xe_exec_queue.c23
-rw-r--r--drivers/gpu/drm/xe/xe_ggtt.c10
-rw-r--r--drivers/gpu/drm/xe/xe_ggtt_types.h5
-rw-r--r--drivers/gpu/drm/xe/xe_gsc_proxy.c43
-rw-r--r--drivers/gpu/drm/xe/xe_gsc_types.h2
-rw-r--r--drivers/gpu/drm/xe/xe_gt.c66
-rw-r--r--drivers/gpu/drm/xe/xe_gt_ccs_mode.c2
-rw-r--r--drivers/gpu/drm/xe/xe_guc.c32
-rw-r--r--drivers/gpu/drm/xe/xe_guc.h1
-rw-r--r--drivers/gpu/drm/xe/xe_guc_ct.c1
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c86
-rw-r--r--drivers/gpu/drm/xe/xe_hw_engine.c3
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.c4
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.h3
-rw-r--r--drivers/gpu/drm/xe/xe_oa.c7
-rw-r--r--drivers/gpu/drm/xe/xe_pagefault.c6
-rw-r--r--drivers/gpu/drm/xe/xe_pt.c50
-rw-r--r--drivers/gpu/drm/xe/xe_pxp.c23
-rw-r--r--drivers/gpu/drm/xe/xe_reg_sr.c4
-rw-r--r--drivers/gpu/drm/xe/xe_ring_ops.c9
-rw-r--r--drivers/gpu/drm/xe/xe_sriov_packet.c2
-rw-r--r--drivers/gpu/drm/xe/xe_svm.c2
-rw-r--r--drivers/gpu/drm/xe/xe_sync.c30
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c22
-rw-r--r--drivers/gpu/drm/xe/xe_vm_madvise.c19
-rw-r--r--drivers/gpu/drm/xe/xe_vm_types.h4
-rw-r--r--drivers/gpu/drm/xe/xe_wa.c14
-rw-r--r--drivers/gpu/nova-core/gsp.rs46
-rw-r--r--drivers/gpu/nova-core/gsp/boot.rs2
-rw-r--r--drivers/gpu/nova-core/gsp/cmdq.rs93
-rw-r--r--drivers/gpu/nova-core/gsp/fw.rs101
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.c3
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.c2
-rw-r--r--drivers/hid/hid-apple.c7
-rw-r--r--drivers/hid/hid-appletb-kbd.c5
-rw-r--r--drivers/hid/hid-asus.c21
-rw-r--r--drivers/hid/hid-cmedia.c2
-rw-r--r--drivers/hid/hid-core.c7
-rw-r--r--drivers/hid/hid-creative-sb0540.c2
-rw-r--r--drivers/hid/hid-debug.c6
-rw-r--r--drivers/hid/hid-ids.h11
-rw-r--r--drivers/hid/hid-input.c21
-rw-r--r--drivers/hid/hid-kysona.c2
-rw-r--r--drivers/hid/hid-logitech-hidpp.c6
-rw-r--r--drivers/hid/hid-magicmouse.c6
-rw-r--r--drivers/hid/hid-mcp2221.c2
-rw-r--r--drivers/hid/hid-multitouch.c50
-rw-r--r--drivers/hid/hid-quirks.c1
-rw-r--r--drivers/hid/hid-roccat.c2
-rw-r--r--drivers/hid/hid-zydacron.c2
-rw-r--r--drivers/hid/intel-ish-hid/ipc/hw-ish.h2
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c12
-rw-r--r--drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c7
-rw-r--r--drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h4
-rw-r--r--drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c1
-rw-r--r--drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c6
-rw-r--r--drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h2
-rw-r--r--drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c1
-rw-r--r--drivers/hid/usbhid/hid-pidff.c11
-rw-r--r--drivers/hid/wacom_wac.c10
-rw-r--r--drivers/hv/mshv_regions.c6
-rw-r--r--drivers/hv/mshv_root.h5
-rw-r--r--drivers/hv/mshv_root_main.c108
-rw-r--r--drivers/hv/mshv_synic.c188
-rw-r--r--drivers/hwmon/Kconfig16
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/adm1177.c54
-rw-r--r--drivers/hwmon/aht10.c6
-rw-r--r--drivers/hwmon/asus-ec-sensors.c7
-rw-r--r--drivers/hwmon/axi-fan-control.c2
-rw-r--r--drivers/hwmon/it87.c5
-rw-r--r--drivers/hwmon/macsmc-hwmon.c53
-rw-r--r--drivers/hwmon/max6639.c12
-rw-r--r--drivers/hwmon/occ/common.c19
-rw-r--r--drivers/hwmon/peci/cputemp.c4
-rw-r--r--drivers/hwmon/pmbus/hac300s.c2
-rw-r--r--drivers/hwmon/pmbus/ina233.c5
-rw-r--r--drivers/hwmon/pmbus/isl68137.c28
-rw-r--r--drivers/hwmon/pmbus/ltc4286.c1
-rw-r--r--drivers/hwmon/pmbus/mp2869.c35
-rw-r--r--drivers/hwmon/pmbus/mp2975.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c192
-rw-r--r--drivers/hwmon/pmbus/pxe1610.c5
-rw-r--r--drivers/hwmon/pmbus/q54sj108a2.c19
-rw-r--r--drivers/hwmon/pmbus/tps53679.c10
-rw-r--r--drivers/hwmon/sa67mcu-hwmon.c161
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-cp2615.c3
-rw-r--r--drivers/i2c/busses/i2c-designware-amdisp.c11
-rw-r--r--drivers/i2c/busses/i2c-fsi.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c14
-rw-r--r--drivers/i2c/busses/i2c-imx.c53
-rw-r--r--drivers/i2c/busses/i2c-pxa.c17
-rw-r--r--drivers/i2c/busses/i2c-tegra.c5
-rw-r--r--drivers/i3c/Kconfig12
-rw-r--r--drivers/i3c/master/dw-i3c-master.c6
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/cmd.h1
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/cmd_v1.c8
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/cmd_v2.c8
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/core.c143
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/dma.c158
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/hci.h5
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/pio.c16
-rw-r--r--drivers/iio/accel/adxl313_core.c2
-rw-r--r--drivers/iio/accel/adxl355_core.c2
-rw-r--r--drivers/iio/accel/adxl380.c2
-rw-r--r--drivers/iio/adc/ad4062.c8
-rw-r--r--drivers/iio/adc/ad7768-1.c13
-rw-r--r--drivers/iio/adc/ade9000.c12
-rw-r--r--drivers/iio/adc/aspeed_adc.c1
-rw-r--r--drivers/iio/adc/nxp-sar-adc.c9
-rw-r--r--drivers/iio/adc/ti-adc161s626.c41
-rw-r--r--drivers/iio/adc/ti-ads1018.c2
-rw-r--r--drivers/iio/adc/ti-ads1119.c11
-rw-r--r--drivers/iio/adc/ti-ads7950.c8
-rw-r--r--drivers/iio/chemical/bme680_core.c2
-rw-r--r--drivers/iio/chemical/sps30_i2c.c2
-rw-r--r--drivers/iio/chemical/sps30_serial.c2
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c48
-rw-r--r--drivers/iio/dac/ad5770r.c2
-rw-r--r--drivers/iio/dac/ds4424.c2
-rw-r--r--drivers/iio/dac/mcp47feb02.c51
-rw-r--r--drivers/iio/frequency/adf4377.c2
-rw-r--r--drivers/iio/gyro/mpu3050-core.c50
-rw-r--r--drivers/iio/gyro/mpu3050-i2c.c3
-rw-r--r--drivers/iio/imu/adis.c2
-rw-r--r--drivers/iio/imu/adis16550.c8
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c15
-rw-r--r--drivers/iio/imu/bno055/bno055.c2
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c2
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c4
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c2
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600.h2
-rw-r--r--drivers/iio/imu/inv_icm45600/inv_icm45600_core.c11
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c8
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c5
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c15
-rw-r--r--drivers/iio/industrialio-buffer.c6
-rw-r--r--drivers/iio/light/bh1780.c2
-rw-r--r--drivers/iio/light/vcnl4035.c18
-rw-r--r--drivers/iio/light/veml6070.c4
-rw-r--r--drivers/iio/magnetometer/Kconfig3
-rw-r--r--drivers/iio/magnetometer/tlv493d.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c24
-rw-r--r--drivers/iio/potentiometer/mcp4131.c2
-rw-r--r--drivers/iio/pressure/abp2030pa.c2
-rw-r--r--drivers/iio/proximity/hx9023s.c6
-rw-r--r--drivers/iio/proximity/rfd77402.c7
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/core/cache.c13
-rw-r--r--drivers/infiniband/core/cma.c6
-rw-r--r--drivers/infiniband/core/core_priv.h3
-rw-r--r--drivers/infiniband/core/device.c39
-rw-r--r--drivers/infiniband/core/rw.c37
-rw-r--r--drivers/infiniband/core/umem.c5
-rw-r--r--drivers/infiniband/core/umem_dmabuf.c4
-rw-r--r--drivers/infiniband/core/uverbs_std_types_dmabuf.c2
-rw-r--r--drivers/infiniband/hw/bng_re/bng_dev.c66
-rw-r--r--drivers/infiniband/hw/efa/efa_com.c88
-rw-r--r--drivers/infiniband/hw/efa/efa_verbs.c2
-rw-r--r--drivers/infiniband/hw/ionic/ionic_controlpath.c6
-rw-r--r--drivers/infiniband/hw/ionic/ionic_ibdev.c2
-rw-r--r--drivers/infiniband/hw/irdma/cm.c29
-rw-r--r--drivers/infiniband/hw/irdma/uk.c39
-rw-r--r--drivers/infiniband/hw/irdma/utils.c2
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c12
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c5
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c7
-rw-r--r--drivers/input/joystick/xpad.c5
-rw-r--r--drivers/input/misc/uinput.c35
-rw-r--r--drivers/input/mouse/bcm5974.c42
-rw-r--r--drivers/input/rmi4/rmi_f54.c4
-rw-r--r--drivers/input/serio/i8042-acpipnpio.h7
-rw-r--r--drivers/interconnect/qcom/sm8450.c4
-rw-r--r--drivers/iommu/amd/iommu.c15
-rw-r--r--drivers/iommu/dma-iommu.c21
-rw-r--r--drivers/iommu/generic_pt/fmt/amdv1.h2
-rw-r--r--drivers/iommu/generic_pt/iommu_pt.h2
-rw-r--r--drivers/iommu/intel/dmar.c3
-rw-r--r--drivers/iommu/intel/svm.c12
-rw-r--r--drivers/iommu/iommu-sva.c12
-rw-r--r--drivers/iommu/iommu.c12
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c4
-rw-r--r--drivers/irqchip/irq-gic-v5-irs.c2
-rw-r--r--drivers/irqchip/irq-ls-extirq.c53
-rw-r--r--drivers/irqchip/irq-mmp.c2
-rw-r--r--drivers/irqchip/irq-qcom-mpm.c3
-rw-r--r--drivers/irqchip/irq-renesas-rzv2h.c2
-rw-r--r--drivers/irqchip/irq-riscv-aplic-main.c25
-rw-r--r--drivers/irqchip/irq-riscv-rpmi-sysmsi.c1
-rw-r--r--drivers/irqchip/irq-sifive-plic.c7
-rw-r--r--drivers/media/dvb-core/dmxdev.c4
-rw-r--r--drivers/media/dvb-core/dvb_net.c3
-rw-r--r--drivers/media/i2c/ccs/ccs-core.c2
-rw-r--r--drivers/media/mc/mc-request.c5
-rw-r--r--drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c4
-rw-r--r--drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c50
-rw-r--r--drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c3
-rw-r--r--drivers/media/platform/synopsys/Kconfig1
-rw-r--r--drivers/media/platform/synopsys/dw-mipi-csi2rx.c2
-rw-r--r--drivers/media/platform/verisilicon/imx8m_vpu_hw.c2
-rw-r--r--drivers/media/usb/uvc/uvc_video.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c5
-rw-r--r--drivers/misc/amd-sbi/Kconfig3
-rw-r--r--drivers/misc/fastrpc.c5
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d.c6
-rw-r--r--drivers/misc/mei/Kconfig1
-rw-r--r--drivers/misc/mei/hw-me.c14
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c38
-rw-r--r--drivers/mmc/host/mmci_qcom_dml.c1
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c2
-rw-r--r--drivers/mmc/host/sdhci-pci-gli.c9
-rw-r--r--drivers/mmc/host/sdhci.c9
-rw-r--r--drivers/mmc/host/vub300.c19
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c6
-rw-r--r--drivers/mtd/nand/raw/cadence-nand-controller.c2
-rw-r--r--drivers/mtd/nand/raw/nand_base.c14
-rw-r--r--drivers/mtd/nand/raw/pl35x-nand-controller.c3
-rw-r--r--drivers/mtd/parsers/redboot.c6
-rw-r--r--drivers/mtd/spi-nor/core.c14
-rw-r--r--drivers/net/bonding/bond_debugfs.c16
-rw-r--r--drivers/net/bonding/bond_main.c83
-rw-r--r--drivers/net/bonding/bond_options.c2
-rw-r--r--drivers/net/bonding/bond_sysfs.c4
-rw-r--r--drivers/net/caif/caif_serial.c3
-rw-r--r--drivers/net/can/dev/calc_bittiming.c2
-rw-r--r--drivers/net/can/dev/netlink.c4
-rw-r--r--drivers/net/can/dummy_can.c1
-rw-r--r--drivers/net/can/spi/hi311x.c5
-rw-r--r--drivers/net/can/spi/mcp251x.c44
-rw-r--r--drivers/net/can/usb/ems_usb.c7
-rw-r--r--drivers/net/can/usb/esd_usb.c30
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.c8
-rw-r--r--drivers/net/can/usb/f81604.c45
-rw-r--r--drivers/net/can/usb/gs_usb.c22
-rw-r--r--drivers/net/can/usb/ucan.c2
-rw-r--r--drivers/net/dsa/bcm_sf2.c8
-rw-r--r--drivers/net/dsa/microchip/ksz_ptp.c11
-rw-r--r--drivers/net/dsa/mxl862xx/mxl862xx.c1
-rw-r--r--drivers/net/dsa/realtek/rtl8365mb.c5
-rw-r--r--drivers/net/dsa/realtek/rtl8366rb-leds.c6
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c16
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c24
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.h1
-rw-r--r--drivers/net/ethernet/airoha/airoha_ppe.c9
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c1
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-common.h2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c29
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c1
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c82
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h7
-rw-r--r--drivers/net/ethernet/arc/emac_main.c11
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig2
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp.c41
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c91
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c9
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c5
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c31
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h5
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c10
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c13
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c165
-rw-r--r--drivers/net/ethernet/cadence/macb_pci.c10
-rw-r--r--drivers/net/ethernet/cadence/macb_ptp.c4
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c28
-rw-r--r--drivers/net/ethernet/freescale/Kconfig2
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c10
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c15
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc4_hw.h11
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc4_pf.c118
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ethtool.c12
-rw-r--r--drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c24
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c3
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx_dqo.c56
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c8
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h1
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h4
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c31
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c17
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c41
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_trace.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c14
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h3
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c50
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c107
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c1
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/devlink.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h23
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c38
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c83
-rw-r--r--drivers/net/ethernet/intel/ice/ice_idc.c44
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c11
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c30
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.c5
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.c3
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf.h2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_ethtool.c3
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_idc.c6
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c1
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c16
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c22
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.h5
-rw-r--r--drivers/net/ethernet/intel/idpf/xdp.c6
-rw-r--r--drivers/net/ethernet/intel/idpf/xsk.c1
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c3
-rw-r--r--drivers/net/ethernet/intel/igb/igb_xsk.c38
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c48
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c36
-rw-r--r--drivers/net/ethernet/intel/ixgbe/devlink/devlink.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c13
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c10
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c10
-rw-r--r--drivers/net/ethernet/intel/libeth/xsk.c1
-rw-r--r--drivers/net/ethernet/intel/libie/fwlog.c53
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c4
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_main.c40
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_rx.c27
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c38
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c28
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c6
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c15
-rw-r--r--drivers/net/ethernet/mediatek/mtk_ppe_offload.c21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c49
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw.c53
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sriov.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c4
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c2
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_txrx.c6
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_txrx.h2
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.c5
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c28
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c6
-rw-r--r--drivers/net/ethernet/microsoft/mana/hw_channel.c6
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c40
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.c17
-rw-r--r--drivers/net/ethernet/qualcomm/qca_uart.c2
-rw-r--r--drivers/net/ethernet/spacemit/k1_emac.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c48
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c60
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c18
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.h2
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c9
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_common.c11
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_prueth.c8
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_type.h8
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h4
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c9
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c5
-rw-r--r--drivers/net/ethernet/xscale/ptp_ixp46x.c3
-rw-r--r--drivers/net/ipa/reg/gsi_reg-v5.0.c9
-rw-r--r--drivers/net/ipvlan/ipvtap.c5
-rw-r--r--drivers/net/macvtap.c5
-rw-r--r--drivers/net/mctp/mctp-i2c.c1
-rw-r--r--drivers/net/mctp/mctp-usb.c3
-rw-r--r--drivers/net/mdio/mdio-realtek-rtl9300.c3
-rw-r--r--drivers/net/netconsole.c5
-rw-r--r--drivers/net/netdevsim/netdev.c5
-rw-r--r--drivers/net/ovpn/tcp.c53
-rw-r--r--drivers/net/phy/phy_device.c25
-rw-r--r--drivers/net/phy/qcom/qca807x.c2
-rw-r--r--drivers/net/phy/sfp.c29
-rw-r--r--drivers/net/team/team_core.c91
-rw-r--r--drivers/net/tun_vnet.h2
-rw-r--r--drivers/net/usb/aqc111.c12
-rw-r--r--drivers/net/usb/cdc_ncm.c10
-rw-r--r--drivers/net/usb/kalmia.c7
-rw-r--r--drivers/net/usb/kaweth.c15
-rw-r--r--drivers/net/usb/lan78xx.c14
-rw-r--r--drivers/net/usb/lan78xx.h3
-rw-r--r--drivers/net/usb/pegasus.c48
-rw-r--r--drivers/net/usb/qmi_wwan.c4
-rw-r--r--drivers/net/usb/r8152.c1
-rw-r--r--drivers/net/usb/usbnet.c7
-rw-r--r--drivers/net/virtio_net.c27
-rw-r--r--drivers/net/vxlan/vxlan_core.c11
-rw-r--r--drivers/net/wan/farsync.c2
-rw-r--r--drivers/net/wan/lapbether.c13
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c15
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c7
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/commands.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/scan.h10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/iface.c101
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mac80211.c19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.c1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mlo.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/notif.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/scan.c30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/scan.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c3
-rw-r--r--drivers/net/wireless/marvell/libertas/main.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mac.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/scan.c4
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00usb.c2
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c2
-rw-r--r--drivers/net/wireless/st/cw1200/pm.c2
-rw-r--r--drivers/net/wireless/ti/wl1251/tx.c8
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c2
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c3
-rw-r--r--drivers/net/wireless/virtual/virt_wifi.c1
-rw-r--r--drivers/net/xen-netfront.c34
-rw-r--r--drivers/nfc/nxp-nci/i2c.c4
-rw-r--r--drivers/nfc/pn533/uart.c14
-rw-r--r--drivers/nfc/pn533/usb.c1
-rw-r--r--drivers/nfc/s3fwrn5/uart.c10
-rw-r--r--drivers/nvdimm/bus.c5
-rw-r--r--drivers/nvme/host/core.c31
-rw-r--r--drivers/nvme/host/fabrics.c4
-rw-r--r--drivers/nvme/host/multipath.c14
-rw-r--r--drivers/nvme/host/nvme.h57
-rw-r--r--drivers/nvme/host/pci.c194
-rw-r--r--drivers/nvme/host/pr.c4
-rw-r--r--drivers/nvme/host/sysfs.c23
-rw-r--r--drivers/nvme/host/tcp.c5
-rw-r--r--drivers/nvme/target/admin-cmd.c2
-rw-r--r--drivers/nvme/target/core.c14
-rw-r--r--drivers/nvme/target/fcloop.c15
-rw-r--r--drivers/nvme/target/nvmet.h1
-rw-r--r--drivers/nvme/target/rdma.c1
-rw-r--r--drivers/nvmem/imx-ocotp-ele.c1
-rw-r--r--drivers/nvmem/imx-ocotp.c1
-rw-r--r--drivers/nvmem/zynqmp_nvmem.c8
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-ep.c25
-rw-r--r--drivers/pci/controller/pci-hyperv.c12
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-test.c5
-rw-r--r--drivers/pci/pwrctrl/core.c56
-rw-r--r--drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c12
-rw-r--r--drivers/pci/pwrctrl/slot.c1
-rw-r--r--drivers/pci/xen-pcifront.c8
-rw-r--r--drivers/phy/Kconfig5
-rw-r--r--drivers/phy/freescale/phy-fsl-lynx-28g.c2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-ufs.c3
-rw-r--r--drivers/phy/spacemit/phy-k1-usb2.c14
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c2
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs42l43.c5
-rw-r--r--drivers/pinctrl/cix/pinctrl-sky1.c3
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c36
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.h1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c9
-rw-r--r--drivers/pinctrl/meson/pinctrl-amlogic-a4.c3
-rw-r--r--drivers/pinctrl/pinconf-generic.c4
-rw-r--r--drivers/pinctrl/pinctrl-amdisp.c2
-rw-r--r--drivers/pinctrl/pinctrl-cy8c95x0.c4
-rw-r--r--drivers/pinctrl/pinctrl-equilibrium.c31
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c9
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c12
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcs615.c1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c16
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza1.c2
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzt2h.c15
-rw-r--r--drivers/pinctrl/stm32/Kconfig1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c92
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.h4
-rw-r--r--drivers/platform/olpc/olpc-xo175-ec.c2
-rw-r--r--drivers/platform/x86/amd/hsmp/hsmp.c2
-rw-r--r--drivers/platform/x86/amd/pmc/pmc-quirks.c9
-rw-r--r--drivers/platform/x86/asus-armoury.h238
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c2
-rw-r--r--drivers/platform/x86/dell/alienware-wmi-wmax.c2
-rw-r--r--drivers/platform/x86/dell/dell-wmi-base.c6
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c1
-rw-r--r--drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c9
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c31
-rw-r--r--drivers/platform/x86/intel/hid.c29
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c7
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c9
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c10
-rw-r--r--drivers/platform/x86/lenovo/thinkpad_acpi.c6
-rw-r--r--drivers/platform/x86/lenovo/wmi-gamezone.c2
-rw-r--r--drivers/platform/x86/oxpec.c30
-rw-r--r--drivers/platform/x86/redmi-wmi.c25
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c18
-rw-r--r--drivers/platform/x86/uniwill/uniwill-acpi.c110
-rw-r--r--drivers/platform/x86/uniwill/uniwill-wmi.h6
-rw-r--r--drivers/pmdomain/bcm/bcm2835-power.c18
-rw-r--r--drivers/pmdomain/imx/gpcv2.c4
-rw-r--r--drivers/pmdomain/imx/imx8mp-blk-ctrl.c8
-rw-r--r--drivers/pmdomain/mediatek/mtk-pm-domains.c2
-rw-r--r--drivers/pmdomain/rockchip/pm-domains.c2
-rw-r--r--drivers/power/sequencing/pwrseq-pcie-m2.c2
-rw-r--r--drivers/regulator/Kconfig2
-rw-r--r--drivers/regulator/bd71828-regulator.c2
-rw-r--r--drivers/regulator/bq257xx-regulator.c3
-rw-r--r--drivers/regulator/fp9931.c7
-rw-r--r--drivers/regulator/mt6363-regulator.c4
-rw-r--r--drivers/regulator/pca9450-regulator.c14
-rw-r--r--drivers/regulator/pf9453-regulator.c2
-rw-r--r--drivers/regulator/tps65185.c3
-rw-r--r--drivers/remoteproc/imx_rproc.c2
-rw-r--r--drivers/remoteproc/mtk_scp.c39
-rw-r--r--drivers/remoteproc/qcom_sysmon.c2
-rw-r--r--drivers/remoteproc/qcom_wcnss.c2
-rw-r--r--drivers/resctrl/mpam_devices.c2
-rw-r--r--drivers/resctrl/test_mpam_devices.c22
-rw-r--r--drivers/reset/core.c1
-rw-r--r--drivers/reset/reset-rzg2l-usbphy-ctrl.c5
-rw-r--r--drivers/reset/spacemit/reset-spacemit-k3.c60
-rw-r--r--drivers/s390/block/dasd_eckd.c16
-rw-r--r--drivers/s390/crypto/zcrypt_ccamisc.c12
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c3
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c32
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c36
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h3
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c44
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c2
-rw-r--r--drivers/scsi/scsi_devinfo.c2
-rw-r--r--drivers/scsi/scsi_scan.c7
-rw-r--r--drivers/scsi/scsi_transport_sas.c2
-rw-r--r--drivers/scsi/ses.c7
-rw-r--r--drivers/scsi/snic/vnic_dev.c9
-rw-r--r--drivers/scsi/storvsc_drv.c5
-rw-r--r--drivers/scsi/xen-scsifront.c2
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c6
-rw-r--r--drivers/soc/aspeed/aspeed-socinfo.c2
-rw-r--r--drivers/soc/fsl/qbman/qman.c24
-rw-r--r--drivers/soc/fsl/qe/qmc.c4
-rw-r--r--drivers/soc/microchip/mpfs-control-scb.c6
-rw-r--r--drivers/soc/microchip/mpfs-mss-top-sysreg.c6
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c13
-rw-r--r--drivers/soc/qcom/pdr_internal.h2
-rw-r--r--drivers/soc/qcom/pmic_glink_altmode.c39
-rw-r--r--drivers/soc/qcom/qcom_pdr_msg.c2
-rw-r--r--drivers/soc/rockchip/grf.c1
-rw-r--r--drivers/spi/spi-amlogic-spifc-a4.c63
-rw-r--r--drivers/spi/spi-amlogic-spisg.c12
-rw-r--r--drivers/spi/spi-atcspi200.c38
-rw-r--r--drivers/spi/spi-axiado.c31
-rw-r--r--drivers/spi/spi-cadence-quadspi.c23
-rw-r--r--drivers/spi/spi-dw-dma.c2
-rw-r--r--drivers/spi/spi-fsl-lpspi.c3
-rw-r--r--drivers/spi/spi-geni-qcom.c13
-rw-r--r--drivers/spi/spi-intel-pci.c1
-rw-r--r--drivers/spi/spi-meson-spicc.c2
-rw-r--r--drivers/spi/spi-rockchip-sfc.c2
-rw-r--r--drivers/spi/spi-sn-f-ospi.c42
-rw-r--r--drivers/spi/spi-stm32-ospi.c12
-rw-r--r--drivers/spi/spi-stm32.c3
-rw-r--r--drivers/spi/spi-zynq-qspi.c42
-rw-r--r--drivers/spi/spi.c57
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c15
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c5
-rw-r--r--drivers/staging/sm750fb/sm750.c1
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c22
-rw-r--r--drivers/target/loopback/tcm_loop.c52
-rw-r--r--drivers/target/target_core_configfs.c15
-rw-r--r--drivers/target/target_core_file.c2
-rw-r--r--drivers/tee/tee_shm.c27
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c8
-rw-r--r--drivers/thermal/thermal_core.c32
-rw-r--r--drivers/thunderbolt/nhi.c2
-rw-r--r--drivers/tty/serial/8250/8250.h25
-rw-r--r--drivers/tty/serial/8250/8250_dma.c15
-rw-r--r--drivers/tty/serial/8250/8250_dw.c296
-rw-r--r--drivers/tty/serial/8250/8250_pci.c17
-rw-r--r--drivers/tty/serial/8250/8250_port.c75
-rw-r--r--drivers/tty/serial/serial_core.c5
-rw-r--r--drivers/tty/serial/uartlite.c1
-rw-r--r--drivers/tty/vt/vt.c26
-rw-r--r--drivers/ufs/core/ufshcd.c49
-rw-r--r--drivers/usb/cdns3/cdns3-gadget.c4
-rw-r--r--drivers/usb/class/cdc-acm.c14
-rw-r--r--drivers/usb/class/cdc-acm.h2
-rw-r--r--drivers/usb/class/cdc-wdm.c4
-rw-r--r--drivers/usb/class/usbtmc.c9
-rw-r--r--drivers/usb/common/ulpi.c5
-rw-r--r--drivers/usb/core/config.c6
-rw-r--r--drivers/usb/core/driver.c23
-rw-r--r--drivers/usb/core/hcd.c2
-rw-r--r--drivers/usb/core/message.c100
-rw-r--r--drivers/usb/core/offload.c102
-rw-r--r--drivers/usb/core/phy.c20
-rw-r--r--drivers/usb/core/quirks.c24
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/dwc2/gadget.c2
-rw-r--r--drivers/usb/dwc3/dwc3-google.c5
-rw-r--r--drivers/usb/dwc3/dwc3-imx8mp.c2
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c2
-rw-r--r--drivers/usb/gadget/function/f_ecm.c37
-rw-r--r--drivers/usb/gadget/function/f_eem.c59
-rw-r--r--drivers/usb/gadget/function/f_hid.c23
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c12
-rw-r--r--drivers/usb/gadget/function/f_ncm.c146
-rw-r--r--drivers/usb/gadget/function/f_rndis.c51
-rw-r--r--drivers/usb/gadget/function/f_subset.c63
-rw-r--r--drivers/usb/gadget/function/f_tcm.c14
-rw-r--r--drivers/usb/gadget/function/f_uac1_legacy.c47
-rw-r--r--drivers/usb/gadget/function/f_uvc.c39
-rw-r--r--drivers/usb/gadget/function/u_ecm.h21
-rw-r--r--drivers/usb/gadget/function/u_eem.h21
-rw-r--r--drivers/usb/gadget/function/u_ether.c83
-rw-r--r--drivers/usb/gadget/function/u_ether.h56
-rw-r--r--drivers/usb/gadget/function/u_ether_configfs.h177
-rw-r--r--drivers/usb/gadget/function/u_gether.h22
-rw-r--r--drivers/usb/gadget/function/u_ncm.h25
-rw-r--r--drivers/usb/gadget/function/u_rndis.h31
-rw-r--r--drivers/usb/gadget/function/uvc.h3
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c5
-rw-r--r--drivers/usb/gadget/function/uvc_video.c2
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c42
-rw-r--r--drivers/usb/host/ehci-brcm.c4
-rw-r--r--drivers/usb/host/xhci-debugfs.c10
-rw-r--r--drivers/usb/host/xhci-ring.c1
-rw-r--r--drivers/usb/host/xhci-sideband.c18
-rw-r--r--drivers/usb/host/xhci.c4
-rw-r--r--drivers/usb/image/mdc800.c6
-rw-r--r--drivers/usb/misc/usbio.c7
-rw-r--r--drivers/usb/misc/uss720.c2
-rw-r--r--drivers/usb/misc/yurex.c2
-rw-r--r--drivers/usb/renesas_usbhs/common.c9
-rw-r--r--drivers/usb/roles/class.c7
-rw-r--r--drivers/usb/serial/io_edgeport.c3
-rw-r--r--drivers/usb/serial/io_usbvend.h1
-rw-r--r--drivers/usb/serial/option.c4
-rw-r--r--drivers/usb/typec/altmodes/displayport.c7
-rw-r--r--drivers/usb/typec/altmodes/thunderbolt.c44
-rw-r--r--drivers/usb/typec/class.c4
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c2
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c10
-rw-r--r--drivers/vfio/pci/vfio_pci_dmabuf.c5
-rw-r--r--drivers/video/fbdev/au1100fb.c8
-rw-r--r--drivers/virt/coco/tdx-guest/tdx-guest.c12
-rw-r--r--drivers/virtio/virtio_ring.c10
-rw-r--r--drivers/xen/privcmd.c76
-rw-r--r--drivers/xen/xen-acpi-processor.c7
-rw-r--r--drivers/xen/xen-pciback/xenbus.c10
-rw-r--r--drivers/xen/xenbus/xenbus_client.c17
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c42
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c2
947 files changed, 11288 insertions, 5271 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index df0ff0764d0d..6f4b545f7377 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -9,6 +9,7 @@ config ARCH_SUPPORTS_ACPI
menuconfig ACPI
bool "ACPI (Advanced Configuration and Power Interface) Support"
depends on ARCH_SUPPORTS_ACPI
+ select AUXILIARY_BUS
select PNP
select NLS
select CRC32
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 64199b19ceff..a09636a4168e 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -135,7 +135,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
}
}
- if (adev->device_type == ACPI_BUS_TYPE_DEVICE && !adev->pnp.type.backlight) {
+ if (adev->device_type == ACPI_BUS_TYPE_DEVICE) {
LIST_HEAD(resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index b34a48068a8d..b1652cab631a 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -113,6 +113,10 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (ide_dev) {
errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
+ if (errata.piix4.bmisx)
+ dev_dbg(&ide_dev->dev,
+ "Bus master activity detection (BM-IDE) erratum enabled\n");
+
pci_dev_put(ide_dev);
}
@@ -131,20 +135,17 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
if (isa_dev) {
pci_read_config_byte(isa_dev, 0x76, &value1);
pci_read_config_byte(isa_dev, 0x77, &value2);
- if ((value1 & 0x80) || (value2 & 0x80))
+ if ((value1 & 0x80) || (value2 & 0x80)) {
errata.piix4.fdma = 1;
+ dev_dbg(&isa_dev->dev,
+ "Type-F DMA livelock erratum (C3 disabled)\n");
+ }
pci_dev_put(isa_dev);
}
break;
}
- if (ide_dev)
- dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
-
- if (isa_dev)
- dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
-
return 0;
}
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 3fa28f1abca3..adbaf0226c90 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) "ACPI: video: " fmt
+#include <linux/auxiliary_bus.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -21,7 +22,6 @@
#include <linux/sort.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include <linux/suspend.h>
@@ -77,8 +77,9 @@ static int register_count;
static DEFINE_MUTEX(register_count_mutex);
static DEFINE_MUTEX(video_list_lock);
static LIST_HEAD(video_bus_head);
-static int acpi_video_bus_probe(struct platform_device *pdev);
-static void acpi_video_bus_remove(struct platform_device *pdev);
+static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
+ const struct auxiliary_device_id *id);
+static void acpi_video_bus_remove(struct auxiliary_device *aux);
static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data);
/*
@@ -93,19 +94,16 @@ enum acpi_video_level_idx {
ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */
};
-static const struct acpi_device_id video_device_ids[] = {
- {ACPI_VIDEO_HID, 0},
- {"", 0},
+static const struct auxiliary_device_id video_bus_auxiliary_id_table[] = {
+ { .name = "acpi.video_bus" },
+ {},
};
-MODULE_DEVICE_TABLE(acpi, video_device_ids);
+MODULE_DEVICE_TABLE(auxiliary, video_bus_auxiliary_id_table);
-static struct platform_driver acpi_video_bus = {
+static struct auxiliary_driver acpi_video_bus = {
.probe = acpi_video_bus_probe,
.remove = acpi_video_bus_remove,
- .driver = {
- .name = "acpi-video",
- .acpi_match_table = video_device_ids,
- },
+ .id_table = video_bus_auxiliary_id_table,
};
struct acpi_video_bus_flags {
@@ -1885,7 +1883,7 @@ static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device)
}
static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video,
- struct platform_device *pdev)
+ struct device *parent)
{
struct input_dev *input;
struct acpi_video_device *dev;
@@ -1908,7 +1906,7 @@ static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video,
input->phys = video->phys;
input->id.bustype = BUS_HOST;
input->id.product = 0x06;
- input->dev.parent = &pdev->dev;
+ input->dev.parent = parent;
input->evbit[0] = BIT(EV_KEY);
set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
set_bit(KEY_VIDEO_NEXT, input->keybit);
@@ -1980,9 +1978,10 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
static int instance;
-static int acpi_video_bus_probe(struct platform_device *pdev)
+static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
+ const struct auxiliary_device_id *id_unused)
{
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev);
struct acpi_video_bus *video;
bool auto_detect;
int error;
@@ -2019,7 +2018,7 @@ static int acpi_video_bus_probe(struct platform_device *pdev)
instance++;
}
- platform_set_drvdata(pdev, video);
+ auxiliary_set_drvdata(aux_dev, video);
video->device = device;
strscpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
@@ -2068,7 +2067,7 @@ static int acpi_video_bus_probe(struct platform_device *pdev)
!auto_detect)
acpi_video_bus_register_backlight(video);
- error = acpi_video_bus_add_notify_handler(video, pdev);
+ error = acpi_video_bus_add_notify_handler(video, &aux_dev->dev);
if (error)
goto err_del;
@@ -2096,10 +2095,10 @@ err_free_video:
return error;
}
-static void acpi_video_bus_remove(struct platform_device *pdev)
+static void acpi_video_bus_remove(struct auxiliary_device *aux_dev)
{
- struct acpi_video_bus *video = platform_get_drvdata(pdev);
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
+ struct acpi_video_bus *video = auxiliary_get_drvdata(aux_dev);
+ struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev);
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
acpi_video_bus_notify);
@@ -2163,7 +2162,7 @@ int acpi_video_register(void)
dmi_check_system(video_dmi_table);
- ret = platform_driver_register(&acpi_video_bus);
+ ret = auxiliary_driver_register(&acpi_video_bus);
if (ret)
goto leave;
@@ -2183,7 +2182,7 @@ void acpi_video_unregister(void)
{
mutex_lock(&register_count_mutex);
if (register_count) {
- platform_driver_unregister(&acpi_video_bus);
+ auxiliary_driver_unregister(&acpi_video_bus);
register_count = 0;
may_report_brightness_keys = false;
}
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 5f70b196e0aa..07d5790d09f8 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -379,8 +379,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_CPC", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Bufs) */
- PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,
- 0, 0, 0),
+ PACKAGE_INFO(ACPI_PTYPE1_VAR,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER |
+ ACPI_RTYPE_PACKAGE, 0, 0, 0, 0),
{{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
@@ -450,7 +451,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DSM",
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
- ACPI_TYPE_ANY | ACPI_TYPE_PACKAGE) |
+ ACPI_TYPE_PACKAGE | ACPI_TYPE_ANY) |
ARG_COUNT_IS_MINIMUM,
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index f6707325f582..2ec095e2009e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -818,9 +818,6 @@ const struct acpi_device *acpi_companion_match(const struct device *dev)
if (list_empty(&adev->pnp.ids))
return NULL;
- if (adev->pnp.type.backlight)
- return adev;
-
return acpi_primary_dev_companion(adev, dev);
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index f2579611e0a5..aa55ecfc2923 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1457,15 +1457,6 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
return 0;
/*
- * Skip devices whose ACPI companions don't support power management and
- * don't have a wakeup GPE.
- */
- if (!acpi_device_power_manageable(adev) && !acpi_device_can_wakeup(adev)) {
- dev_dbg(dev, "No ACPI power management or wakeup GPE\n");
- return 0;
- }
-
- /*
* Only attach the power domain to the first device if the
* companion is shared by multiple. This is to prevent doing power
* management twice.
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 5f63ed120a2c..6f0065257a77 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1656,6 +1656,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca
ret = ec_install_handlers(ec, device, call_reg);
if (ret) {
+ ec_remove_handlers(ec);
+
if (ec == first_ec)
first_ec = NULL;
diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c
index f2c943b934be..9470f1830ff5 100644
--- a/drivers/acpi/osi.c
+++ b/drivers/acpi/osi.c
@@ -390,6 +390,19 @@ static const struct dmi_system_id acpi_osi_dmi_table[] __initconst = {
},
/*
+ * The screen backlight turns off during udev device creation
+ * when returning true for _OSI("Windows 2009")
+ */
+ {
+ .callback = dmi_disable_osi_win7,
+ .ident = "Acer Aspire One D255",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AOD255"),
+ },
+ },
+
+ /*
* The wireless hotkey does not work on those machines when
* returning true for _OSI("Windows 2012")
*/
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5b777316b9ac..62b9c83d4f20 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1681,7 +1681,7 @@ acpi_status __init acpi_os_initialize(void)
* Use acpi_os_map_generic_address to pre-map the reset
* register if it's in system memory.
*/
- void *rv;
+ void __iomem *rv;
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
pr_debug("%s: Reset register mapping %s\n", __func__,
diff --git a/drivers/acpi/riscv/rimt.c b/drivers/acpi/riscv/rimt.c
index 229c4a0d47a3..906282b0e63c 100644
--- a/drivers/acpi/riscv/rimt.c
+++ b/drivers/acpi/riscv/rimt.c
@@ -263,6 +263,13 @@ static int rimt_iommu_xlate(struct device *dev, struct acpi_rimt_node *node, u32
if (!rimt_fwnode)
return -EPROBE_DEFER;
+ /*
+ * EPROBE_DEFER ensures IOMMU is probed before the devices that
+ * depend on them. During shutdown, however, the IOMMU may be removed
+ * first, leading to issues. To avoid this, a device link is added
+ * which enforces the correct removal order.
+ */
+ device_link_add(dev, rimt_fwnode->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
return acpi_iommu_fwspec_init(dev, deviceid, rimt_fwnode);
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index dfdd004fb1a9..e8cdbdb46fdb 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -6,6 +6,7 @@
#define pr_fmt(fmt) "ACPI: " fmt
#include <linux/async.h>
+#include <linux/auxiliary_bus.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -2192,6 +2193,44 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
return acpi_bus_check_add(handle, false, (struct acpi_device **)ret_p);
}
+static void acpi_video_bus_device_release(struct device *dev)
+{
+ struct auxiliary_device *aux_dev = to_auxiliary_dev(dev);
+
+ kfree(aux_dev);
+}
+
+static void acpi_create_video_bus_device(struct acpi_device *adev,
+ struct acpi_device *parent)
+{
+ struct auxiliary_device *aux_dev;
+ static unsigned int aux_dev_id;
+
+ aux_dev = kzalloc_obj(*aux_dev);
+ if (!aux_dev)
+ return;
+
+ aux_dev->id = aux_dev_id++;
+ aux_dev->name = "video_bus";
+ aux_dev->dev.parent = acpi_get_first_physical_node(parent);
+ if (!aux_dev->dev.parent)
+ goto err;
+
+ aux_dev->dev.release = acpi_video_bus_device_release;
+
+ if (auxiliary_device_init(aux_dev))
+ goto err;
+
+ ACPI_COMPANION_SET(&aux_dev->dev, adev);
+ if (__auxiliary_device_add(aux_dev, "acpi"))
+ auxiliary_device_uninit(aux_dev);
+
+ return;
+
+err:
+ kfree(aux_dev);
+}
+
struct acpi_scan_system_dev {
struct list_head node;
struct acpi_device *adev;
@@ -2229,6 +2268,12 @@ static void acpi_default_enumeration(struct acpi_device *device)
sd->adev = device;
list_add_tail(&sd->node, &acpi_scan_system_dev_list);
}
+ } else if (device->pnp.type.backlight) {
+ struct acpi_device *parent;
+
+ parent = acpi_dev_parent(device);
+ if (parent)
+ acpi_create_video_bus_device(device, parent);
} else {
/* For a regular device object, create a platform device. */
acpi_create_platform_device(device, NULL);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 66ec81e306d4..132a9df98471 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -386,6 +386,14 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "80E1"),
},
},
+ {
+ .callback = init_nvs_save_s3,
+ .ident = "Lenovo G70-35",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "80Q5"),
+ },
+ },
/*
* ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
* the Low Power S0 Idle firmware interface (see
diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs
index fdd97112ef5c..b57e0c7ba3f1 100644
--- a/drivers/android/binder/page_range.rs
+++ b/drivers/android/binder/page_range.rs
@@ -13,6 +13,8 @@
//
// The shrinker will use trylock methods because it locks them in a different order.
+use crate::AssertSync;
+
use core::{
marker::PhantomPinned,
mem::{size_of, size_of_val, MaybeUninit},
@@ -142,6 +144,30 @@ pub(crate) struct ShrinkablePageRange {
_pin: PhantomPinned,
}
+// We do not define any ops. For now, used only to check identity of vmas.
+static BINDER_VM_OPS: AssertSync<bindings::vm_operations_struct> = AssertSync(pin_init::zeroed());
+
+// To ensure that we do not accidentally install pages into or zap pages from the wrong vma, we
+// check its vm_ops and private data before using it.
+fn check_vma(vma: &virt::VmaRef, owner: *const ShrinkablePageRange) -> Option<&virt::VmaMixedMap> {
+ // SAFETY: Just reading the vm_ops pointer of any active vma is safe.
+ let vm_ops = unsafe { (*vma.as_ptr()).vm_ops };
+ if !ptr::eq(vm_ops, &BINDER_VM_OPS.0) {
+ return None;
+ }
+
+ // SAFETY: Reading the vm_private_data pointer of a binder-owned vma is safe.
+ let vm_private_data = unsafe { (*vma.as_ptr()).vm_private_data };
+ // The ShrinkablePageRange is only dropped when the Process is dropped, which only happens once
+ // the file's ->release handler is invoked, which means the ShrinkablePageRange outlives any
+ // VMA associated with it, so there can't be any false positives due to pointer reuse here.
+ if !ptr::eq(vm_private_data, owner.cast()) {
+ return None;
+ }
+
+ vma.as_mixedmap_vma()
+}
+
struct Inner {
/// Array of pages.
///
@@ -308,6 +334,18 @@ impl ShrinkablePageRange {
inner.size = num_pages;
inner.vma_addr = vma.start();
+ // This pointer is only used for comparison - it's not dereferenced.
+ //
+ // SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
+ // `vm_private_data`.
+ unsafe {
+ (*vma.as_ptr()).vm_private_data = ptr::from_ref(self).cast_mut().cast::<c_void>()
+ };
+
+ // SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
+ // `vm_ops`.
+ unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS.0 };
+
Ok(num_pages)
}
@@ -399,22 +437,25 @@ impl ShrinkablePageRange {
//
// Using `mmput_async` avoids this, because then the `mm` cleanup is instead queued to a
// workqueue.
- MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?)
- .mmap_read_lock()
- .vma_lookup(vma_addr)
- .ok_or(ESRCH)?
- .as_mixedmap_vma()
- .ok_or(ESRCH)?
- .vm_insert_page(user_page_addr, &new_page)
- .inspect_err(|err| {
- pr_warn!(
- "Failed to vm_insert_page({}): vma_addr:{} i:{} err:{:?}",
- user_page_addr,
- vma_addr,
- i,
- err
- )
- })?;
+ let mm = MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?);
+ {
+ let vma_read;
+ let mmap_read;
+ let vma = if let Some(ret) = mm.lock_vma_under_rcu(vma_addr) {
+ vma_read = ret;
+ check_vma(&vma_read, self)
+ } else {
+ mmap_read = mm.mmap_read_lock();
+ mmap_read
+ .vma_lookup(vma_addr)
+ .and_then(|vma| check_vma(vma, self))
+ };
+
+ match vma {
+ Some(vma) => vma.vm_insert_page(user_page_addr, &new_page)?,
+ None => return Err(ESRCH),
+ }
+ }
let inner = self.lock.lock();
@@ -667,12 +708,15 @@ unsafe extern "C" fn rust_shrink_free_page(
let mmap_read;
let mm_mutex;
let vma_addr;
+ let range_ptr;
{
// CAST: The `list_head` field is first in `PageInfo`.
let info = item as *mut PageInfo;
// SAFETY: The `range` field of `PageInfo` is immutable.
- let range = unsafe { &*((*info).range) };
+ range_ptr = unsafe { (*info).range };
+ // SAFETY: The `range` outlives its `PageInfo` values.
+ let range = unsafe { &*range_ptr };
mm = match range.mm.mmget_not_zero() {
Some(mm) => MmWithUser::into_mmput_async(mm),
@@ -717,9 +761,11 @@ unsafe extern "C" fn rust_shrink_free_page(
// SAFETY: The lru lock is locked when this method is called.
unsafe { bindings::spin_unlock(&raw mut (*lru).lock) };
- if let Some(vma) = mmap_read.vma_lookup(vma_addr) {
- let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
- vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
+ if let Some(unchecked_vma) = mmap_read.vma_lookup(vma_addr) {
+ if let Some(vma) = check_vma(unchecked_vma, range_ptr) {
+ let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
+ vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
+ }
}
drop(mmap_read);
diff --git a/drivers/android/binder/process.rs b/drivers/android/binder/process.rs
index 41de5593197c..f06498129aa9 100644
--- a/drivers/android/binder/process.rs
+++ b/drivers/android/binder/process.rs
@@ -1295,7 +1295,8 @@ impl Process {
}
pub(crate) fn dead_binder_done(&self, cookie: u64, thread: &Thread) {
- if let Some(death) = self.inner.lock().pull_delivered_death(cookie) {
+ let death = self.inner.lock().pull_delivered_death(cookie);
+ if let Some(death) = death {
death.set_notification_done(thread);
}
}
diff --git a/drivers/android/binder/range_alloc/array.rs b/drivers/android/binder/range_alloc/array.rs
index 07e1dec2ce63..ada1d1b4302e 100644
--- a/drivers/android/binder/range_alloc/array.rs
+++ b/drivers/android/binder/range_alloc/array.rs
@@ -118,7 +118,7 @@ impl<T> ArrayRangeAllocator<T> {
size: usize,
is_oneway: bool,
pid: Pid,
- ) -> Result<usize> {
+ ) -> Result<(usize, bool)> {
// Compute new value of free_oneway_space, which is set only on success.
let new_oneway_space = if is_oneway {
match self.free_oneway_space.checked_sub(size) {
@@ -146,7 +146,38 @@ impl<T> ArrayRangeAllocator<T> {
.ok()
.unwrap();
- Ok(insert_at_offset)
+ // Start detecting spammers once we have less than 20%
+ // of async space left (which is less than 10% of total
+ // buffer size).
+ //
+ // (This will short-circuit, so `low_oneway_space` is
+ // only called when necessary.)
+ let oneway_spam_detected =
+ is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
+
+ Ok((insert_at_offset, oneway_spam_detected))
+ }
+
+ /// Find the amount and size of buffers allocated by the current caller.
+ ///
+ /// The idea is that once we cross the threshold, whoever is responsible
+ /// for the low async space is likely to try to send another async transaction,
+ /// and at some point we'll catch them in the act. This is more efficient
+ /// than keeping a map per pid.
+ fn low_oneway_space(&self, calling_pid: Pid) -> bool {
+ let mut total_alloc_size = 0;
+ let mut num_buffers = 0;
+
+ // Warn if this pid has more than 50 transactions, or more than 50% of
+ // async space (which is 25% of total buffer size). Oneway spam is only
+ // detected when the threshold is exceeded.
+ for range in &self.ranges {
+ if range.state.is_oneway() && range.state.pid() == calling_pid {
+ total_alloc_size += range.size;
+ num_buffers += 1;
+ }
+ }
+ num_buffers > 50 || total_alloc_size > self.size / 4
}
pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result<FreedRange> {
diff --git a/drivers/android/binder/range_alloc/mod.rs b/drivers/android/binder/range_alloc/mod.rs
index 2301e2bc1a1f..1f4734468ff1 100644
--- a/drivers/android/binder/range_alloc/mod.rs
+++ b/drivers/android/binder/range_alloc/mod.rs
@@ -188,11 +188,11 @@ impl<T> RangeAllocator<T> {
self.reserve_new(args)
}
Impl::Array(array) => {
- let offset =
+ let (offset, oneway_spam_detected) =
array.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid)?;
Ok(ReserveNew::Success(ReserveNewSuccess {
offset,
- oneway_spam_detected: false,
+ oneway_spam_detected,
_empty_array_alloc: args.empty_array_alloc,
_new_tree_alloc: args.new_tree_alloc,
_tree_alloc: args.tree_alloc,
diff --git a/drivers/android/binder/range_alloc/tree.rs b/drivers/android/binder/range_alloc/tree.rs
index 838fdd2b47ea..48796fcdb362 100644
--- a/drivers/android/binder/range_alloc/tree.rs
+++ b/drivers/android/binder/range_alloc/tree.rs
@@ -164,15 +164,6 @@ impl<T> TreeRangeAllocator<T> {
self.free_oneway_space
};
- // Start detecting spammers once we have less than 20%
- // of async space left (which is less than 10% of total
- // buffer size).
- //
- // (This will short-circut, so `low_oneway_space` is
- // only called when necessary.)
- let oneway_spam_detected =
- is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
-
let (found_size, found_off, tree_node, free_tree_node) = match self.find_best_match(size) {
None => {
pr_warn!("ENOSPC from range_alloc.reserve_new - size: {}", size);
@@ -203,6 +194,15 @@ impl<T> TreeRangeAllocator<T> {
self.free_tree.insert(free_tree_node);
}
+ // Start detecting spammers once we have less than 20%
+ // of async space left (which is less than 10% of total
+ // buffer size).
+ //
+ // (This will short-circuit, so `low_oneway_space` is
+ // only called when necessary.)
+ let oneway_spam_detected =
+ is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
+
Ok((found_off, oneway_spam_detected))
}
diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index aa5f2a75adb4..014010662df8 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -306,7 +306,7 @@ impl kernel::Module for BinderModule {
/// Makes the inner type Sync.
#[repr(transparent)]
pub struct AssertSync<T>(T);
-// SAFETY: Used only to insert `file_operations` into a global, which is safe.
+// SAFETY: Used only to insert C bindings types into globals, which is safe.
unsafe impl<T> Sync for AssertSync<T> {}
/// File operations that rust_binderfs.c can use.
diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs
index 0b62d24b2118..c004214b1662 100644
--- a/drivers/android/binder/thread.rs
+++ b/drivers/android/binder/thread.rs
@@ -1015,12 +1015,9 @@ impl Thread {
// Copy offsets if there are any.
if offsets_size > 0 {
- {
- let mut reader =
- UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
- .reader();
- alloc.copy_into(&mut reader, aligned_data_size, offsets_size)?;
- }
+ let mut offsets_reader =
+ UserSlice::new(UserPtr::from_addr(trd_data_ptr.offsets as _), offsets_size)
+ .reader();
let offsets_start = aligned_data_size;
let offsets_end = aligned_data_size + offsets_size;
@@ -1041,11 +1038,9 @@ impl Thread {
.step_by(size_of::<u64>())
.enumerate()
{
- let offset: usize = view
- .alloc
- .read::<u64>(index_offset)?
- .try_into()
- .map_err(|_| EINVAL)?;
+ let offset = offsets_reader.read::<u64>()?;
+ view.alloc.write(index_offset, &offset)?;
+ let offset: usize = offset.try_into().map_err(|_| EINVAL)?;
if offset < end_of_previous_object || !is_aligned(offset, size_of::<u32>()) {
pr_warn!("Got transaction with invalid offset.");
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 931d0081169b..1d73a53370cf 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -68,6 +68,7 @@ enum board_ids {
/* board IDs for specific chipsets in alphabetical order */
board_ahci_al,
board_ahci_avn,
+ board_ahci_jmb585,
board_ahci_mcp65,
board_ahci_mcp77,
board_ahci_mcp89,
@@ -212,6 +213,15 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_avn_ops,
},
+ /* JMicron JMB582/585: 64-bit DMA is broken, force 32-bit */
+ [board_ahci_jmb585] = {
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR |
+ AHCI_HFLAG_32BIT_ONLY),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
[board_ahci_mcp65] = {
AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
AHCI_HFLAG_YES_NCQ),
@@ -439,6 +449,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* Elkhart Lake IDs 0x4b60 & 0x4b62 https://sata-io.org/product/8803 not tested yet */
{ PCI_VDEVICE(INTEL, 0x4b63), board_ahci_pcs_quirk }, /* Elkhart Lake AHCI */
+ /* JMicron JMB582/585: force 32-bit DMA (broken 64-bit implementation) */
+ { PCI_VDEVICE(JMICRON, 0x0582), board_ahci_jmb585 },
+ { PCI_VDEVICE(JMICRON, 0x0585), board_ahci_jmb585 },
+
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 11909417f017..374993031895 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4188,7 +4188,11 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
{ "ST3320[68]13AS", "SD1[5-9]", ATA_QUIRK_NONCQ |
ATA_QUIRK_FIRMWARE_WARN },
+ /* ADATA devices with LPM issues. */
+ { "ADATA SU680", NULL, ATA_QUIRK_NOLPM },
+
/* Seagate disks with LPM issues */
+ { "ST1000DM010-2EP102", NULL, ATA_QUIRK_NOLPM },
{ "ST2000DM008-2FR102", NULL, ATA_QUIRK_NOLPM },
/* drives which fail FPDMA_AA activation (some may freeze afterwards)
@@ -4231,6 +4235,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
/* Devices that do not need bridging limits applied */
{ "MTRON MSP-SATA*", NULL, ATA_QUIRK_BRIDGE_OK },
{ "BUFFALO HD-QSU2/R5", NULL, ATA_QUIRK_BRIDGE_OK },
+ { "QEMU HARDDISK", "2.5+", ATA_QUIRK_BRIDGE_OK },
/* Devices which aren't very happy with higher link speeds */
{ "WD My Book", NULL, ATA_QUIRK_1_5_GBPS },
@@ -6269,10 +6274,6 @@ static void ata_port_detach(struct ata_port *ap)
}
}
- /* Make sure the deferred qc work finished. */
- cancel_work_sync(&ap->deferred_qc_work);
- WARN_ON(ap->deferred_qc);
-
/* Tell EH to disable all devices */
ap->pflags |= ATA_PFLAG_UNLOADING;
ata_port_schedule_eh(ap);
@@ -6283,9 +6284,11 @@ static void ata_port_detach(struct ata_port *ap)
/* wait till EH commits suicide */
ata_port_wait_eh(ap);
- /* it better be dead now */
+ /* It better be dead now and not have any remaining deferred qc. */
WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
+ WARN_ON(ap->deferred_qc);
+ cancel_work_sync(&ap->deferred_qc_work);
cancel_delayed_work_sync(&ap->hotplug_task);
cancel_delayed_work_sync(&ap->scsi_rescan_task);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 72a22b6c9682..23be85418b3b 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -640,12 +640,29 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
set_host_byte(scmd, DID_OK);
ata_qc_for_each_raw(ap, qc, i) {
- if (qc->flags & ATA_QCFLAG_ACTIVE &&
- qc->scsicmd == scmd)
+ if (qc->scsicmd != scmd)
+ continue;
+ if ((qc->flags & ATA_QCFLAG_ACTIVE) ||
+ qc == ap->deferred_qc)
break;
}
- if (i < ATA_MAX_QUEUE) {
+ if (i < ATA_MAX_QUEUE && qc == ap->deferred_qc) {
+ /*
+ * This is a deferred command that timed out while
+ * waiting for the command queue to drain. Since the qc
+ * is not active yet (deferred_qc is still set, so the
+ * deferred qc work has not issued the command yet),
+ * simply signal the timeout by finishing the SCSI
+ * command and clear the deferred qc to prevent the
+ * deferred qc work from issuing this qc.
+ */
+ WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
+ ap->deferred_qc = NULL;
+ cancel_work(&ap->deferred_qc_work);
+ set_host_byte(scmd, DID_TIME_OUT);
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+ } else if (i < ATA_MAX_QUEUE) {
/* the scmd has an associated qc */
if (!(qc->flags & ATA_QCFLAG_EH)) {
/* which hasn't failed yet, timeout */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index c0dd75a0287c..3b65df914ebb 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1699,6 +1699,7 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
scmd = qc->scsicmd;
ap->deferred_qc = NULL;
+ cancel_work(&ap->deferred_qc_work);
ata_qc_free(qc);
scmd->result = (DID_SOFT_ERROR << 16);
scsi_done(scmd);
@@ -3599,7 +3600,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
if (cdb[2] != 1 && cdb[2] != 3) {
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
- ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
+ ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
return 0;
}
diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c
index defb0573e43c..c7a962728752 100644
--- a/drivers/auxdisplay/lcd2s.c
+++ b/drivers/auxdisplay/lcd2s.c
@@ -99,8 +99,13 @@ static int lcd2s_print(struct charlcd *lcd, int c)
{
struct lcd2s_data *lcd2s = lcd->drvdata;
u8 buf[2] = { LCD2S_CMD_WRITE, c };
+ int ret;
- lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+ ret = lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf))
+ return -EIO;
return 0;
}
@@ -108,9 +113,13 @@ static int lcd2s_gotoxy(struct charlcd *lcd, unsigned int x, unsigned int y)
{
struct lcd2s_data *lcd2s = lcd->drvdata;
u8 buf[3] = { LCD2S_CMD_CUR_POS, y + 1, x + 1 };
+ int ret;
- lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
-
+ ret = lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(buf))
+ return -EIO;
return 0;
}
diff --git a/drivers/auxdisplay/line-display.c b/drivers/auxdisplay/line-display.c
index 81b4aac65807..fb6d9294140d 100644
--- a/drivers/auxdisplay/line-display.c
+++ b/drivers/auxdisplay/line-display.c
@@ -365,7 +365,7 @@ static DEFINE_IDA(linedisp_id);
static void linedisp_release(struct device *dev)
{
- struct linedisp *linedisp = to_linedisp(dev);
+ struct linedisp *linedisp = container_of(dev, struct linedisp, dev);
kfree(linedisp->map);
kfree(linedisp->message);
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 79d031d2d845..1af95ac68b77 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -179,19 +179,10 @@ void device_release_driver_internal(struct device *dev, const struct device_driv
void driver_detach(const struct device_driver *drv);
void driver_deferred_probe_del(struct device *dev);
void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf);
-static inline int driver_match_device_locked(const struct device_driver *drv,
- struct device *dev)
-{
- device_lock_assert(dev);
-
- return drv->bus->match ? drv->bus->match(dev, drv) : 1;
-}
-
static inline int driver_match_device(const struct device_driver *drv,
struct device *dev)
{
- guard(device)(dev);
- return driver_match_device_locked(drv, dev);
+ return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
static inline void dev_sync_state(struct device *dev)
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index bb61d8adbab1..8b6722ff8590 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -504,6 +504,36 @@ int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,
}
EXPORT_SYMBOL_GPL(bus_for_each_drv);
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ ret = __device_set_driver_override(dev, buf, count);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ guard(spinlock)(&dev->driver_override.lock);
+ return sysfs_emit(buf, "%s\n", dev->driver_override.name);
+}
+static DEVICE_ATTR_RW(driver_override);
+
+static struct attribute *driver_override_dev_attrs[] = {
+ &dev_attr_driver_override.attr,
+ NULL,
+};
+
+static const struct attribute_group driver_override_dev_group = {
+ .attrs = driver_override_dev_attrs,
+};
+
/**
* bus_add_device - add device to bus
* @dev: device being added
@@ -537,9 +567,15 @@ int bus_add_device(struct device *dev)
if (error)
goto out_put;
+ if (dev->bus->driver_override) {
+ error = device_add_group(dev, &driver_override_dev_group);
+ if (error)
+ goto out_groups;
+ }
+
error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev));
if (error)
- goto out_groups;
+ goto out_override;
error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem");
if (error)
@@ -550,6 +586,9 @@ int bus_add_device(struct device *dev)
out_subsys:
sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
+out_override:
+ if (dev->bus->driver_override)
+ device_remove_group(dev, &driver_override_dev_group);
out_groups:
device_remove_groups(dev, sp->bus->dev_groups);
out_put:
@@ -607,6 +646,8 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->kobj, "subsystem");
sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
+ if (dev->bus->driver_override)
+ device_remove_group(dev, &driver_override_dev_group);
device_remove_groups(dev, dev->bus->dev_groups);
if (klist_node_attached(&dev->p->knode_bus))
klist_del(&dev->p->knode_bus);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 827fc7adacc7..ffab0a9c8ccb 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -127,7 +127,7 @@ static const struct kobj_type class_ktype = {
};
int class_create_file_ns(const struct class *cls, const struct class_attribute *attr,
- const void *ns)
+ const struct ns_common *ns)
{
struct subsys_private *sp = class_to_subsys(cls);
int error;
@@ -143,7 +143,7 @@ int class_create_file_ns(const struct class *cls, const struct class_attribute *
EXPORT_SYMBOL_GPL(class_create_file_ns);
void class_remove_file_ns(const struct class *cls, const struct class_attribute *attr,
- const void *ns)
+ const struct ns_common *ns)
{
struct subsys_private *sp = class_to_subsys(cls);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 791f9e444df8..0613de0fbe44 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2556,6 +2556,7 @@ static void device_release(struct kobject *kobj)
devres_release_all(dev);
kfree(dev->dma_range_map);
+ kfree(dev->driver_override.name);
if (dev->release)
dev->release(dev);
@@ -2569,15 +2570,14 @@ static void device_release(struct kobject *kobj)
kfree(p);
}
-static const void *device_namespace(const struct kobject *kobj)
+static const struct ns_common *device_namespace(const struct kobject *kobj)
{
const struct device *dev = kobj_to_dev(kobj);
- const void *ns = NULL;
if (dev->class && dev->class->namespace)
- ns = dev->class->namespace(dev);
+ return dev->class->namespace(dev);
- return ns;
+ return NULL;
}
static void device_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid)
@@ -3159,6 +3159,7 @@ void device_initialize(struct device *dev)
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
+ spin_lock_init(&dev->driver_override.lock);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0354f209529c..37c7e54e0e4c 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -381,6 +381,66 @@ static void __exit deferred_probe_exit(void)
}
__exitcall(deferred_probe_exit);
+int __device_set_driver_override(struct device *dev, const char *s, size_t len)
+{
+ const char *new, *old;
+ char *cp;
+
+ if (!s)
+ return -EINVAL;
+
+ /*
+ * The stored value will be used in sysfs show callback (sysfs_emit()),
+ * which has a length limit of PAGE_SIZE and adds a trailing newline.
+ * Thus we can store one character less to avoid truncation during sysfs
+ * show.
+ */
+ if (len >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ /*
+ * Compute the real length of the string in case userspace sends us a
+ * bunch of \0 characters like python likes to do.
+ */
+ len = strlen(s);
+
+ if (!len) {
+ /* Empty string passed - clear override */
+ spin_lock(&dev->driver_override.lock);
+ old = dev->driver_override.name;
+ dev->driver_override.name = NULL;
+ spin_unlock(&dev->driver_override.lock);
+ kfree(old);
+
+ return 0;
+ }
+
+ cp = strnchr(s, len, '\n');
+ if (cp)
+ len = cp - s;
+
+ new = kstrndup(s, len, GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ spin_lock(&dev->driver_override.lock);
+ old = dev->driver_override.name;
+ if (cp != s) {
+ dev->driver_override.name = new;
+ spin_unlock(&dev->driver_override.lock);
+ } else {
+ /* "\n" passed - clear override */
+ dev->driver_override.name = NULL;
+ spin_unlock(&dev->driver_override.lock);
+
+ kfree(new);
+ }
+ kfree(old);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__device_set_driver_override);
+
/**
* device_is_bound() - Check if device is bound to a driver
* @dev: device to check
@@ -928,7 +988,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
bool async_allowed;
int ret;
- ret = driver_match_device_locked(drv, dev);
+ ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
return 0;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b45d41b018ca..d44591d52e36 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -603,7 +603,6 @@ static void platform_device_release(struct device *dev)
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
kfree(pa->pdev.resource);
- kfree(pa->pdev.driver_override);
kfree(pa);
}
@@ -1306,38 +1305,9 @@ static ssize_t numa_node_show(struct device *dev,
}
static DEVICE_ATTR_RO(numa_node);
-static ssize_t driver_override_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct platform_device *pdev = to_platform_device(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", pdev->driver_override);
- device_unlock(dev);
-
- return len;
-}
-
-static ssize_t driver_override_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int ret;
-
- ret = driver_set_override(dev, &pdev->driver_override, buf, count);
- if (ret)
- return ret;
-
- return count;
-}
-static DEVICE_ATTR_RW(driver_override);
-
static struct attribute *platform_dev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_numa_node.attr,
- &dev_attr_driver_override.attr,
NULL,
};
@@ -1377,10 +1347,12 @@ static int platform_match(struct device *dev, const struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
+ int ret;
/* When driver_override is set, only bind to the matching driver */
- if (pdev->driver_override)
- return !strcmp(pdev->driver_override, drv->name);
+ ret = device_match_driver_override(dev, drv);
+ if (ret >= 0)
+ return ret;
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
@@ -1516,6 +1488,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
const struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
+ .driver_override = true,
.match = platform_match,
.uevent = platform_uevent,
.probe = platform_probe,
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 0ee8ea971aa4..335288e8b5b3 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1895,6 +1895,7 @@ void pm_runtime_reinit(struct device *dev)
void pm_runtime_remove(struct device *dev)
{
__pm_runtime_disable(dev, false);
+ flush_work(&dev->power.work);
pm_runtime_reinit(dev);
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 6a63860579dd..8d9a34be57fb 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -797,7 +797,18 @@ struct fwnode_handle *
fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
- return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
+ struct fwnode_handle *next;
+
+ if (IS_ERR_OR_NULL(fwnode))
+ return NULL;
+
+ /* Try to find a child in primary fwnode */
+ next = fwnode_call_ptr_op(fwnode, get_next_child_node, child);
+ if (next)
+ return next;
+
+ /* When no more children in primary, continue with secondary */
+ return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child);
}
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
@@ -841,19 +852,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node);
struct fwnode_handle *device_get_next_child_node(const struct device *dev,
struct fwnode_handle *child)
{
- const struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct fwnode_handle *next;
-
- if (IS_ERR_OR_NULL(fwnode))
- return NULL;
-
- /* Try to find a child in primary fwnode */
- next = fwnode_get_next_child_node(fwnode, child);
- if (next)
- return next;
-
- /* When no more children in primary, continue with secondary */
- return fwnode_get_next_child_node(fwnode->secondary, child);
+ return fwnode_get_next_child_node(dev_fwnode(dev), child);
}
EXPORT_SYMBOL_GPL(device_get_next_child_node);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 607c1246d994..e388b19850e3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
unsigned int val_num)
{
void *orig_work_buf;
+ unsigned int selector_reg;
unsigned int win_offset;
unsigned int win_page;
bool page_chg;
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return -EINVAL;
}
- /* It is possible to have selector register inside data window.
- In that case, selector register is located on every page and
- it needs no page switching, when accessed alone. */
+ /*
+ * Calculate the address of the selector register in the corresponding
+ * data window if it is located on every page.
+ */
+ page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
+ if (page_chg)
+ selector_reg = range->range_min + win_page * range->window_len +
+ range->selector_reg - range->window_start;
+
+ /*
+ * It is possible to have selector register inside data window.
+ * In that case, selector register is located on every page and it
+ * needs no page switching, when accessed alone.
+ *
+ * Nevertheless we should synchronize the cache values for it.
+ * This can't be properly achieved if the selector register is
+ * the first and the only one to be read inside the data window.
+ * That's why we update it in that case as well.
+ *
+ * However, we specifically avoid updating it for the default page,
+ * when it's overlapped with the real data window, to prevent from
+ * infinite looping.
+ */
if (val_num > 1 ||
+ (page_chg && selector_reg != range->selector_reg) ||
range->window_start + win_offset != range->selector_reg) {
/* Use separate work_buf during page switching */
orig_work_buf = map->work_buf;
@@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
ret = _regmap_update_bits(map, range->selector_reg,
range->selector_mask,
win_page << range->selector_shift,
- &page_chg, false);
+ NULL, false);
map->work_buf = orig_work_buf;
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index 742b2908ff68..b3dbf6c76e98 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -483,38 +483,20 @@ void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i)
int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i)
{
- struct lru_cache *al = device->act_log;
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9);
- unsigned nr_al_extents;
- unsigned available_update_slots;
unsigned enr;
- D_ASSERT(device, first <= last);
-
- nr_al_extents = 1 + last - first; /* worst case: all touched extends are cold. */
- available_update_slots = min(al->nr_elements - al->used,
- al->max_pending_changes - al->pending_changes);
-
- /* We want all necessary updates for a given request within the same transaction
- * We could first check how many updates are *actually* needed,
- * and use that instead of the worst-case nr_al_extents */
- if (available_update_slots < nr_al_extents) {
- /* Too many activity log extents are currently "hot".
- *
- * If we have accumulated pending changes already,
- * we made progress.
- *
- * If we cannot get even a single pending change through,
- * stop the fast path until we made some progress,
- * or requests to "cold" extents could be starved. */
- if (!al->pending_changes)
- __set_bit(__LC_STARVING, &device->act_log->flags);
- return -ENOBUFS;
+ if (i->partially_in_al_next_enr) {
+ D_ASSERT(device, first < i->partially_in_al_next_enr);
+ D_ASSERT(device, last >= i->partially_in_al_next_enr);
+ first = i->partially_in_al_next_enr;
}
+ D_ASSERT(device, first <= last);
+
/* Is resync active in this area? */
for (enr = first; enr <= last; enr++) {
struct lc_element *tmp;
@@ -529,14 +511,21 @@ int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *
}
}
- /* Checkout the refcounts.
- * Given that we checked for available elements and update slots above,
- * this has to be successful. */
+ /* Try to checkout the refcounts. */
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
al_ext = lc_get_cumulative(device->act_log, enr);
- if (!al_ext)
- drbd_info(device, "LOGIC BUG for enr=%u\n", enr);
+
+ if (!al_ext) {
+ /* Did not work. We may have exhausted the possible
+ * changes per transaction. Or raced with someone
+ * "locking" it against changes.
+ * Remember where to continue from.
+ */
+ if (enr > first)
+ i->partially_in_al_next_enr = enr;
+ return -ENOBUFS;
+ }
}
return 0;
}
@@ -556,7 +545,11 @@ void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i)
for (enr = first; enr <= last; enr++) {
extent = lc_find(device->act_log, enr);
- if (!extent) {
+ /* Yes, this masks a bug elsewhere. However, during normal
+ * operation this is harmless, so no need to crash the kernel
+ * by the BUG_ON(refcount == 0) in lc_put().
+ */
+ if (!extent || extent->refcnt == 0) {
drbd_err(device, "al_complete_io() called on inactive extent %u\n", enr);
continue;
}
diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h
index 366489b72fe9..5d3213b81eed 100644
--- a/drivers/block/drbd/drbd_interval.h
+++ b/drivers/block/drbd/drbd_interval.h
@@ -8,12 +8,15 @@
struct drbd_interval {
struct rb_node rb;
sector_t sector; /* start sector of the interval */
- unsigned int size; /* size in bytes */
sector_t end; /* highest interval end in subtree */
+ unsigned int size; /* size in bytes */
unsigned int local:1 /* local or remote request? */;
unsigned int waiting:1; /* someone is waiting for completion */
unsigned int completed:1; /* this has been completed already;
* ignore for conflict detection */
+
+ /* to resume a partially successful drbd_al_begin_io_nonblock(); */
+ unsigned int partially_in_al_next_enr;
};
static inline void drbd_clear_interval(struct drbd_interval *i)
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index b8f0eddf7e87..200d464e984b 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -32,6 +32,7 @@
#include <linux/memcontrol.h>
#include <linux/mm_inline.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/random.h>
#include <linux/reboot.h>
#include <linux/notifier.h>
@@ -732,9 +733,9 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device)
}
if (apv >= 88)
- strcpy(p->verify_alg, nc->verify_alg);
+ strscpy(p->verify_alg, nc->verify_alg);
if (apv >= 89)
- strcpy(p->csums_alg, nc->csums_alg);
+ strscpy(p->csums_alg, nc->csums_alg);
rcu_read_unlock();
return drbd_send_command(peer_device, sock, cmd, size, NULL, 0);
@@ -745,6 +746,7 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
struct drbd_socket *sock;
struct p_protocol *p;
struct net_conf *nc;
+ size_t integrity_alg_len;
int size, cf;
sock = &connection->data;
@@ -762,8 +764,10 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
}
size = sizeof(*p);
- if (connection->agreed_pro_version >= 87)
- size += strlen(nc->integrity_alg) + 1;
+ if (connection->agreed_pro_version >= 87) {
+ integrity_alg_len = strlen(nc->integrity_alg) + 1;
+ size += integrity_alg_len;
+ }
p->protocol = cpu_to_be32(nc->wire_protocol);
p->after_sb_0p = cpu_to_be32(nc->after_sb_0p);
@@ -778,7 +782,7 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
p->conn_flags = cpu_to_be32(cf);
if (connection->agreed_pro_version >= 87)
- strcpy(p->integrity_alg, nc->integrity_alg);
+ strscpy(p->integrity_alg, nc->integrity_alg, integrity_alg_len);
rcu_read_unlock();
return __conn_send_command(connection, sock, cmd, size, NULL, 0);
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 3cfef456a1f3..58b95bf4bdca 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -3801,14 +3801,14 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
*new_net_conf = *old_net_conf;
if (verify_tfm) {
- strcpy(new_net_conf->verify_alg, p->verify_alg);
+ strscpy(new_net_conf->verify_alg, p->verify_alg);
new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1;
crypto_free_shash(peer_device->connection->verify_tfm);
peer_device->connection->verify_tfm = verify_tfm;
drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg);
}
if (csums_tfm) {
- strcpy(new_net_conf->csums_alg, p->csums_alg);
+ strscpy(new_net_conf->csums_alg, p->csums_alg);
new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1;
crypto_free_shash(peer_device->connection->csums_tfm);
peer_device->connection->csums_tfm = csums_tfm;
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index d15826f6ee81..70f75ef07945 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -621,7 +621,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break;
case READ_COMPLETED_WITH_ERROR:
- drbd_set_out_of_sync(peer_device, req->i.sector, req->i.size);
+ drbd_set_out_of_sync(first_peer_device(device),
+ req->i.sector, req->i.size);
drbd_report_io_error(device, req);
__drbd_chk_io_error(device, DRBD_READ_ERROR);
fallthrough;
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 004f367243b6..63aeb7a76a8c 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -4443,7 +4443,9 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
/* Skip partition scan if disabled by user */
if (ub->dev_info.flags & UBLK_F_NO_AUTO_PART_SCAN) {
- clear_bit(GD_SUPPRESS_PART_SCAN, &disk->state);
+ /* Not clear for unprivileged daemons, see comment above */
+ if (!ub->unprivileged_daemons)
+ clear_bit(GD_SUPPRESS_PART_SCAN, &disk->state);
} else {
/* Schedule async partition scan for trusted daemons */
if (!ub->unprivileged_daemons)
@@ -5006,15 +5008,22 @@ static int ublk_ctrl_get_features(const struct ublksrv_ctrl_cmd *header)
return 0;
}
-static void ublk_ctrl_set_size(struct ublk_device *ub, const struct ublksrv_ctrl_cmd *header)
+static int ublk_ctrl_set_size(struct ublk_device *ub, const struct ublksrv_ctrl_cmd *header)
{
struct ublk_param_basic *p = &ub->params.basic;
u64 new_size = header->data[0];
+ int ret = 0;
mutex_lock(&ub->mutex);
+ if (!ub->ub_disk) {
+ ret = -ENODEV;
+ goto out;
+ }
p->dev_sectors = new_size;
set_capacity_and_notify(ub->ub_disk, p->dev_sectors);
+out:
mutex_unlock(&ub->mutex);
+ return ret;
}
struct count_busy {
@@ -5335,8 +5344,7 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
ret = ublk_ctrl_end_recovery(ub, &header);
break;
case UBLK_CMD_UPDATE_SIZE:
- ublk_ctrl_set_size(ub, &header);
- ret = 0;
+ ret = ublk_ctrl_set_size(ub, &header);
break;
case UBLK_CMD_QUIESCE_DEV:
ret = ublk_ctrl_quiesce_dev(ub, &header);
diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c
index 65a40266437c..51c043342127 100644
--- a/drivers/block/zloop.c
+++ b/drivers/block/zloop.c
@@ -542,6 +542,21 @@ out:
zloop_put_cmd(cmd);
}
+/*
+ * Sync the entire FS containing the zone files instead of walking all files.
+ */
+static int zloop_flush(struct zloop_device *zlo)
+{
+ struct super_block *sb = file_inode(zlo->data_dir)->i_sb;
+ int ret;
+
+ down_read(&sb->s_umount);
+ ret = sync_filesystem(sb);
+ up_read(&sb->s_umount);
+
+ return ret;
+}
+
static void zloop_handle_cmd(struct zloop_cmd *cmd)
{
struct request *rq = blk_mq_rq_from_pdu(cmd);
@@ -562,11 +577,7 @@ static void zloop_handle_cmd(struct zloop_cmd *cmd)
zloop_rw(cmd);
return;
case REQ_OP_FLUSH:
- /*
- * Sync the entire FS containing the zone files instead of
- * walking all files
- */
- cmd->ret = sync_filesystem(file_inode(zlo->data_dir)->i_sb);
+ cmd->ret = zloop_flush(zlo);
break;
case REQ_OP_ZONE_RESET:
cmd->ret = zloop_reset_zone(zlo, rq_zone_no(rq));
@@ -981,7 +992,8 @@ static int zloop_ctl_add(struct zloop_options *opts)
struct queue_limits lim = {
.max_hw_sectors = SZ_1M >> SECTOR_SHIFT,
.chunk_sectors = opts->zone_size,
- .features = BLK_FEAT_ZONED,
+ .features = BLK_FEAT_ZONED | BLK_FEAT_WRITE_CACHE,
+
};
unsigned int nr_zones, i, j;
struct zloop_device *zlo;
@@ -1162,7 +1174,12 @@ static int zloop_ctl_remove(struct zloop_options *opts)
int ret;
if (!(opts->mask & ZLOOP_OPT_ID)) {
- pr_err("No ID specified\n");
+ pr_err("No ID specified for remove\n");
+ return -EINVAL;
+ }
+
+ if (opts->mask & ~ZLOOP_OPT_ID) {
+ pr_err("Invalid option specified for remove\n");
return -EINVAL;
}
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index bca33403fc8b..af679375b193 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -549,7 +549,7 @@ static ssize_t bd_stat_show(struct device *dev, struct device_attribute *attr,
return ret;
}
-static ssize_t writeback_compressed_store(struct device *dev,
+static ssize_t compressed_writeback_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
@@ -564,12 +564,12 @@ static ssize_t writeback_compressed_store(struct device *dev,
return -EBUSY;
}
- zram->wb_compressed = val;
+ zram->compressed_wb = val;
return len;
}
-static ssize_t writeback_compressed_show(struct device *dev,
+static ssize_t compressed_writeback_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@@ -577,7 +577,7 @@ static ssize_t writeback_compressed_show(struct device *dev,
struct zram *zram = dev_to_zram(dev);
guard(rwsem_read)(&zram->dev_lock);
- val = zram->wb_compressed;
+ val = zram->compressed_wb;
return sysfs_emit(buf, "%d\n", val);
}
@@ -917,9 +917,8 @@ static void zram_account_writeback_submit(struct zram *zram)
static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
{
- u32 size, index = req->pps->index;
- int err, prio;
- bool huge;
+ u32 index = req->pps->index;
+ int err;
err = blk_status_to_errno(req->bio.bi_status);
if (err) {
@@ -946,28 +945,13 @@ static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
goto out;
}
- if (zram->wb_compressed) {
- /*
- * ZRAM_WB slots get freed, we need to preserve data required
- * for read decompression.
- */
- size = get_slot_size(zram, index);
- prio = get_slot_comp_priority(zram, index);
- huge = test_slot_flag(zram, index, ZRAM_HUGE);
- }
-
- slot_free(zram, index);
- set_slot_flag(zram, index, ZRAM_WB);
+ clear_slot_flag(zram, index, ZRAM_IDLE);
+ if (test_slot_flag(zram, index, ZRAM_HUGE))
+ atomic64_dec(&zram->stats.huge_pages);
+ atomic64_sub(get_slot_size(zram, index), &zram->stats.compr_data_size);
+ zs_free(zram->mem_pool, get_slot_handle(zram, index));
set_slot_handle(zram, index, req->blk_idx);
-
- if (zram->wb_compressed) {
- if (huge)
- set_slot_flag(zram, index, ZRAM_HUGE);
- set_slot_size(zram, index, size);
- set_slot_comp_priority(zram, index, prio);
- }
-
- atomic64_inc(&zram->stats.pages_stored);
+ set_slot_flag(zram, index, ZRAM_WB);
out:
slot_unlock(zram, index);
@@ -1100,7 +1084,7 @@ static int zram_writeback_slots(struct zram *zram,
*/
if (!test_slot_flag(zram, index, ZRAM_PP_SLOT))
goto next;
- if (zram->wb_compressed)
+ if (zram->compressed_wb)
err = read_from_zspool_raw(zram, req->page, index);
else
err = read_from_zspool(zram, req->page, index);
@@ -1429,7 +1413,7 @@ static void zram_async_read_endio(struct bio *bio)
*
* Keep the existing behavior for now.
*/
- if (zram->wb_compressed == false) {
+ if (zram->compressed_wb == false) {
/* No decompression needed, complete the parent IO */
bio_endio(req->parent);
bio_put(bio);
@@ -1508,7 +1492,7 @@ static int read_from_bdev_sync(struct zram *zram, struct page *page, u32 index,
flush_work(&req.work);
destroy_work_on_stack(&req.work);
- if (req.error || zram->wb_compressed == false)
+ if (req.error || zram->compressed_wb == false)
return req.error;
return decompress_bdev_page(zram, page, index);
@@ -2010,8 +1994,13 @@ static void slot_free(struct zram *zram, u32 index)
set_slot_comp_priority(zram, index, 0);
if (test_slot_flag(zram, index, ZRAM_HUGE)) {
+ /*
+ * Writeback completion decrements ->huge_pages but keeps
+ * ZRAM_HUGE flag for deferred decompression path.
+ */
+ if (!test_slot_flag(zram, index, ZRAM_WB))
+ atomic64_dec(&zram->stats.huge_pages);
clear_slot_flag(zram, index, ZRAM_HUGE);
- atomic64_dec(&zram->stats.huge_pages);
}
if (test_slot_flag(zram, index, ZRAM_WB)) {
@@ -3007,7 +2996,7 @@ static DEVICE_ATTR_WO(writeback);
static DEVICE_ATTR_RW(writeback_limit);
static DEVICE_ATTR_RW(writeback_limit_enable);
static DEVICE_ATTR_RW(writeback_batch_size);
-static DEVICE_ATTR_RW(writeback_compressed);
+static DEVICE_ATTR_RW(compressed_writeback);
#endif
#ifdef CONFIG_ZRAM_MULTI_COMP
static DEVICE_ATTR_RW(recomp_algorithm);
@@ -3031,7 +3020,7 @@ static struct attribute *zram_disk_attrs[] = {
&dev_attr_writeback_limit.attr,
&dev_attr_writeback_limit_enable.attr,
&dev_attr_writeback_batch_size.attr,
- &dev_attr_writeback_compressed.attr,
+ &dev_attr_compressed_writeback.attr,
#endif
&dev_attr_io_stat.attr,
&dev_attr_mm_stat.attr,
@@ -3091,7 +3080,7 @@ static int zram_add(void)
init_rwsem(&zram->dev_lock);
#ifdef CONFIG_ZRAM_WRITEBACK
zram->wb_batch_size = 32;
- zram->wb_compressed = false;
+ zram->compressed_wb = false;
#endif
/* gendisk structure */
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 515a72d9c06f..f0de8f8218f5 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -133,7 +133,7 @@ struct zram {
#ifdef CONFIG_ZRAM_WRITEBACK
struct file *backing_dev;
bool wb_limit_enable;
- bool wb_compressed;
+ bool compressed_wb;
u32 wb_batch_size;
u64 bd_wb_limit;
struct block_device *bdev;
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 246b6205c5e0..ab146894ba4e 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -251,11 +251,13 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
bt_dev_err(hdev, "Hardware error 0x%2.2x", code);
+ hci_req_sync_lock(hdev);
+
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reset after hardware error failed (%ld)",
PTR_ERR(skb));
- return;
+ goto unlock;
}
kfree_skb(skb);
@@ -263,18 +265,21 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)",
PTR_ERR(skb));
- return;
+ goto unlock;
}
if (skb->len != 13) {
bt_dev_err(hdev, "Exception info size mismatch");
kfree_skb(skb);
- return;
+ goto unlock;
}
bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1));
kfree_skb(skb);
+
+unlock:
+ hci_req_sync_unlock(hdev);
}
EXPORT_SYMBOL_GPL(btintel_hw_error);
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 74f820e89655..3b0626920193 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
*/
if (soc_type == QCA_WCN3988)
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
+ else if (soc_type == QCA_WCN3998)
+ rom_ver = ((soc_ver & 0x0000f000) >> 0x07) | (soc_ver & 0x0000000f);
else
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index a1c5eb993e47..5c535f3ab722 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2376,8 +2376,11 @@ static void btusb_work(struct work_struct *work)
if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) {
if (hdev->voice_setting & 0x0020) {
static const int alts[3] = { 2, 4, 5 };
+ unsigned int sco_idx;
- new_alts = alts[data->sco_num - 1];
+ sco_idx = min_t(unsigned int, data->sco_num - 1,
+ ARRAY_SIZE(alts) - 1);
+ new_alts = alts[sco_idx];
} else {
new_alts = data->sco_num;
}
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 07cc2a79a77b..a889a66a326f 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
{
struct h4_struct *h4 = hu->priv;
- if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
- return -EUNATCH;
-
h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
if (IS_ERR(h4->rx_skb)) {
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index 91acf24f1ef5..91c96ad12342 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev)
if (err || !fw->data || !fw->size) {
bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
err, bts_scr_name);
+ if (!err)
+ release_firmware(fw);
return -EINVAL;
}
ptr = (void *)fw->data;
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 5b02e7c3f56d..bb9f002aa85e 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2046,19 +2046,23 @@ retry:
}
out:
- if (ret && retries < MAX_INIT_RETRIES) {
- bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
+ if (ret) {
qca_power_shutdown(hu);
- if (hu->serdev) {
- serdev_device_close(hu->serdev);
- ret = serdev_device_open(hu->serdev);
- if (ret) {
- bt_dev_err(hdev, "failed to open port");
- return ret;
+
+ if (retries < MAX_INIT_RETRIES) {
+ bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
+ if (hu->serdev) {
+ serdev_device_close(hu->serdev);
+ ret = serdev_device_open(hu->serdev);
+ if (ret) {
+ bt_dev_err(hdev, "failed to open port");
+ return ret;
+ }
}
+ retries++;
+ goto retry;
}
- retries++;
- goto retry;
+ return ret;
}
/* Setup bdaddr */
diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c
index 3f00d953fb9a..c920bd6fbaaf 100644
--- a/drivers/bus/simple-pm-bus.c
+++ b/drivers/bus/simple-pm-bus.c
@@ -36,7 +36,7 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
* that's not listed in simple_pm_bus_of_match. We don't want to do any
* of the simple-pm-bus tasks for these devices, so return early.
*/
- if (pdev->driver_override)
+ if (device_has_driver_override(&pdev->dev))
return 0;
match = of_match_device(dev->driver->of_match_table, dev);
@@ -78,7 +78,7 @@ static void simple_pm_bus_remove(struct platform_device *pdev)
{
const void *data = of_device_get_match_data(&pdev->dev);
- if (pdev->driver_override || data)
+ if (device_has_driver_override(&pdev->dev) || data)
return;
dev_dbg(&pdev->dev, "%s\n", __func__);
diff --git a/drivers/cache/ax45mp_cache.c b/drivers/cache/ax45mp_cache.c
index 1d7dd3d2c101..934c5087ec2b 100644
--- a/drivers/cache/ax45mp_cache.c
+++ b/drivers/cache/ax45mp_cache.c
@@ -178,11 +178,11 @@ static const struct of_device_id ax45mp_cache_ids[] = {
static int __init ax45mp_cache_init(void)
{
- struct device_node *np;
struct resource res;
int ret;
- np = of_find_matching_node(NULL, ax45mp_cache_ids);
+ struct device_node *np __free(device_node) =
+ of_find_matching_node(NULL, ax45mp_cache_ids);
if (!of_device_is_available(np))
return -ENODEV;
diff --git a/drivers/cache/starfive_starlink_cache.c b/drivers/cache/starfive_starlink_cache.c
index 24c7d078ca22..3a25d2d7c70c 100644
--- a/drivers/cache/starfive_starlink_cache.c
+++ b/drivers/cache/starfive_starlink_cache.c
@@ -102,11 +102,11 @@ static const struct of_device_id starlink_cache_ids[] = {
static int __init starlink_cache_init(void)
{
- struct device_node *np;
u32 block_size;
int ret;
- np = of_find_matching_node(NULL, starlink_cache_ids);
+ struct device_node *np __free(device_node) =
+ of_find_matching_node(NULL, starlink_cache_ids);
if (!of_device_is_available(np))
return -ENODEV;
diff --git a/drivers/char/ipmi/ipmi_ipmb.c b/drivers/char/ipmi/ipmi_ipmb.c
index 3a51e58b2487..28818952a7a4 100644
--- a/drivers/char/ipmi/ipmi_ipmb.c
+++ b/drivers/char/ipmi/ipmi_ipmb.c
@@ -202,11 +202,16 @@ static int ipmi_ipmb_slave_cb(struct i2c_client *client,
break;
case I2C_SLAVE_READ_REQUESTED:
+ *val = 0xff;
+ ipmi_ipmb_check_msg_done(iidev);
+ break;
+
case I2C_SLAVE_STOP:
ipmi_ipmb_check_msg_done(iidev);
break;
case I2C_SLAVE_READ_PROCESSED:
+ *val = 0xff;
break;
}
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index c530966c4e07..c41f51c82edd 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -602,6 +602,22 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf,
static int __scan_channels(struct ipmi_smi *intf,
struct ipmi_device_id *id, bool rescan);
+static void ipmi_lock_xmit_msgs(struct ipmi_smi *intf, int run_to_completion,
+ unsigned long *flags)
+{
+ if (run_to_completion)
+ return;
+ spin_lock_irqsave(&intf->xmit_msgs_lock, *flags);
+}
+
+static void ipmi_unlock_xmit_msgs(struct ipmi_smi *intf, int run_to_completion,
+ unsigned long *flags)
+{
+ if (run_to_completion)
+ return;
+ spin_unlock_irqrestore(&intf->xmit_msgs_lock, *flags);
+}
+
static void free_ipmi_user(struct kref *ref)
{
struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount);
@@ -1869,21 +1885,32 @@ static struct ipmi_smi_msg *smi_add_send_msg(struct ipmi_smi *intf,
return smi_msg;
}
-static void smi_send(struct ipmi_smi *intf,
+static int smi_send(struct ipmi_smi *intf,
const struct ipmi_smi_handlers *handlers,
struct ipmi_smi_msg *smi_msg, int priority)
{
int run_to_completion = READ_ONCE(intf->run_to_completion);
unsigned long flags = 0;
+ int rv = 0;
- if (!run_to_completion)
- spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
+ ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
smi_msg = smi_add_send_msg(intf, smi_msg, priority);
- if (!run_to_completion)
- spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
+ ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
- if (smi_msg)
- handlers->sender(intf->send_info, smi_msg);
+ if (smi_msg) {
+ rv = handlers->sender(intf->send_info, smi_msg);
+ if (rv) {
+ ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
+ intf->curr_msg = NULL;
+ ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
+ /*
+ * Something may have been added to the transmit
+ * queue, so schedule a check for that.
+ */
+ queue_work(system_wq, &intf->smi_work);
+ }
+ }
+ return rv;
}
static bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg)
@@ -2296,6 +2323,7 @@ static int i_ipmi_request(struct ipmi_user *user,
struct ipmi_recv_msg *recv_msg;
int run_to_completion = READ_ONCE(intf->run_to_completion);
int rv = 0;
+ bool in_seq_table = false;
if (supplied_recv) {
recv_msg = supplied_recv;
@@ -2349,33 +2377,50 @@ static int i_ipmi_request(struct ipmi_user *user,
rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg,
source_address, source_lun,
retries, retry_time_ms);
+ in_seq_table = true;
} else if (is_ipmb_direct_addr(addr)) {
rv = i_ipmi_req_ipmb_direct(intf, addr, msgid, msg, smi_msg,
recv_msg, source_lun);
} else if (is_lan_addr(addr)) {
rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg,
source_lun, retries, retry_time_ms);
+ in_seq_table = true;
} else {
- /* Unknown address type. */
+ /* Unknown address type. */
ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
}
- if (rv) {
-out_err:
- if (!supplied_smi)
- ipmi_free_smi_msg(smi_msg);
- if (!supplied_recv)
- ipmi_free_recv_msg(recv_msg);
- } else {
+ if (!rv) {
dev_dbg(intf->si_dev, "Send: %*ph\n",
smi_msg->data_size, smi_msg->data);
- smi_send(intf, intf->handlers, smi_msg, priority);
+ rv = smi_send(intf, intf->handlers, smi_msg, priority);
+ if (rv != IPMI_CC_NO_ERROR)
+ /* smi_send() returns an IPMI err, return a Linux one. */
+ rv = -EIO;
+ if (rv && in_seq_table) {
+ /*
+ * If it's in the sequence table, it will be
+ * retried later, so ignore errors.
+ */
+ rv = 0;
+ /* But we need to fix the timeout. */
+ intf_start_seq_timer(intf, smi_msg->msgid);
+ ipmi_free_smi_msg(smi_msg);
+ smi_msg = NULL;
+ }
}
+out_err:
if (!run_to_completion)
mutex_unlock(&intf->users_mutex);
+ if (rv) {
+ if (!supplied_smi)
+ ipmi_free_smi_msg(smi_msg);
+ if (!supplied_recv)
+ ipmi_free_recv_msg(recv_msg);
+ }
return rv;
}
@@ -3949,12 +3994,12 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf,
dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
msg->data_size, msg->data);
- smi_send(intf, intf->handlers, msg, 0);
- /*
- * We used the message, so return the value that
- * causes it to not be freed or queued.
- */
- rv = -1;
+ if (smi_send(intf, intf->handlers, msg, 0) == IPMI_CC_NO_ERROR)
+ /*
+ * We used the message, so return the value that
+ * causes it to not be freed or queued.
+ */
+ rv = -1;
} else if (!IS_ERR(recv_msg)) {
/* Extract the source address from the data. */
ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
@@ -4028,12 +4073,12 @@ static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi *intf,
msg->data[4] = IPMI_INVALID_CMD_COMPLETION_CODE;
msg->data_size = 5;
- smi_send(intf, intf->handlers, msg, 0);
- /*
- * We used the message, so return the value that
- * causes it to not be freed or queued.
- */
- rv = -1;
+ if (smi_send(intf, intf->handlers, msg, 0) == IPMI_CC_NO_ERROR)
+ /*
+ * We used the message, so return the value that
+ * causes it to not be freed or queued.
+ */
+ rv = -1;
} else if (!IS_ERR(recv_msg)) {
/* Extract the source address from the data. */
daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr;
@@ -4173,7 +4218,7 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *intf,
struct ipmi_smi_msg *msg)
{
struct cmd_rcvr *rcvr;
- int rv = 0;
+ int rv = 0; /* Free by default */
unsigned char netfn;
unsigned char cmd;
unsigned char chan;
@@ -4226,12 +4271,12 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *intf,
dev_dbg(intf->si_dev, "Invalid command: %*ph\n",
msg->data_size, msg->data);
- smi_send(intf, intf->handlers, msg, 0);
- /*
- * We used the message, so return the value that
- * causes it to not be freed or queued.
- */
- rv = -1;
+ if (smi_send(intf, intf->handlers, msg, 0) == IPMI_CC_NO_ERROR)
+ /*
+ * We used the message, so return the value that
+ * causes it to not be freed or queued.
+ */
+ rv = -1;
} else if (!IS_ERR(recv_msg)) {
/* Extract the source address from the data. */
lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
@@ -4824,8 +4869,7 @@ static void smi_work(struct work_struct *t)
* message delivery.
*/
restart:
- if (!run_to_completion)
- spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
+ ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
if (intf->curr_msg == NULL && !intf->in_shutdown) {
struct list_head *entry = NULL;
@@ -4841,8 +4885,7 @@ restart:
intf->curr_msg = newmsg;
}
}
- if (!run_to_completion)
- spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
+ ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
if (newmsg) {
cc = intf->handlers->sender(intf->send_info, newmsg);
@@ -4850,8 +4893,11 @@ restart:
if (newmsg->recv_msg)
deliver_err_response(intf,
newmsg->recv_msg, cc);
- else
- ipmi_free_smi_msg(newmsg);
+ ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
+ intf->curr_msg = NULL;
+ ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
+ ipmi_free_smi_msg(newmsg);
+ newmsg = NULL;
goto restart;
}
}
@@ -4919,16 +4965,14 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf,
spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock,
flags);
- if (!run_to_completion)
- spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
+ ipmi_lock_xmit_msgs(intf, run_to_completion, &flags);
/*
* We can get an asynchronous event or receive message in addition
* to commands we send.
*/
if (msg == intf->curr_msg)
intf->curr_msg = NULL;
- if (!run_to_completion)
- spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
+ ipmi_unlock_xmit_msgs(intf, run_to_completion, &flags);
if (run_to_completion)
smi_work(&intf->smi_work);
@@ -5041,7 +5085,12 @@ static void check_msg_timeout(struct ipmi_smi *intf, struct seq_table *ent,
ipmi_inc_stat(intf,
retransmitted_ipmb_commands);
- smi_send(intf, intf->handlers, smi_msg, 0);
+ /* If this fails we'll retry later or timeout. */
+ if (smi_send(intf, intf->handlers, smi_msg, 0) != IPMI_CC_NO_ERROR) {
+ /* But fix the timeout. */
+ intf_start_seq_timer(intf, smi_msg->msgid);
+ ipmi_free_smi_msg(smi_msg);
+ }
} else
ipmi_free_smi_msg(smi_msg);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 6bdf624c37ce..4a9e9de4d684 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -809,6 +809,12 @@ restart:
*/
return_hosed_msg(smi_info, IPMI_BUS_ERR);
}
+ if (smi_info->waiting_msg != NULL) {
+ /* Also handle if there was a message waiting. */
+ smi_info->curr_msg = smi_info->waiting_msg;
+ smi_info->waiting_msg = NULL;
+ return_hosed_msg(smi_info, IPMI_BUS_ERR);
+ }
smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_HOSED);
goto out;
}
@@ -918,9 +924,14 @@ static int sender(void *send_info, struct ipmi_smi_msg *msg)
{
struct smi_info *smi_info = send_info;
unsigned long flags;
+ int rv = IPMI_CC_NO_ERROR;
debug_timestamp(smi_info, "Enqueue");
+ /*
+ * Check here for run to completion mode. A check under lock is
+ * later.
+ */
if (smi_info->si_state == SI_HOSED)
return IPMI_BUS_ERR;
@@ -934,18 +945,15 @@ static int sender(void *send_info, struct ipmi_smi_msg *msg)
}
spin_lock_irqsave(&smi_info->si_lock, flags);
- /*
- * The following two lines don't need to be under the lock for
- * the lock's sake, but they do need SMP memory barriers to
- * avoid getting things out of order. We are already claiming
- * the lock, anyway, so just do it under the lock to avoid the
- * ordering problem.
- */
- BUG_ON(smi_info->waiting_msg);
- smi_info->waiting_msg = msg;
- check_start_timer_thread(smi_info);
+ if (smi_info->si_state == SI_HOSED) {
+ rv = IPMI_BUS_ERR;
+ } else {
+ BUG_ON(smi_info->waiting_msg);
+ smi_info->waiting_msg = msg;
+ check_start_timer_thread(smi_info);
+ }
spin_unlock_irqrestore(&smi_info->si_lock, flags);
- return IPMI_CC_NO_ERROR;
+ return rv;
}
static void set_run_to_completion(void *send_info, bool i_run_to_completion)
@@ -1113,7 +1121,9 @@ static void smi_timeout(struct timer_list *t)
* SI_USEC_PER_JIFFY);
smi_result = smi_event_handler(smi_info, time_diff);
- if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
+ if (smi_info->si_state == SI_HOSED) {
+ timeout = jiffies + SI_TIMEOUT_HOSED;
+ } else if ((smi_info->io.irq) && (!smi_info->interrupt_disabled)) {
/* Running with interrupts, only do long timeouts. */
timeout = jiffies + SI_TIMEOUT_JIFFIES;
smi_inc_stat(smi_info, long_timeouts);
@@ -2226,7 +2236,8 @@ static void wait_msg_processed(struct smi_info *smi_info)
unsigned long jiffies_now;
long time_diff;
- while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
+ while (smi_info->si_state != SI_HOSED &&
+ (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL))) {
jiffies_now = jiffies;
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
* SI_USEC_PER_JIFFY);
diff --git a/drivers/char/ipmi/ipmi_si_ls2k.c b/drivers/char/ipmi/ipmi_si_ls2k.c
index 45442c257efd..4c1da80f256c 100644
--- a/drivers/char/ipmi/ipmi_si_ls2k.c
+++ b/drivers/char/ipmi/ipmi_si_ls2k.c
@@ -168,7 +168,7 @@ static void ipmi_ls2k_remove(struct platform_device *pdev)
ipmi_si_remove_by_dev(&pdev->dev);
}
-struct platform_driver ipmi_ls2k_platform_driver = {
+static struct platform_driver ipmi_ls2k_platform_driver = {
.driver = {
.name = "ls2k-ipmi-si",
},
diff --git a/drivers/char/random.c b/drivers/char/random.c
index dcd002e1b890..7ff4d29911fd 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -96,8 +96,7 @@ static ATOMIC_NOTIFIER_HEAD(random_ready_notifier);
/* Control how we warn userspace. */
static struct ratelimit_state urandom_warning =
RATELIMIT_STATE_INIT_FLAGS("urandom_warning", HZ, 3, RATELIMIT_MSG_ON_RELEASE);
-static int ratelimit_disable __read_mostly =
- IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM);
+static int ratelimit_disable __read_mostly = 0;
module_param_named(ratelimit_disable, ratelimit_disable, int, 0644);
MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression");
@@ -168,12 +167,6 @@ int __cold execute_with_initialized_rng(struct notifier_block *nb)
return ret;
}
-#define warn_unseeded_randomness() \
- if (IS_ENABLED(CONFIG_WARN_ALL_UNSEEDED_RANDOM) && !crng_ready()) \
- printk_deferred(KERN_NOTICE "random: %s called from %pS with crng_init=%d\n", \
- __func__, (void *)_RET_IP_, crng_init)
-
-
/*********************************************************************
*
* Fast key erasure RNG, the "crng".
@@ -434,7 +427,6 @@ static void _get_random_bytes(void *buf, size_t len)
*/
void get_random_bytes(void *buf, size_t len)
{
- warn_unseeded_randomness();
_get_random_bytes(buf, len);
}
EXPORT_SYMBOL(get_random_bytes);
@@ -523,8 +515,6 @@ type get_random_ ##type(void) \
struct batch_ ##type *batch; \
unsigned long next_gen; \
\
- warn_unseeded_randomness(); \
- \
if (!crng_ready()) { \
_get_random_bytes(&ret, sizeof(ret)); \
return ret; \
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
index 3ae162625bb1..c781425a005e 100644
--- a/drivers/clk/imx/clk-imx8qxp.c
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -346,7 +346,29 @@ static struct platform_driver imx8qxp_clk_driver = {
},
.probe = imx8qxp_clk_probe,
};
-module_platform_driver(imx8qxp_clk_driver);
+
+static int __init imx8qxp_clk_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&imx8qxp_clk_driver);
+ if (ret)
+ return ret;
+
+ ret = imx_clk_scu_module_init();
+ if (ret)
+ platform_driver_unregister(&imx8qxp_clk_driver);
+
+ return ret;
+}
+module_init(imx8qxp_clk_init);
+
+static void __exit imx8qxp_clk_exit(void)
+{
+ imx_clk_scu_module_exit();
+ platform_driver_unregister(&imx8qxp_clk_driver);
+}
+module_exit(imx8qxp_clk_exit);
MODULE_AUTHOR("Aisheng Dong <aisheng.dong@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX8QXP clock driver");
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index 33e637ad3579..9b33df9967ec 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -191,6 +191,16 @@ static bool imx_scu_clk_is_valid(u32 rsrc_id)
return p != NULL;
}
+int __init imx_clk_scu_module_init(void)
+{
+ return platform_driver_register(&imx_clk_scu_driver);
+}
+
+void __exit imx_clk_scu_module_exit(void)
+{
+ return platform_driver_unregister(&imx_clk_scu_driver);
+}
+
int imx_clk_scu_init(struct device_node *np,
const struct imx_clk_scu_rsrc_table *data)
{
@@ -215,7 +225,7 @@ int imx_clk_scu_init(struct device_node *np,
rsrc_table = data;
}
- return platform_driver_register(&imx_clk_scu_driver);
+ return 0;
}
/*
@@ -696,8 +706,7 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
if (ret)
goto put_device;
- ret = driver_set_override(&pdev->dev, &pdev->driver_override,
- "imx-scu-clk", strlen("imx-scu-clk"));
+ ret = device_set_driver_override(&pdev->dev, "imx-scu-clk");
if (ret)
goto put_device;
diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h
index af7b697f51ca..ca82f2cce897 100644
--- a/drivers/clk/imx/clk-scu.h
+++ b/drivers/clk/imx/clk-scu.h
@@ -25,6 +25,8 @@ extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8dxl;
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qxp;
extern const struct imx_clk_scu_rsrc_table imx_clk_scu_rsrc_imx8qm;
+int __init imx_clk_scu_module_init(void);
+void __exit imx_clk_scu_module_exit(void);
int imx_clk_scu_init(struct device_node *np,
const struct imx_clk_scu_rsrc_table *data);
struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,
diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c
index 48a8a607a84c..0df9f4636fb6 100644
--- a/drivers/comedi/comedi_fops.c
+++ b/drivers/comedi/comedi_fops.c
@@ -793,13 +793,15 @@ static void do_become_nonbusy(struct comedi_device *dev,
__comedi_clear_subdevice_runflags(s, COMEDI_SRF_RUNNING |
COMEDI_SRF_BUSY);
spin_unlock_irqrestore(&s->spin_lock, flags);
- if (comedi_is_runflags_busy(runflags)) {
+ if (async) {
/*
* "Run active" counter was set to 1 when setting up the
* command. Decrement it and wait for it to become 0.
*/
- comedi_put_is_subdevice_running(s);
- wait_for_completion(&async->run_complete);
+ if (comedi_is_runflags_busy(runflags)) {
+ comedi_put_is_subdevice_running(s);
+ wait_for_completion(&async->run_complete);
+ }
comedi_buf_reset(s);
async->inttrig = NULL;
kfree(async->cmd.chanlist);
diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c
index db225a3bf012..5ab96b5eefd1 100644
--- a/drivers/comedi/drivers.c
+++ b/drivers/comedi/drivers.c
@@ -1063,6 +1063,14 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = -EIO;
goto out;
}
+ if (IS_ENABLED(CONFIG_LOCKDEP)) {
+ /*
+ * dev->spinlock is for private use by the attached low-level
+ * driver. Reinitialize it to stop lock-dependency tracking
+ * between attachments to different low-level drivers.
+ */
+ spin_lock_init(&dev->spinlock);
+ }
dev->driver = driv;
dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
: dev->driver->driver_name;
diff --git a/drivers/comedi/drivers/dt2815.c b/drivers/comedi/drivers/dt2815.c
index 03ba2fd18a21..d066dc303520 100644
--- a/drivers/comedi/drivers/dt2815.c
+++ b/drivers/comedi/drivers/dt2815.c
@@ -175,6 +175,18 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
? current_range_type : voltage_range_type;
}
+ /*
+ * Check if hardware is present before attempting any I/O operations.
+ * Reading 0xff from status register typically indicates no hardware
+ * on the bus (floating bus reads as all 1s).
+ */
+ if (inb(dev->iobase + DT2815_STATUS) == 0xff) {
+ dev_err(dev->class_dev,
+ "No hardware detected at I/O base 0x%lx\n",
+ dev->iobase);
+ return -ENODEV;
+ }
+
/* Init the 2815 */
outb(0x00, dev->iobase + DT2815_STATUS);
for (i = 0; i < 100; i++) {
diff --git a/drivers/comedi/drivers/me4000.c b/drivers/comedi/drivers/me4000.c
index 7dd3a0071863..effe9fdbbafe 100644
--- a/drivers/comedi/drivers/me4000.c
+++ b/drivers/comedi/drivers/me4000.c
@@ -315,6 +315,18 @@ static int me4000_xilinx_download(struct comedi_device *dev,
unsigned int val;
unsigned int i;
+ /* Get data stream length from header. */
+ if (size >= 4) {
+ file_length = (((unsigned int)data[0] & 0xff) << 24) +
+ (((unsigned int)data[1] & 0xff) << 16) +
+ (((unsigned int)data[2] & 0xff) << 8) +
+ ((unsigned int)data[3] & 0xff);
+ }
+ if (size < 16 || file_length > size - 16) {
+ dev_err(dev->class_dev, "Firmware length inconsistency\n");
+ return -EINVAL;
+ }
+
if (!xilinx_iobase)
return -ENODEV;
@@ -346,10 +358,6 @@ static int me4000_xilinx_download(struct comedi_device *dev,
outl(val, devpriv->plx_regbase + PLX9052_CNTRL);
/* Download Xilinx firmware */
- file_length = (((unsigned int)data[0] & 0xff) << 24) +
- (((unsigned int)data[1] & 0xff) << 16) +
- (((unsigned int)data[2] & 0xff) << 8) +
- ((unsigned int)data[3] & 0xff);
usleep_range(10, 1000);
for (i = 0; i < file_length; i++) {
diff --git a/drivers/comedi/drivers/me_daq.c b/drivers/comedi/drivers/me_daq.c
index 076b15097afd..2f2ea029cffc 100644
--- a/drivers/comedi/drivers/me_daq.c
+++ b/drivers/comedi/drivers/me_daq.c
@@ -344,6 +344,25 @@ static int me2600_xilinx_download(struct comedi_device *dev,
unsigned int file_length;
unsigned int i;
+ /*
+ * Format of the firmware
+ * Build longs from the byte-wise coded header
+ * Byte 1-3: length of the array
+ * Byte 4-7: version
+ * Byte 8-11: date
+ * Byte 12-15: reserved
+ */
+ if (size >= 4) {
+ file_length = (((unsigned int)data[0] & 0xff) << 24) +
+ (((unsigned int)data[1] & 0xff) << 16) +
+ (((unsigned int)data[2] & 0xff) << 8) +
+ ((unsigned int)data[3] & 0xff);
+ }
+ if (size < 16 || file_length > size - 16) {
+ dev_err(dev->class_dev, "Firmware length inconsistency\n");
+ return -EINVAL;
+ }
+
/* disable irq's on PLX */
writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR);
@@ -358,22 +377,6 @@ static int me2600_xilinx_download(struct comedi_device *dev,
sleep(1);
/*
- * Format of the firmware
- * Build longs from the byte-wise coded header
- * Byte 1-3: length of the array
- * Byte 4-7: version
- * Byte 8-11: date
- * Byte 12-15: reserved
- */
- if (size < 16)
- return -EINVAL;
-
- file_length = (((unsigned int)data[0] & 0xff) << 24) +
- (((unsigned int)data[1] & 0xff) << 16) +
- (((unsigned int)data[2] & 0xff) << 8) +
- ((unsigned int)data[3] & 0xff);
-
- /*
* Loop for writing firmware byte by byte to xilinx
* Firmware data start at offset 16
*/
diff --git a/drivers/comedi/drivers/ni_atmio16d.c b/drivers/comedi/drivers/ni_atmio16d.c
index e5e7cc423c87..b057b3b3582e 100644
--- a/drivers/comedi/drivers/ni_atmio16d.c
+++ b/drivers/comedi/drivers/ni_atmio16d.c
@@ -698,7 +698,8 @@ static int atmio16d_attach(struct comedi_device *dev,
static void atmio16d_detach(struct comedi_device *dev)
{
- reset_atmio16d(dev);
+ if (dev->private)
+ reset_atmio16d(dev);
comedi_legacy_detach(dev);
}
diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c
index e755d54dfece..7bfb6979193c 100644
--- a/drivers/counter/rz-mtu3-cnt.c
+++ b/drivers/counter/rz-mtu3-cnt.c
@@ -107,9 +107,9 @@ static bool rz_mtu3_is_counter_invalid(struct counter_device *counter, int id)
struct rz_mtu3_cnt *const priv = counter_priv(counter);
unsigned long tmdr;
- pm_runtime_get_sync(priv->ch->dev);
+ pm_runtime_get_sync(counter->parent);
tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
- pm_runtime_put(priv->ch->dev);
+ pm_runtime_put(counter->parent);
if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr))
return false;
@@ -165,12 +165,12 @@ static int rz_mtu3_count_read(struct counter_device *counter,
if (ret)
return ret;
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
if (count->id == RZ_MTU3_32_BIT_CH)
*val = rz_mtu3_32bit_ch_read(ch, RZ_MTU3_TCNTLW);
else
*val = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TCNT);
- pm_runtime_put(ch->dev);
+ pm_runtime_put(counter->parent);
mutex_unlock(&priv->lock);
return 0;
@@ -187,26 +187,26 @@ static int rz_mtu3_count_write(struct counter_device *counter,
if (ret)
return ret;
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
if (count->id == RZ_MTU3_32_BIT_CH)
rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TCNTLW, val);
else
rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TCNT, val);
- pm_runtime_put(ch->dev);
+ pm_runtime_put(counter->parent);
mutex_unlock(&priv->lock);
return 0;
}
static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch,
- struct rz_mtu3_cnt *const priv,
+ struct counter_device *const counter,
enum counter_function *function)
{
u8 timer_mode;
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1);
- pm_runtime_put(ch->dev);
+ pm_runtime_put(counter->parent);
switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) {
case RZ_MTU3_TMDR1_PH_CNT_MODE_1:
@@ -240,7 +240,7 @@ static int rz_mtu3_count_function_read(struct counter_device *counter,
if (ret)
return ret;
- ret = rz_mtu3_count_function_read_helper(ch, priv, function);
+ ret = rz_mtu3_count_function_read_helper(ch, counter, function);
mutex_unlock(&priv->lock);
return ret;
@@ -279,9 +279,9 @@ static int rz_mtu3_count_function_write(struct counter_device *counter,
return -EINVAL;
}
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode);
- pm_runtime_put(ch->dev);
+ pm_runtime_put(counter->parent);
mutex_unlock(&priv->lock);
return 0;
@@ -300,9 +300,9 @@ static int rz_mtu3_count_direction_read(struct counter_device *counter,
if (ret)
return ret;
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
tsr = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TSR);
- pm_runtime_put(ch->dev);
+ pm_runtime_put(counter->parent);
*direction = (tsr & RZ_MTU3_TSR_TCFD) ?
COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD;
@@ -377,14 +377,14 @@ static int rz_mtu3_count_ceiling_write(struct counter_device *counter,
return -EINVAL;
}
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
if (count->id == RZ_MTU3_32_BIT_CH)
rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TGRALW, ceiling);
else
rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, ceiling);
rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA);
- pm_runtime_put(ch->dev);
+ pm_runtime_put(counter->parent);
mutex_unlock(&priv->lock);
return 0;
@@ -495,25 +495,28 @@ static int rz_mtu3_count_enable_read(struct counter_device *counter,
static int rz_mtu3_count_enable_write(struct counter_device *counter,
struct counter_count *count, u8 enable)
{
- struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id);
struct rz_mtu3_cnt *const priv = counter_priv(counter);
int ret = 0;
+ mutex_lock(&priv->lock);
+
+ if (priv->count_is_enabled[count->id] == enable)
+ goto exit;
+
if (enable) {
- mutex_lock(&priv->lock);
- pm_runtime_get_sync(ch->dev);
+ pm_runtime_get_sync(counter->parent);
ret = rz_mtu3_initialize_counter(counter, count->id);
if (ret == 0)
priv->count_is_enabled[count->id] = true;
- mutex_unlock(&priv->lock);
} else {
- mutex_lock(&priv->lock);
rz_mtu3_terminate_counter(counter, count->id);
priv->count_is_enabled[count->id] = false;
- pm_runtime_put(ch->dev);
- mutex_unlock(&priv->lock);
+ pm_runtime_put(counter->parent);
}
+exit:
+ mutex_unlock(&priv->lock);
+
return ret;
}
@@ -540,9 +543,9 @@ static int rz_mtu3_cascade_counts_enable_get(struct counter_device *counter,
if (ret)
return ret;
- pm_runtime_get_sync(priv->ch->dev);
+ pm_runtime_get_sync(counter->parent);
tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
- pm_runtime_put(priv->ch->dev);
+ pm_runtime_put(counter->parent);
*cascade_enable = test_bit(RZ_MTU3_TMDR3_LWA, &tmdr);
mutex_unlock(&priv->lock);
@@ -559,10 +562,10 @@ static int rz_mtu3_cascade_counts_enable_set(struct counter_device *counter,
if (ret)
return ret;
- pm_runtime_get_sync(priv->ch->dev);
+ pm_runtime_get_sync(counter->parent);
rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3,
RZ_MTU3_TMDR3_LWA, cascade_enable);
- pm_runtime_put(priv->ch->dev);
+ pm_runtime_put(counter->parent);
mutex_unlock(&priv->lock);
return 0;
@@ -579,9 +582,9 @@ static int rz_mtu3_ext_input_phase_clock_select_get(struct counter_device *count
if (ret)
return ret;
- pm_runtime_get_sync(priv->ch->dev);
+ pm_runtime_get_sync(counter->parent);
tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
- pm_runtime_put(priv->ch->dev);
+ pm_runtime_put(counter->parent);
*ext_input_phase_clock_select = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr);
mutex_unlock(&priv->lock);
@@ -598,11 +601,11 @@ static int rz_mtu3_ext_input_phase_clock_select_set(struct counter_device *count
if (ret)
return ret;
- pm_runtime_get_sync(priv->ch->dev);
+ pm_runtime_get_sync(counter->parent);
rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3,
RZ_MTU3_TMDR3_PHCKSEL,
ext_input_phase_clock_select);
- pm_runtime_put(priv->ch->dev);
+ pm_runtime_put(counter->parent);
mutex_unlock(&priv->lock);
return 0;
@@ -640,7 +643,7 @@ static int rz_mtu3_action_read(struct counter_device *counter,
if (ret)
return ret;
- ret = rz_mtu3_count_function_read_helper(ch, priv, &function);
+ ret = rz_mtu3_count_function_read_helper(ch, counter, &function);
if (ret) {
mutex_unlock(&priv->lock);
return ret;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 277884d91913..1f794524a1d9 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1427,12 +1427,9 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
* If there is a problem with its frequency table, take it
* offline and drop it.
*/
- if (policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_ASCENDING &&
- policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_DESCENDING) {
- ret = cpufreq_table_validate_and_sort(policy);
- if (ret)
- goto out_offline_policy;
- }
+ ret = cpufreq_table_validate_and_sort(policy);
+ if (ret)
+ goto out_offline_policy;
/* related_cpus should at least include policy->cpus. */
cpumask_copy(policy->related_cpus, policy->cpus);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index e0e847764511..df01d33993d8 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_policy *policy)
dbs_info->requested_freq = policy->cur;
}
+static void cs_limits(struct cpufreq_policy *policy)
+{
+ struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
+
+ /*
+ * The limits have changed, so may have the current frequency. Reset
+ * requested_freq to avoid any unintended outcomes due to the mismatch.
+ */
+ dbs_info->requested_freq = policy->cur;
+}
+
static struct dbs_governor cs_governor = {
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
.kobj_type = { .default_groups = cs_groups },
@@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = {
.init = cs_init,
.exit = cs_exit,
.start = cs_start,
+ .limits = cs_limits,
};
#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 36eb7aee4bcd..86f35e451914 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -468,13 +468,13 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
/* Failure, so roll back. */
pr_err("initialization failed (dbs_data kobject init error %d)\n", ret);
- kobject_put(&dbs_data->attr_set.kobj);
-
policy->governor_data = NULL;
if (!have_governor_per_policy())
gov->gdbs_data = NULL;
- gov->exit(dbs_data);
+
+ kobject_put(&dbs_data->attr_set.kobj);
+ goto free_policy_dbs_info;
free_dbs_data:
kfree(dbs_data);
@@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
{
+ struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs;
/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
@@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
mutex_lock(&policy_dbs->update_mutex);
cpufreq_policy_apply_limits(policy);
gov_update_sample_delay(policy_dbs, 0);
+ if (gov->limits)
+ gov->limits(policy);
mutex_unlock(&policy_dbs->update_mutex);
out:
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 168c23fd7fca..1462d59277bd 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -138,6 +138,7 @@ struct dbs_governor {
int (*init)(struct dbs_data *dbs_data);
void (*exit)(struct dbs_data *dbs_data);
void (*start)(struct cpufreq_policy *policy);
+ void (*limits)(struct cpufreq_policy *policy);
};
static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 7f251daf03ce..5b364d8da4f9 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -360,6 +360,10 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
if (policy_has_boost_freq(policy))
policy->boost_supported = true;
+ if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING ||
+ policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_DESCENDING)
+ return 0;
+
return set_freq_table_sorted(policy);
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index a48af3540c74..11c58af41900 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1476,13 +1476,13 @@ static void __intel_pstate_update_max_freq(struct cpufreq_policy *policy,
refresh_frequency_limits(policy);
}
-static bool intel_pstate_update_max_freq(struct cpudata *cpudata)
+static bool intel_pstate_update_max_freq(int cpu)
{
- struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
+ struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
if (!policy)
return false;
- __intel_pstate_update_max_freq(policy, cpudata);
+ __intel_pstate_update_max_freq(policy, all_cpu_data[cpu]);
return true;
}
@@ -1501,7 +1501,7 @@ static void intel_pstate_update_limits_for_all(void)
int cpu;
for_each_possible_cpu(cpu)
- intel_pstate_update_max_freq(all_cpu_data[cpu]);
+ intel_pstate_update_max_freq(cpu);
mutex_lock(&hybrid_capacity_lock);
@@ -1647,8 +1647,8 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
static void update_cpu_qos_request(int cpu, enum freq_qos_req_type type)
{
struct cpudata *cpudata = all_cpu_data[cpu];
- unsigned int freq = cpudata->pstate.turbo_freq;
struct freq_qos_request *req;
+ unsigned int freq;
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
if (!policy)
@@ -1661,6 +1661,8 @@ static void update_cpu_qos_request(int cpu, enum freq_qos_req_type type)
if (hwp_active)
intel_pstate_get_hwp_cap(cpudata);
+ freq = cpudata->pstate.turbo_freq;
+
if (type == FREQ_QOS_MIN) {
freq = DIV_ROUND_UP(freq * global.min_perf_pct, 100);
} else {
@@ -1908,7 +1910,7 @@ static void intel_pstate_notify_work(struct work_struct *work)
struct cpudata *cpudata =
container_of(to_delayed_work(work), struct cpudata, hwp_notify_work);
- if (intel_pstate_update_max_freq(cpudata)) {
+ if (intel_pstate_update_max_freq(cpudata->cpu)) {
/*
* The driver will not be unregistered while this function is
* running, so update the capacity without acquiring the driver
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 65fbb8e807b9..c7876e9e024f 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -359,16 +359,6 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev,
int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
bool *stop_tick)
{
- /*
- * If there is only a single idle state (or none), there is nothing
- * meaningful for the governor to choose. Skip the governor and
- * always use state 0 with the tick running.
- */
- if (drv->state_count <= 1) {
- *stop_tick = false;
- return 0;
- }
-
return cpuidle_curr_governor->select(drv, dev, stop_tick);
}
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 8adc7fe71c04..98d1023007e3 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -52,9 +52,10 @@ static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data,
rng->priv = 0;
} else {
work_data = kmalloc_obj(*work_data, GFP_ATOMIC);
- if (!work_data)
+ if (!work_data) {
+ atomic_dec(&i2c_priv->tfm_count);
return -ENOMEM;
-
+ }
work_data->ctx = i2c_priv;
work_data->client = i2c_priv->client;
diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c
index 167372936ca7..78964e1712e5 100644
--- a/drivers/crypto/caam/caamalg_qi2.c
+++ b/drivers/crypto/caam/caamalg_qi2.c
@@ -3326,9 +3326,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key,
if (aligned_len < keylen)
return -EOVERFLOW;
- hashed_key = kmemdup(key, aligned_len, GFP_KERNEL);
+ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
if (!hashed_key)
return -ENOMEM;
+ memcpy(hashed_key, key, keylen);
ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
if (ret)
goto bad_free_key;
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 628c43a7efc4..44122208f70c 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -441,9 +441,10 @@ static int ahash_setkey(struct crypto_ahash *ahash,
if (aligned_len < keylen)
return -EOVERFLOW;
- hashed_key = kmemdup(key, keylen, GFP_KERNEL);
+ hashed_key = kmalloc(aligned_len, GFP_KERNEL);
if (!hashed_key)
return -ENOMEM;
+ memcpy(hashed_key, key, keylen);
ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize);
if (ret)
goto bad_free_key;
diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c
index adc9542ae806..b07ae529b591 100644
--- a/drivers/crypto/ccp/sev-dev-tsm.c
+++ b/drivers/crypto/ccp/sev-dev-tsm.c
@@ -378,9 +378,9 @@ void sev_tsm_init_locked(struct sev_device *sev, void *tio_status_page)
return;
error_exit:
- kfree(t);
pr_err("Failed to enable SEV-TIO: ret=%d en=%d initdone=%d SEV=%d\n",
ret, t->tio_en, t->tio_init_done, boot_cpu_has(X86_FEATURE_SEV));
+ kfree(t);
}
void sev_tsm_uninit(struct sev_device *sev)
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 096f993974d1..aebf4dad545e 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -1105,15 +1105,12 @@ struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages)
{
struct psp_device *psp_master = psp_get_master_device();
struct snp_hv_fixed_pages_entry *entry;
- struct sev_device *sev;
unsigned int order;
struct page *page;
- if (!psp_master || !psp_master->sev_data)
+ if (!psp_master)
return NULL;
- sev = psp_master->sev_data;
-
order = get_order(PMD_SIZE * num_2mb_pages);
/*
@@ -1126,7 +1123,8 @@ struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages)
* This API uses SNP_INIT_EX to transition allocated pages to HV_Fixed
* page state, fail if SNP is already initialized.
*/
- if (sev->snp_initialized)
+ if (psp_master->sev_data &&
+ ((struct sev_device *)psp_master->sev_data)->snp_initialized)
return NULL;
/* Re-use freed pages that match the request */
@@ -1162,7 +1160,7 @@ void snp_free_hv_fixed_pages(struct page *page)
struct psp_device *psp_master = psp_get_master_device();
struct snp_hv_fixed_pages_entry *entry, *nentry;
- if (!psp_master || !psp_master->sev_data)
+ if (!psp_master)
return;
/*
@@ -2410,10 +2408,8 @@ static int sev_ioctl_do_snp_platform_status(struct sev_issue_cmd *argp)
* in Firmware state on failure. Use snp_reclaim_pages() to
* transition either case back to Hypervisor-owned state.
*/
- if (snp_reclaim_pages(__pa(data), 1, true)) {
- snp_leak_pages(__page_to_pfn(status_page), 1);
+ if (snp_reclaim_pages(__pa(data), 1, true))
return -EFAULT;
- }
}
if (ret)
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 329f60ad422e..9214bbfc868f 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -332,6 +332,13 @@ static int __init padlock_init(void)
if (!x86_match_cpu(padlock_sha_ids) || !boot_cpu_has(X86_FEATURE_PHE_EN))
return -ENODEV;
+ /*
+ * Skip family 0x07 and newer used by Zhaoxin processors,
+ * as the driver's self-tests fail on these CPUs.
+ */
+ if (c->x86 >= 0x07)
+ return -ENODEV;
+
/* Register the newly added algorithm module if on *
* VIA Nano processor, or else just do as before */
if (c->x86_model < 0x0f) {
diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c
index 0e07d0523291..9210cceb4b7b 100644
--- a/drivers/crypto/tegra/tegra-se-aes.c
+++ b/drivers/crypto/tegra/tegra-se-aes.c
@@ -529,7 +529,7 @@ static struct tegra_se_alg tegra_aes_algs[] = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-tegra",
.cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_aes_ctx),
.cra_alignmask = 0xf,
@@ -550,7 +550,7 @@ static struct tegra_se_alg tegra_aes_algs[] = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-tegra",
.cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_aes_ctx),
.cra_alignmask = 0xf,
@@ -572,7 +572,7 @@ static struct tegra_se_alg tegra_aes_algs[] = {
.cra_name = "ctr(aes)",
.cra_driver_name = "ctr-aes-tegra",
.cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = 1,
.cra_ctxsize = sizeof(struct tegra_aes_ctx),
.cra_alignmask = 0xf,
@@ -594,6 +594,7 @@ static struct tegra_se_alg tegra_aes_algs[] = {
.cra_name = "xts(aes)",
.cra_driver_name = "xts-aes-tegra",
.cra_priority = 500,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_aes_ctx),
.cra_alignmask = (__alignof__(u64) - 1),
@@ -1922,6 +1923,7 @@ static struct tegra_se_alg tegra_aead_algs[] = {
.cra_name = "gcm(aes)",
.cra_driver_name = "gcm-aes-tegra",
.cra_priority = 500,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = 1,
.cra_ctxsize = sizeof(struct tegra_aead_ctx),
.cra_alignmask = 0xf,
@@ -1944,6 +1946,7 @@ static struct tegra_se_alg tegra_aead_algs[] = {
.cra_name = "ccm(aes)",
.cra_driver_name = "ccm-aes-tegra",
.cra_priority = 500,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = 1,
.cra_ctxsize = sizeof(struct tegra_aead_ctx),
.cra_alignmask = 0xf,
@@ -1971,7 +1974,7 @@ static struct tegra_se_alg tegra_cmac_algs[] = {
.cra_name = "cmac(aes)",
.cra_driver_name = "tegra-se-cmac",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_cmac_ctx),
.cra_alignmask = 0,
diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c
index 4a298ace6e9f..06bb5bf0fa33 100644
--- a/drivers/crypto/tegra/tegra-se-hash.c
+++ b/drivers/crypto/tegra/tegra-se-hash.c
@@ -761,7 +761,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha1",
.cra_driver_name = "tegra-se-sha1",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -786,7 +786,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha224",
.cra_driver_name = "tegra-se-sha224",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -811,7 +811,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha256",
.cra_driver_name = "tegra-se-sha256",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -836,7 +836,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha384",
.cra_driver_name = "tegra-se-sha384",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -861,7 +861,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha512",
.cra_driver_name = "tegra-se-sha512",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -886,7 +886,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha3-224",
.cra_driver_name = "tegra-se-sha3-224",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA3_224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -911,7 +911,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha3-256",
.cra_driver_name = "tegra-se-sha3-256",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA3_256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -936,7 +936,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha3-384",
.cra_driver_name = "tegra-se-sha3-384",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA3_384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -961,7 +961,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "sha3-512",
.cra_driver_name = "tegra-se-sha3-512",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA3_512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -988,7 +988,8 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "hmac(sha224)",
.cra_driver_name = "tegra-se-hmac-sha224",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -1015,7 +1016,8 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "hmac(sha256)",
.cra_driver_name = "tegra-se-hmac-sha256",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -1042,7 +1044,8 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "hmac(sha384)",
.cra_driver_name = "tegra-se-hmac-sha384",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
@@ -1069,7 +1072,8 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_name = "hmac(sha512)",
.cra_driver_name = "tegra-se-hmac-sha512",
.cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct tegra_sha_ctx),
.cra_alignmask = 0,
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 4589bf11d3fe..80aeb0d556bd 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -59,6 +59,7 @@ config CXL_ACPI
tristate "CXL ACPI: Platform Support"
depends on ACPI
depends on ACPI_NUMA
+ depends on CXL_PMEM || !CXL_PMEM
default CXL_BUS
select ACPI_TABLE_LIB
select ACPI_HMAT
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 007b8aff0238..5b0570df0fd9 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -152,6 +152,24 @@ int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c);
int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
struct access_coordinate *c);
+static inline struct device *port_to_host(struct cxl_port *port)
+{
+ struct cxl_port *parent = is_cxl_root(port) ? NULL :
+ to_cxl_port(port->dev.parent);
+
+ /*
+ * The host of CXL root port and the first level of ports is
+ * the platform firmware device, the host of all other ports
+ * is their parent port.
+ */
+ if (!parent)
+ return port->uport_dev;
+ else if (is_cxl_root(parent))
+ return parent->uport_dev;
+ else
+ return &parent->dev;
+}
+
static inline struct device *dport_to_host(struct cxl_dport *dport)
{
struct cxl_port *port = dport->port;
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index e3f0c39e6812..cb5d5a047a9d 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -94,7 +94,6 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
struct cxl_hdm *cxlhdm;
void __iomem *hdm;
u32 ctrl;
- int i;
if (!info)
return false;
@@ -113,22 +112,16 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
return false;
/*
- * If any decoders are committed already, there should not be any
- * emulated DVSEC decoders.
+ * If HDM decoders are globally enabled, do not fall back to DVSEC
+ * range emulation. Zeroed decoder registers after region teardown
+ * do not imply absence of HDM capability.
+ *
+ * Falling back to DVSEC here would treat the decoder as AUTO and
+ * may incorrectly latch default interleave settings.
*/
- for (i = 0; i < cxlhdm->decoder_count; i++) {
- ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
- dev_dbg(&info->port->dev,
- "decoder%d.%d: committed: %ld base: %#x_%.8x size: %#x_%.8x\n",
- info->port->id, i,
- FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl),
- readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i)),
- readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(i)),
- readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i)),
- readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i)));
- if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
- return false;
- }
+ ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
+ if (ctrl & CXL_HDM_DECODER_ENABLE)
+ return false;
return true;
}
@@ -904,7 +897,7 @@ static void cxl_decoder_reset(struct cxl_decoder *cxld)
if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
return;
- if (test_bit(CXL_DECODER_F_LOCK, &cxld->flags))
+ if (cxld->flags & CXL_DECODER_F_LOCK)
return;
if (port->commit_end == id)
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index fa6dd0c94656..12386d912705 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -311,6 +311,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
* cxl_payload_from_user_allowed() - Check contents of in_payload.
* @opcode: The mailbox command opcode.
* @payload_in: Pointer to the input payload passed in from user space.
+ * @in_size: Size of @payload_in in bytes.
*
* Return:
* * true - payload_in passes check for @opcode.
@@ -325,12 +326,15 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
*
* The specific checks are determined by the opcode.
*/
-static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in)
+static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in,
+ size_t in_size)
{
switch (opcode) {
case CXL_MBOX_OP_SET_PARTITION_INFO: {
struct cxl_mbox_set_partition_info *pi = payload_in;
+ if (in_size < sizeof(*pi))
+ return false;
if (pi->flags & CXL_SET_PARTITION_IMMEDIATE_FLAG)
return false;
break;
@@ -338,6 +342,8 @@ static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in)
case CXL_MBOX_OP_CLEAR_LOG: {
const uuid_t *uuid = (uuid_t *)payload_in;
+ if (in_size < sizeof(uuid_t))
+ return false;
/*
* Restrict the ‘Clear log’ action to only apply to
* Vendor debug logs.
@@ -365,7 +371,8 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox_cmd,
if (IS_ERR(mbox_cmd->payload_in))
return PTR_ERR(mbox_cmd->payload_in);
- if (!cxl_payload_from_user_allowed(opcode, mbox_cmd->payload_in)) {
+ if (!cxl_payload_from_user_allowed(opcode, mbox_cmd->payload_in,
+ in_size)) {
dev_dbg(cxl_mbox->host, "%s: input payload not allowed\n",
cxl_mem_opcode_to_name(opcode));
kvfree(mbox_cmd->payload_in);
@@ -1294,7 +1301,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
* Require an endpoint to be safe otherwise the driver can not
* be sure that the device is unmapped.
*/
- if (endpoint && cxl_num_decoders_committed(endpoint) == 0)
+ if (cxlmd->dev.driver && cxl_num_decoders_committed(endpoint) == 0)
return __cxl_mem_sanitize(mds, cmd);
return -EBUSY;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index f547d8ac34c7..273c22118d3d 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -1089,10 +1089,8 @@ static int cxlmd_add(struct cxl_memdev *cxlmd, struct cxl_dev_state *cxlds)
DEFINE_FREE(put_cxlmd, struct cxl_memdev *,
if (!IS_ERR_OR_NULL(_T)) put_device(&_T->dev))
-static struct cxl_memdev *cxl_memdev_autoremove(struct cxl_memdev *cxlmd)
+static bool cxl_memdev_attach_failed(struct cxl_memdev *cxlmd)
{
- int rc;
-
/*
* If @attach is provided fail if the driver is not attached upon
* return. Note that failure here could be the result of a race to
@@ -1100,7 +1098,14 @@ static struct cxl_memdev *cxl_memdev_autoremove(struct cxl_memdev *cxlmd)
* succeeded and then cxl_mem unbound before the lock is acquired.
*/
guard(device)(&cxlmd->dev);
- if (cxlmd->attach && !cxlmd->dev.driver) {
+ return (cxlmd->attach && !cxlmd->dev.driver);
+}
+
+static struct cxl_memdev *cxl_memdev_autoremove(struct cxl_memdev *cxlmd)
+{
+ int rc;
+
+ if (cxl_memdev_attach_failed(cxlmd)) {
cxl_memdev_unregister(cxlmd);
return ERR_PTR(-ENXIO);
}
diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c
index 3c6e76721522..68462e38a977 100644
--- a/drivers/cxl/core/pmem.c
+++ b/drivers/cxl/core/pmem.c
@@ -115,15 +115,17 @@ static void unregister_nvb(void *_cxl_nvb)
device_unregister(&cxl_nvb->dev);
}
-/**
- * devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology
- * @host: platform firmware root device
- * @port: CXL port at the root of a CXL topology
- *
- * Return: bridge device that can host cxl_nvdimm objects
- */
-struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
- struct cxl_port *port)
+static bool cxl_nvdimm_bridge_failed_attach(struct cxl_nvdimm_bridge *cxl_nvb)
+{
+ struct device *dev = &cxl_nvb->dev;
+
+ guard(device)(dev);
+ /* If the device has no driver, then it failed to attach. */
+ return dev->driver == NULL;
+}
+
+struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,
+ struct cxl_port *port)
{
struct cxl_nvdimm_bridge *cxl_nvb;
struct device *dev;
@@ -145,6 +147,11 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
if (rc)
goto err;
+ if (cxl_nvdimm_bridge_failed_attach(cxl_nvb)) {
+ unregister_nvb(cxl_nvb);
+ return ERR_PTR(-ENODEV);
+ }
+
rc = devm_add_action_or_reset(host, unregister_nvb, cxl_nvb);
if (rc)
return ERR_PTR(rc);
@@ -155,7 +162,7 @@ err:
put_device(dev);
return ERR_PTR(rc);
}
-EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, "CXL");
+EXPORT_SYMBOL_FOR_MODULES(__devm_cxl_add_nvdimm_bridge, "cxl_pmem");
static void cxl_nvdimm_release(struct device *dev)
{
@@ -255,6 +262,21 @@ int devm_cxl_add_nvdimm(struct device *host, struct cxl_port *port,
if (!cxl_nvb)
return -ENODEV;
+ /*
+ * Take the uport_dev lock to guard against race of nvdimm_bus object.
+ * cxl_acpi_probe() registers the nvdimm_bus and is done under the
+ * root port uport_dev lock.
+ *
+ * Take the cxl_nvb device lock to ensure that cxl_nvb driver is in a
+ * consistent state. And the driver registers nvdimm_bus.
+ */
+ guard(device)(cxl_nvb->port->uport_dev);
+ guard(device)(&cxl_nvb->dev);
+ if (!cxl_nvb->nvdimm_bus) {
+ rc = -ENODEV;
+ goto err_alloc;
+ }
+
cxl_nvd = cxl_nvdimm_alloc(cxl_nvb, cxlmd);
if (IS_ERR(cxl_nvd)) {
rc = PTR_ERR(cxl_nvd);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index b69c2529744c..c5aacd7054f1 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -552,10 +552,13 @@ static void cxl_port_release(struct device *dev)
xa_destroy(&port->dports);
xa_destroy(&port->regions);
ida_free(&cxl_port_ida, port->id);
- if (is_cxl_root(port))
+
+ if (is_cxl_root(port)) {
kfree(to_cxl_root(port));
- else
+ } else {
+ put_device(dev->parent);
kfree(port);
+ }
}
static ssize_t decoders_committed_show(struct device *dev,
@@ -615,22 +618,8 @@ struct cxl_port *parent_port_of(struct cxl_port *port)
static void unregister_port(void *_port)
{
struct cxl_port *port = _port;
- struct cxl_port *parent = parent_port_of(port);
- struct device *lock_dev;
-
- /*
- * CXL root port's and the first level of ports are unregistered
- * under the platform firmware device lock, all other ports are
- * unregistered while holding their parent port lock.
- */
- if (!parent)
- lock_dev = port->uport_dev;
- else if (is_cxl_root(parent))
- lock_dev = parent->uport_dev;
- else
- lock_dev = &parent->dev;
- device_lock_assert(lock_dev);
+ device_lock_assert(port_to_host(port));
port->dead = true;
device_unregister(&port->dev);
}
@@ -721,6 +710,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
struct cxl_port *iter;
dev->parent = &parent_port->dev;
+ get_device(dev->parent);
port->depth = parent_port->depth + 1;
port->parent_dport = parent_dport;
@@ -1427,20 +1417,11 @@ static struct device *grandparent(struct device *dev)
return NULL;
}
-static struct device *endpoint_host(struct cxl_port *endpoint)
-{
- struct cxl_port *port = to_cxl_port(endpoint->dev.parent);
-
- if (is_cxl_root(port))
- return port->uport_dev;
- return &port->dev;
-}
-
static void delete_endpoint(void *data)
{
struct cxl_memdev *cxlmd = data;
struct cxl_port *endpoint = cxlmd->endpoint;
- struct device *host = endpoint_host(endpoint);
+ struct device *host = port_to_host(endpoint);
scoped_guard(device, host) {
if (host->driver && !endpoint->dead) {
@@ -1456,7 +1437,7 @@ static void delete_endpoint(void *data)
int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint)
{
- struct device *host = endpoint_host(endpoint);
+ struct device *host = port_to_host(endpoint);
struct device *dev = &cxlmd->dev;
get_device(host);
@@ -1790,7 +1771,16 @@ static struct cxl_dport *find_or_add_dport(struct cxl_port *port,
{
struct cxl_dport *dport;
- device_lock_assert(&port->dev);
+ /*
+ * The port is already visible in CXL hierarchy, but it may still
+ * be in the process of binding to the CXL port driver at this point.
+ *
+ * port creation and driver binding are protected by the port's host
+ * lock, so acquire the host lock here to ensure the port has completed
+ * driver binding before proceeding with dport addition.
+ */
+ guard(device)(port_to_host(port));
+ guard(device)(&port->dev);
dport = cxl_find_dport_by_dev(port, dport_dev);
if (!dport) {
dport = probe_dport(port, dport_dev);
@@ -1857,13 +1847,11 @@ retry:
* RP port enumerated by cxl_acpi without dport will
* have the dport added here.
*/
- scoped_guard(device, &port->dev) {
- dport = find_or_add_dport(port, dport_dev);
- if (IS_ERR(dport)) {
- if (PTR_ERR(dport) == -EAGAIN)
- goto retry;
- return PTR_ERR(dport);
- }
+ dport = find_or_add_dport(port, dport_dev);
+ if (IS_ERR(dport)) {
+ if (PTR_ERR(dport) == -EAGAIN)
+ goto retry;
+ return PTR_ERR(dport);
}
rc = cxl_add_ep(dport, &cxlmd->dev);
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index fec37af1dfbf..c37ae0b28bbb 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1100,12 +1100,12 @@ static int cxl_rr_assign_decoder(struct cxl_port *port, struct cxl_region *cxlr,
static void cxl_region_setup_flags(struct cxl_region *cxlr,
struct cxl_decoder *cxld)
{
- if (test_bit(CXL_DECODER_F_LOCK, &cxld->flags)) {
+ if (cxld->flags & CXL_DECODER_F_LOCK) {
set_bit(CXL_REGION_F_LOCK, &cxlr->flags);
clear_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags);
}
- if (test_bit(CXL_DECODER_F_NORMALIZED_ADDRESSING, &cxld->flags))
+ if (cxld->flags & CXL_DECODER_F_NORMALIZED_ADDRESSING)
set_bit(CXL_REGION_F_NORMALIZED_ADDRESSING, &cxlr->flags);
}
@@ -3854,8 +3854,10 @@ static int __construct_region(struct cxl_region *cxlr,
}
rc = sysfs_update_group(&cxlr->dev.kobj, &cxl_region_group);
- if (rc)
+ if (rc) {
+ kfree(res);
return rc;
+ }
rc = insert_resource(cxlrd->res, res);
if (rc) {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 04c673e7cdb0..9b947286eb9b 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -574,11 +574,16 @@ struct cxl_nvdimm_bridge {
#define CXL_DEV_ID_LEN 19
+enum {
+ CXL_NVD_F_INVALIDATED = 0,
+};
+
struct cxl_nvdimm {
struct device dev;
struct cxl_memdev *cxlmd;
u8 dev_id[CXL_DEV_ID_LEN]; /* for nvdimm, string of 'serial' */
u64 dirty_shutdowns;
+ unsigned long flags;
};
struct cxl_pmem_region_mapping {
@@ -920,6 +925,8 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev);
struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
struct cxl_port *port);
+struct cxl_nvdimm_bridge *__devm_cxl_add_nvdimm_bridge(struct device *host,
+ struct cxl_port *port);
struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm(struct device *dev);
int devm_cxl_add_nvdimm(struct device *host, struct cxl_port *port,
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index 6a97e4e490b6..261dff7ced9f 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -13,6 +13,20 @@
static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
+/**
+ * devm_cxl_add_nvdimm_bridge() - add the root of a LIBNVDIMM topology
+ * @host: platform firmware root device
+ * @port: CXL port at the root of a CXL topology
+ *
+ * Return: bridge device that can host cxl_nvdimm objects
+ */
+struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
+ struct cxl_port *port)
+{
+ return __devm_cxl_add_nvdimm_bridge(host, port);
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, "CXL");
+
static void clear_exclusive(void *mds)
{
clear_exclusive_cxl_commands(mds, exclusive_cmds);
@@ -129,6 +143,9 @@ static int cxl_nvdimm_probe(struct device *dev)
struct nvdimm *nvdimm;
int rc;
+ if (test_bit(CXL_NVD_F_INVALIDATED, &cxl_nvd->flags))
+ return -EBUSY;
+
set_exclusive_cxl_commands(mds, exclusive_cmds);
rc = devm_add_action_or_reset(dev, clear_exclusive, mds);
if (rc)
@@ -309,8 +326,10 @@ static int detach_nvdimm(struct device *dev, void *data)
scoped_guard(device, dev) {
if (dev->driver) {
cxl_nvd = to_cxl_nvdimm(dev);
- if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data)
+ if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data) {
release = true;
+ set_bit(CXL_NVD_F_INVALIDATED, &cxl_nvd->flags);
+ }
}
}
if (release)
@@ -353,6 +372,7 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = {
.probe = cxl_nvdimm_bridge_probe,
.id = CXL_DEVICE_NVDIMM_BRIDGE,
.drv = {
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
.suppress_bind_attrs = true,
},
};
@@ -534,7 +554,7 @@ static __exit void cxl_pmem_exit(void)
MODULE_DESCRIPTION("CXL PMEM: Persistent Memory Support");
MODULE_LICENSE("GPL v2");
-module_init(cxl_pmem_init);
+subsys_initcall(cxl_pmem_init);
module_exit(cxl_pmem_exit);
MODULE_IMPORT_NS("CXL");
MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE);
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index e7d698b352d3..5397dbda4f72 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -844,6 +844,7 @@ static int dw_edma_irq_request(struct dw_edma *dw,
{
struct dw_edma_chip *chip = dw->chip;
struct device *dev = dw->chip->dev;
+ struct msi_desc *msi_desc;
u32 wr_mask = 1;
u32 rd_mask = 1;
int i, err = 0;
@@ -895,9 +896,12 @@ static int dw_edma_irq_request(struct dw_edma *dw,
&dw->irq[i]);
if (err)
goto err_irq_free;
-
- if (irq_get_msi_desc(irq))
+ msi_desc = irq_get_msi_desc(irq);
+ if (msi_desc) {
get_cached_msi_msg(irq, &dw->irq[i].msi);
+ if (!msi_desc->pci.msi_attrib.is_msix)
+ dw->irq[i].msi.data = dw->irq[0].msi.data + i;
+ }
}
dw->nr_irqs = i;
diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c
index e3f8db4fe909..ce8f7254bab2 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c
@@ -252,10 +252,10 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
lower_32_bits(chunk->ll_region.paddr));
SET_CH_32(dw, chan->dir, chan->id, llp.msb,
upper_32_bits(chunk->ll_region.paddr));
+ /* Set consumer cycle */
+ SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
+ HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
}
- /* Set consumer cycle */
- SET_CH_32(dw, chan->dir, chan->id, cycle_sync,
- HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT);
dw_hdma_v0_sync_ll_data(chunk);
diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
index dbcdd1e68319..b596baa0a182 100644
--- a/drivers/dma/fsl-edma-main.c
+++ b/drivers/dma/fsl-edma-main.c
@@ -317,10 +317,8 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
return NULL;
i = fsl_chan - fsl_edma->chans;
- fsl_chan->priority = dma_spec->args[1];
- fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
- fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
- fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
+ if (!b_chmux && i != dma_spec->args[0])
+ continue;
if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1))
continue;
@@ -328,17 +326,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
continue;
- if (!b_chmux && i == dma_spec->args[0]) {
- chan = dma_get_slave_channel(chan);
- chan->device->privatecnt++;
- return chan;
- } else if (b_chmux && !fsl_chan->srcid) {
- /* if controller support channel mux, choose a free channel */
- chan = dma_get_slave_channel(chan);
- chan->device->privatecnt++;
- fsl_chan->srcid = dma_spec->args[0];
- return chan;
- }
+ fsl_chan->srcid = dma_spec->args[0];
+ fsl_chan->priority = dma_spec->args[1];
+ fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
+ fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
+ fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
+
+ chan = dma_get_slave_channel(chan);
+ chan->device->privatecnt++;
+ return chan;
}
return NULL;
}
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index c37d233535f9..0366c7cf3502 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -158,11 +158,7 @@ static const struct device_type idxd_cdev_file_type = {
static void idxd_cdev_dev_release(struct device *dev)
{
struct idxd_cdev *idxd_cdev = dev_to_cdev(dev);
- struct idxd_cdev_context *cdev_ctx;
- struct idxd_wq *wq = idxd_cdev->wq;
- cdev_ctx = &ictx[wq->idxd->data->type];
- ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor);
kfree(idxd_cdev);
}
@@ -582,11 +578,15 @@ int idxd_wq_add_cdev(struct idxd_wq *wq)
void idxd_wq_del_cdev(struct idxd_wq *wq)
{
+ struct idxd_cdev_context *cdev_ctx;
struct idxd_cdev *idxd_cdev;
idxd_cdev = wq->idxd_cdev;
wq->idxd_cdev = NULL;
cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev));
+
+ cdev_ctx = &ictx[wq->idxd->data->type];
+ ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor);
put_device(cdev_dev(idxd_cdev));
}
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index c26128529ff4..131138483b87 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -175,6 +175,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq)
free_descs(wq);
dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
sbitmap_queue_free(&wq->sbq);
+ wq->type = IDXD_WQT_NONE;
}
EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD");
@@ -382,7 +383,6 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)
lockdep_assert_held(&wq->wq_lock);
wq->state = IDXD_WQ_DISABLED;
memset(wq->wqcfg, 0, idxd->wqcfg_size);
- wq->type = IDXD_WQT_NONE;
wq->threshold = 0;
wq->priority = 0;
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
@@ -831,8 +831,7 @@ static void idxd_device_evl_free(struct idxd_device *idxd)
struct device *dev = &idxd->pdev->dev;
struct idxd_evl *evl = idxd->evl;
- gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
- if (!gencfg.evl_en)
+ if (!evl)
return;
mutex_lock(&evl->lock);
@@ -1125,7 +1124,11 @@ int idxd_device_config(struct idxd_device *idxd)
{
int rc;
- lockdep_assert_held(&idxd->dev_lock);
+ guard(spinlock)(&idxd->dev_lock);
+
+ if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
+ return 0;
+
rc = idxd_wqs_setup(idxd);
if (rc < 0)
return rc;
@@ -1332,6 +1335,11 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
free_irq(ie->vector, ie);
idxd_flush_pending_descs(ie);
+
+ /* The interrupt might have been already released by FLR */
+ if (ie->int_handle == INVALID_INT_HANDLE)
+ return;
+
if (idxd->request_int_handles)
idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
idxd_device_clear_perm_entry(idxd, ie);
@@ -1340,6 +1348,23 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
ie->pasid = IOMMU_PASID_INVALID;
}
+void idxd_wq_flush_descs(struct idxd_wq *wq)
+{
+ struct idxd_irq_entry *ie = &wq->ie;
+ struct idxd_device *idxd = wq->idxd;
+
+ guard(mutex)(&wq->wq_lock);
+
+ if (wq->state != IDXD_WQ_ENABLED || wq->type != IDXD_WQT_KERNEL)
+ return;
+
+ idxd_flush_pending_descs(ie);
+ if (idxd->request_int_handles)
+ idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
+ idxd_device_clear_perm_entry(idxd, ie);
+ ie->int_handle = INVALID_INT_HANDLE;
+}
+
int idxd_wq_request_irq(struct idxd_wq *wq)
{
struct idxd_device *idxd = wq->idxd;
@@ -1454,11 +1479,7 @@ int idxd_drv_enable_wq(struct idxd_wq *wq)
}
}
- rc = 0;
- spin_lock(&idxd->dev_lock);
- if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
- rc = idxd_device_config(idxd);
- spin_unlock(&idxd->dev_lock);
+ rc = idxd_device_config(idxd);
if (rc < 0) {
dev_dbg(dev, "Writing wq %d config failed: %d\n", wq->id, rc);
goto err;
@@ -1533,7 +1554,6 @@ void idxd_drv_disable_wq(struct idxd_wq *wq)
idxd_wq_reset(wq);
idxd_wq_free_resources(wq);
percpu_ref_exit(&wq->wq_active);
- wq->type = IDXD_WQT_NONE;
wq->client_count = 0;
}
EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD");
@@ -1554,10 +1574,7 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev)
}
/* Device configuration */
- spin_lock(&idxd->dev_lock);
- if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
- rc = idxd_device_config(idxd);
- spin_unlock(&idxd->dev_lock);
+ rc = idxd_device_config(idxd);
if (rc < 0)
return -ENXIO;
diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c
index dbecd699237e..9937b671f637 100644
--- a/drivers/dma/idxd/dma.c
+++ b/drivers/dma/idxd/dma.c
@@ -194,6 +194,22 @@ static void idxd_dma_release(struct dma_device *device)
kfree(idxd_dma);
}
+static int idxd_dma_terminate_all(struct dma_chan *c)
+{
+ struct idxd_wq *wq = to_idxd_wq(c);
+
+ idxd_wq_flush_descs(wq);
+
+ return 0;
+}
+
+static void idxd_dma_synchronize(struct dma_chan *c)
+{
+ struct idxd_wq *wq = to_idxd_wq(c);
+
+ idxd_wq_drain(wq);
+}
+
int idxd_register_dma_device(struct idxd_device *idxd)
{
struct idxd_dma_dev *idxd_dma;
@@ -224,6 +240,8 @@ int idxd_register_dma_device(struct idxd_device *idxd)
dma->device_issue_pending = idxd_dma_issue_pending;
dma->device_alloc_chan_resources = idxd_dma_alloc_chan_resources;
dma->device_free_chan_resources = idxd_dma_free_chan_resources;
+ dma->device_terminate_all = idxd_dma_terminate_all;
+ dma->device_synchronize = idxd_dma_synchronize;
rc = dma_async_device_register(dma);
if (rc < 0) {
diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
index ea8c4daed38d..ce78b9a7c641 100644
--- a/drivers/dma/idxd/idxd.h
+++ b/drivers/dma/idxd/idxd.h
@@ -803,6 +803,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq);
int idxd_wq_init_percpu_ref(struct idxd_wq *wq);
void idxd_wq_free_irq(struct idxd_wq *wq);
int idxd_wq_request_irq(struct idxd_wq *wq);
+void idxd_wq_flush_descs(struct idxd_wq *wq);
/* submission */
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc);
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index fb80803d5b57..f1cfc7790d95 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -973,7 +973,8 @@ static void idxd_device_config_restore(struct idxd_device *idxd,
idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit;
- idxd->evl->size = saved_evl->size;
+ if (idxd->evl)
+ idxd->evl->size = saved_evl->size;
for (i = 0; i < idxd->max_groups; i++) {
struct idxd_group *saved_group, *group;
@@ -1104,12 +1105,10 @@ static void idxd_reset_done(struct pci_dev *pdev)
idxd_device_config_restore(idxd, idxd->idxd_saved);
/* Re-configure IDXD device if allowed. */
- if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
- rc = idxd_device_config(idxd);
- if (rc < 0) {
- dev_err(dev, "HALT: %s config fails\n", idxd_name);
- goto out;
- }
+ rc = idxd_device_config(idxd);
+ if (rc < 0) {
+ dev_err(dev, "HALT: %s config fails\n", idxd_name);
+ goto out;
}
/* Bind IDXD device to driver. */
@@ -1147,6 +1146,7 @@ static void idxd_reset_done(struct pci_dev *pdev)
}
out:
kfree(idxd->idxd_saved);
+ idxd->idxd_saved = NULL;
}
static const struct pci_error_handlers idxd_error_handler = {
diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
index 7782f8c51c32..6a25e1fd0e62 100644
--- a/drivers/dma/idxd/irq.c
+++ b/drivers/dma/idxd/irq.c
@@ -397,6 +397,17 @@ static void idxd_device_flr(struct work_struct *work)
dev_err(&idxd->pdev->dev, "FLR failed\n");
}
+static void idxd_wqs_flush_descs(struct idxd_device *idxd)
+{
+ int i;
+
+ for (i = 0; i < idxd->max_wqs; i++) {
+ struct idxd_wq *wq = idxd->wqs[i];
+
+ idxd_wq_flush_descs(wq);
+ }
+}
+
static irqreturn_t idxd_halt(struct idxd_device *idxd)
{
union gensts_reg gensts;
@@ -415,6 +426,11 @@ static irqreturn_t idxd_halt(struct idxd_device *idxd)
} else if (gensts.reset_type == IDXD_DEVICE_RESET_FLR) {
idxd->state = IDXD_DEV_HALTED;
idxd_mask_error_interrupts(idxd);
+ /* Flush all pending descriptors, and disable
+ * interrupts, they will be re-enabled when FLR
+ * concludes.
+ */
+ idxd_wqs_flush_descs(idxd);
dev_dbg(&idxd->pdev->dev,
"idxd halted, doing FLR. After FLR, configs are restored\n");
INIT_WORK(&idxd->work, idxd_device_flr);
diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c
index 6db1c5fcedc5..03217041b8b3 100644
--- a/drivers/dma/idxd/submit.c
+++ b/drivers/dma/idxd/submit.c
@@ -138,7 +138,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
*/
list_for_each_entry_safe(d, t, &flist, list) {
list_del_init(&d->list);
- idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, true,
+ idxd_dma_complete_txd(d, IDXD_COMPLETE_ABORT, true,
NULL, NULL);
}
}
diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
index cc2c83d7f710..6d251095c350 100644
--- a/drivers/dma/idxd/sysfs.c
+++ b/drivers/dma/idxd/sysfs.c
@@ -1836,6 +1836,7 @@ static void idxd_conf_device_release(struct device *dev)
{
struct idxd_device *idxd = confdev_to_idxd(dev);
+ destroy_workqueue(idxd->wq);
kfree(idxd->groups);
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index d84ca551b2bf..f30bdf69c740 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -10,6 +10,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
@@ -296,13 +297,10 @@ static void rz_dmac_disable_hw(struct rz_dmac_chan *channel)
{
struct dma_chan *chan = &channel->vc.chan;
struct rz_dmac *dmac = to_rz_dmac(chan->device);
- unsigned long flags;
dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index);
- local_irq_save(flags);
rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
- local_irq_restore(flags);
}
static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars)
@@ -447,6 +445,7 @@ static int rz_dmac_alloc_chan_resources(struct dma_chan *chan)
if (!desc)
break;
+ /* No need to lock. This is called only for the 1st client. */
list_add_tail(&desc->node, &channel->ld_free);
channel->descs_allocated++;
}
@@ -502,18 +501,21 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
dev_dbg(dmac->dev, "%s channel: %d src=0x%pad dst=0x%pad len=%zu\n",
__func__, channel->index, &src, &dest, len);
- if (list_empty(&channel->ld_free))
- return NULL;
+ scoped_guard(spinlock_irqsave, &channel->vc.lock) {
+ if (list_empty(&channel->ld_free))
+ return NULL;
- desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
+ desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
- desc->type = RZ_DMAC_DESC_MEMCPY;
- desc->src = src;
- desc->dest = dest;
- desc->len = len;
- desc->direction = DMA_MEM_TO_MEM;
+ desc->type = RZ_DMAC_DESC_MEMCPY;
+ desc->src = src;
+ desc->dest = dest;
+ desc->len = len;
+ desc->direction = DMA_MEM_TO_MEM;
+
+ list_move_tail(channel->ld_free.next, &channel->ld_queue);
+ }
- list_move_tail(channel->ld_free.next, &channel->ld_queue);
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
}
@@ -529,27 +531,29 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
int dma_length = 0;
int i = 0;
- if (list_empty(&channel->ld_free))
- return NULL;
+ scoped_guard(spinlock_irqsave, &channel->vc.lock) {
+ if (list_empty(&channel->ld_free))
+ return NULL;
- desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
+ desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node);
- for_each_sg(sgl, sg, sg_len, i) {
- dma_length += sg_dma_len(sg);
- }
+ for_each_sg(sgl, sg, sg_len, i)
+ dma_length += sg_dma_len(sg);
- desc->type = RZ_DMAC_DESC_SLAVE_SG;
- desc->sg = sgl;
- desc->sgcount = sg_len;
- desc->len = dma_length;
- desc->direction = direction;
+ desc->type = RZ_DMAC_DESC_SLAVE_SG;
+ desc->sg = sgl;
+ desc->sgcount = sg_len;
+ desc->len = dma_length;
+ desc->direction = direction;
- if (direction == DMA_DEV_TO_MEM)
- desc->src = channel->src_per_address;
- else
- desc->dest = channel->dst_per_address;
+ if (direction == DMA_DEV_TO_MEM)
+ desc->src = channel->src_per_address;
+ else
+ desc->dest = channel->dst_per_address;
+
+ list_move_tail(channel->ld_free.next, &channel->ld_queue);
+ }
- list_move_tail(channel->ld_free.next, &channel->ld_queue);
return vchan_tx_prep(&channel->vc, &desc->vd, flags);
}
@@ -561,8 +565,8 @@ static int rz_dmac_terminate_all(struct dma_chan *chan)
unsigned int i;
LIST_HEAD(head);
- rz_dmac_disable_hw(channel);
spin_lock_irqsave(&channel->vc.lock, flags);
+ rz_dmac_disable_hw(channel);
for (i = 0; i < DMAC_NR_LMDESC; i++)
lmdesc[i].header = 0;
@@ -699,7 +703,9 @@ static void rz_dmac_irq_handle_channel(struct rz_dmac_chan *channel)
if (chstat & CHSTAT_ER) {
dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n",
channel->index, chstat);
- rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
+
+ scoped_guard(spinlock_irqsave, &channel->vc.lock)
+ rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1);
goto done;
}
diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c
index d02a4dac2291..782a55edc55b 100644
--- a/drivers/dma/xilinx/xdma.c
+++ b/drivers/dma/xilinx/xdma.c
@@ -1234,8 +1234,8 @@ static int xdma_probe(struct platform_device *pdev)
xdev->rmap = devm_regmap_init_mmio(&pdev->dev, reg_base,
&xdma_regmap_config);
- if (!xdev->rmap) {
- xdma_err(xdev, "config regmap failed: %d", ret);
+ if (IS_ERR(xdev->rmap)) {
+ xdma_err(xdev, "config regmap failed: %pe", xdev->rmap);
goto failed;
}
INIT_LIST_HEAD(&xdev->dma_dev.channels);
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index b53292e02448..e3a18ee42aa2 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -997,16 +997,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
struct xilinx_cdma_tx_segment,
node);
cdma_hw = &cdma_seg->hw;
- residue += (cdma_hw->control - cdma_hw->status) &
- chan->xdev->max_buffer_len;
+ residue += (cdma_hw->control & chan->xdev->max_buffer_len) -
+ (cdma_hw->status & chan->xdev->max_buffer_len);
} else if (chan->xdev->dma_config->dmatype ==
XDMA_TYPE_AXIDMA) {
axidma_seg = list_entry(entry,
struct xilinx_axidma_tx_segment,
node);
axidma_hw = &axidma_seg->hw;
- residue += (axidma_hw->control - axidma_hw->status) &
- chan->xdev->max_buffer_len;
+ residue += (axidma_hw->control & chan->xdev->max_buffer_len) -
+ (axidma_hw->status & chan->xdev->max_buffer_len);
} else {
aximcdma_seg =
list_entry(entry,
@@ -1014,8 +1014,8 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
node);
aximcdma_hw = &aximcdma_seg->hw;
residue +=
- (aximcdma_hw->control - aximcdma_hw->status) &
- chan->xdev->max_buffer_len;
+ (aximcdma_hw->control & chan->xdev->max_buffer_len) -
+ (aximcdma_hw->status & chan->xdev->max_buffer_len);
}
}
@@ -1235,14 +1235,6 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
dma_cookie_init(dchan);
- if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
- /* For AXI DMA resetting once channel will reset the
- * other channel as well so enable the interrupts here.
- */
- dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
- XILINX_DMA_DMAXR_ALL_IRQ_MASK);
- }
-
if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg)
dma_ctrl_set(chan, XILINX_DMA_REG_DMACR,
XILINX_CDMA_CR_SGMODE);
@@ -1564,8 +1556,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
if (chan->err)
return;
- if (list_empty(&chan->pending_list))
+ if (list_empty(&chan->pending_list)) {
+ if (chan->cyclic) {
+ struct xilinx_dma_tx_descriptor *desc;
+ struct list_head *entry;
+
+ desc = list_last_entry(&chan->done_list,
+ struct xilinx_dma_tx_descriptor, node);
+ list_for_each(entry, &desc->segments) {
+ struct xilinx_axidma_tx_segment *axidma_seg;
+ struct xilinx_axidma_desc_hw *axidma_hw;
+ axidma_seg = list_entry(entry,
+ struct xilinx_axidma_tx_segment,
+ node);
+ axidma_hw = &axidma_seg->hw;
+ axidma_hw->status = 0;
+ }
+
+ list_splice_tail_init(&chan->done_list, &chan->active_list);
+ chan->desc_pendingcount = 0;
+ chan->idle = false;
+ }
return;
+ }
if (!chan->idle)
return;
@@ -1591,6 +1604,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
head_desc->async_tx.phys);
reg &= ~XILINX_DMA_CR_DELAY_MAX;
reg |= chan->irq_delay << XILINX_DMA_CR_DELAY_SHIFT;
+ reg |= XILINX_DMA_DMAXR_ALL_IRQ_MASK;
dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
xilinx_dma_start(chan);
@@ -3024,7 +3038,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
return -EINVAL;
}
- xdev->common.directions |= chan->direction;
+ xdev->common.directions |= BIT(chan->direction);
/* Request the interrupt */
chan->irq = of_irq_get(node, chan->tdest);
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index 63bd97181b9e..37f3c33570ee 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -981,11 +981,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
}
/* Add devres action to release DPLL related resources */
- rc = devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev);
- if (rc)
- goto error;
-
- return 0;
+ return devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev);
error:
zl3073x_dev_dpll_fini(zldev);
@@ -1026,6 +1022,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
"Unknown or non-match chip ID: 0x%0x\n",
id);
}
+ zldev->chip_id = id;
/* Read revision, firmware version and custom config version */
rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index dddfcacea5c0..fd2af3c62a7d 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -35,6 +35,7 @@ struct zl3073x_dpll;
* @dev: pointer to device
* @regmap: regmap to access device registers
* @multiop_lock: to serialize multiple register operations
+ * @chip_id: chip ID read from hardware
* @ref: array of input references' invariants
* @out: array of outs' invariants
* @synth: array of synths' invariants
@@ -48,6 +49,7 @@ struct zl3073x_dev {
struct device *dev;
struct regmap *regmap;
struct mutex multiop_lock;
+ u16 chip_id;
/* Invariants */
struct zl3073x_ref ref[ZL3073X_NUM_REFS];
@@ -144,6 +146,32 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
+/**
+ * zl3073x_dev_is_ref_phase_comp_32bit - check ref phase comp register size
+ * @zldev: pointer to zl3073x device
+ *
+ * Some chip IDs have a 32-bit wide ref_phase_offset_comp register instead
+ * of the default 48-bit.
+ *
+ * Return: true if the register is 32-bit, false if 48-bit
+ */
+static inline bool
+zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev)
+{
+ switch (zldev->chip_id) {
+ case 0x0E30:
+ case 0x0E93:
+ case 0x0E94:
+ case 0x0E95:
+ case 0x0E96:
+ case 0x0E97:
+ case 0x1F60:
+ return true;
+ default:
+ return false;
+ }
+}
+
static inline bool
zl3073x_is_n_pin(u8 id)
{
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index d33175d192c8..aaa14ea5e670 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -475,8 +475,11 @@ zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
ref_id = zl3073x_input_pin_ref_get(pin->id);
ref = zl3073x_ref_state_get(zldev, ref_id);
- /* Perform sign extension for 48bit signed value */
- phase_comp = sign_extend64(ref->phase_comp, 47);
+ /* Perform sign extension based on register width */
+ if (zl3073x_dev_is_ref_phase_comp_32bit(zldev))
+ phase_comp = sign_extend64(ref->phase_comp, 31);
+ else
+ phase_comp = sign_extend64(ref->phase_comp, 47);
/* Reverse two's complement negation applied during set and convert
* to 32bit signed int
diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c
index aa2de13effa8..6b65e6103999 100644
--- a/drivers/dpll/zl3073x/ref.c
+++ b/drivers/dpll/zl3073x/ref.c
@@ -121,8 +121,16 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
return rc;
/* Read phase compensation register */
- rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
- &ref->phase_comp);
+ if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) {
+ u32 val;
+
+ rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32,
+ &val);
+ ref->phase_comp = val;
+ } else {
+ rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
+ &ref->phase_comp);
+ }
if (rc)
return rc;
@@ -179,9 +187,16 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
if (!rc && dref->sync_ctrl != ref->sync_ctrl)
rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL,
ref->sync_ctrl);
- if (!rc && dref->phase_comp != ref->phase_comp)
- rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
- ref->phase_comp);
+ if (!rc && dref->phase_comp != ref->phase_comp) {
+ if (zl3073x_dev_is_ref_phase_comp_32bit(zldev))
+ rc = zl3073x_write_u32(zldev,
+ ZL_REG_REF_PHASE_OFFSET_COMP_32,
+ ref->phase_comp);
+ else
+ rc = zl3073x_write_u48(zldev,
+ ZL_REG_REF_PHASE_OFFSET_COMP,
+ ref->phase_comp);
+ }
if (rc)
return rc;
diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
index d837bee72b17..5573d7188406 100644
--- a/drivers/dpll/zl3073x/regs.h
+++ b/drivers/dpll/zl3073x/regs.h
@@ -194,6 +194,7 @@
#define ZL_REF_CONFIG_DIFF_EN BIT(2)
#define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6)
+#define ZL_REG_REF_PHASE_OFFSET_COMP_32 ZL_REG(10, 0x28, 4)
#define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1)
#define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0)
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 29e9828422bb..11d66333d93b 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -369,13 +369,13 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
if (!mci->layers)
goto error;
+ mci->dev.release = mci_release;
+ device_initialize(&mci->dev);
+
mci->pvt_info = kzalloc(sz_pvt, GFP_KERNEL);
if (!mci->pvt_info)
goto error;
- mci->dev.release = mci_release;
- device_initialize(&mci->dev);
-
/* setup index and various internal pointers */
mci->mc_idx = mc_num;
mci->tot_dimms = tot_dimms;
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index f1a2bee39bf1..82b3b6d9ed2d 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -257,9 +257,10 @@ static void fwnet_header_cache_update(struct hh_cache *hh,
memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
}
-static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+static int fwnet_header_parse(const struct sk_buff *skb, const struct net_device *dev,
+ unsigned char *haddr)
{
- memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
+ memcpy(haddr, dev->dev_addr, FWNET_ALEN);
return FWNET_ALEN;
}
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 1c868c1e4a49..8153d62c58f0 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -848,7 +848,7 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
{
struct device *dev = ohci->card.device;
unsigned int i;
- struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES];
+ struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES] = { NULL };
dma_addr_t dma_addrs[AR_BUFFERS];
void *vaddr;
struct descriptor *d;
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index 12a625387d6e..f2f94d4d533e 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -205,12 +205,12 @@ static int ffa_rxtx_map(phys_addr_t tx_buf, phys_addr_t rx_buf, u32 pg_cnt)
return 0;
}
-static int ffa_rxtx_unmap(u16 vm_id)
+static int ffa_rxtx_unmap(void)
{
ffa_value_t ret;
invoke_ffa_fn((ffa_value_t){
- .a0 = FFA_RXTX_UNMAP, .a1 = PACK_TARGET_INFO(vm_id, 0),
+ .a0 = FFA_RXTX_UNMAP,
}, &ret);
if (ret.a0 == FFA_ERROR)
@@ -2097,7 +2097,7 @@ static int __init ffa_init(void)
pr_err("failed to setup partitions\n");
ffa_notifications_cleanup();
- ffa_rxtx_unmap(drv_info->vm_id);
+ ffa_rxtx_unmap();
free_pages:
if (drv_info->tx_buffer)
free_pages_exact(drv_info->tx_buffer, rxtx_bufsz);
@@ -2112,7 +2112,7 @@ static void __exit ffa_exit(void)
{
ffa_notifications_cleanup();
ffa_partitions_cleanup();
- ffa_rxtx_unmap(drv_info->vm_id);
+ ffa_rxtx_unmap();
free_pages_exact(drv_info->tx_buffer, drv_info->rxtx_bufsz);
free_pages_exact(drv_info->rx_buffer, drv_info->rxtx_bufsz);
kfree(drv_info);
diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
index 9168794adae4..40ec184eedae 100644
--- a/drivers/firmware/arm_scmi/notify.c
+++ b/drivers/firmware/arm_scmi/notify.c
@@ -1066,7 +1066,7 @@ static int scmi_register_event_handler(struct scmi_notify_instance *ni,
* since at creation time we usually want to have all setup and ready before
* events really start flowing.
*
- * Return: A properly refcounted handler on Success, NULL on Failure
+ * Return: A properly refcounted handler on Success, ERR_PTR on Failure
*/
static inline struct scmi_event_handler *
__scmi_event_handler_get_ops(struct scmi_notify_instance *ni,
@@ -1113,7 +1113,7 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni,
}
mutex_unlock(&ni->pending_mtx);
- return hndl;
+ return hndl ?: ERR_PTR(-ENODEV);
}
static struct scmi_event_handler *
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 4c75970326e6..f51245aca259 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -189,13 +189,13 @@ struct scmi_protocol_handle {
/**
* struct scmi_iterator_state - Iterator current state descriptor
- * @desc_index: Starting index for the current mulit-part request.
+ * @desc_index: Starting index for the current multi-part request.
* @num_returned: Number of returned items in the last multi-part reply.
* @num_remaining: Number of remaining items in the multi-part message.
* @max_resources: Maximum acceptable number of items, configured by the caller
* depending on the underlying resources that it is querying.
* @loop_idx: The iterator loop index in the current multi-part reply.
- * @rx_len: Size in bytes of the currenly processed message; it can be used by
+ * @rx_len: Size in bytes of the currently processed message; it can be used by
* the user of the iterator to verify a reply size.
* @priv: Optional pointer to some additional state-related private data setup
* by the caller during the iterations.
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 00e74449ce09..2acad5fa5a28 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -18,6 +18,7 @@
#include <linux/bitmap.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -940,13 +941,13 @@ static int scpi_probe(struct platform_device *pdev)
int idx = scpi_drvinfo->num_chans;
struct scpi_chan *pchan = scpi_drvinfo->channels + idx;
struct mbox_client *cl = &pchan->cl;
- struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
+ struct device_node *shmem __free(device_node) =
+ of_parse_phandle(np, "shmem", idx);
if (!of_match_node(shmem_of_match, shmem))
return -ENXIO;
ret = of_address_to_resource(shmem, 0, &res);
- of_node_put(shmem);
if (ret) {
dev_err(dev, "failed to get SCPI payload mem resource\n");
return ret;
diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c
index b4f1c01e3b5b..5d8be0ac7c5e 100644
--- a/drivers/firmware/cirrus/cs_dsp.c
+++ b/drivers/firmware/cirrus/cs_dsp.c
@@ -1610,11 +1610,17 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
region_name);
if (reg) {
+ /*
+ * Although we expect the underlying bus does not require
+ * physically-contiguous buffers, we pessimistically use
+ * a temporary buffer instead of trusting that the
+ * alignment of region->data is ok.
+ */
region_len = le32_to_cpu(region->len);
if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE);
- kfree(buf);
- buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
+ vfree(buf);
+ buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out_fw;
@@ -1643,7 +1649,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
ret = 0;
out_fw:
- kfree(buf);
+ vfree(buf);
if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@@ -2331,11 +2337,17 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
}
if (reg) {
+ /*
+ * Although we expect the underlying bus does not require
+ * physically-contiguous buffers, we pessimistically use
+ * a temporary buffer instead of trusting that the
+ * alignment of blk->data is ok.
+ */
region_len = le32_to_cpu(blk->len);
if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE);
- kfree(buf);
- buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
+ vfree(buf);
+ buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out_fw;
@@ -2366,7 +2378,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
ret = 0;
out_fw:
- kfree(buf);
+ vfree(buf);
if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index 5a595d026f58..6103b1a082d2 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -60,7 +60,7 @@ extern __weak const efi_config_table_type_t efi_arch_tables[];
* x86 defines its own instance of sysfb_primary_display and uses
* it even without EFI, everything else can get them from here.
*/
-#if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)) || defined(CONFIG_FIRMWARE_EDID)
+#if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_FIRMWARE_EDID))
struct sysfb_display_info sysfb_primary_display __section(".data");
EXPORT_SYMBOL_GPL(sysfb_primary_display);
#endif
diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c
index 4ff0c2926097..6842aa96d704 100644
--- a/drivers/firmware/efi/mokvar-table.c
+++ b/drivers/firmware/efi/mokvar-table.c
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
* as an alternative to ordinary EFI variables, due to platform-dependent
* limitations. The memory occupied by this table is marked as reserved.
*
- * This routine must be called before efi_free_boot_services() in order
+ * This routine must be called before efi_unmap_boot_services() in order
* to guarantee that it can mark the table as reserved.
*
* Implicit inputs:
diff --git a/drivers/firmware/microchip/mpfs-auto-update.c b/drivers/firmware/microchip/mpfs-auto-update.c
index 46b19d803446..1211fd8d0463 100644
--- a/drivers/firmware/microchip/mpfs-auto-update.c
+++ b/drivers/firmware/microchip/mpfs-auto-update.c
@@ -113,10 +113,6 @@ static enum fw_upload_err mpfs_auto_update_prepare(struct fw_upload *fw_uploader
* be added here.
*/
- priv->flash = mpfs_sys_controller_get_flash(priv->sys_controller);
- if (!priv->flash)
- return FW_UPLOAD_ERR_HW_ERROR;
-
erase_size = round_up(erase_size, (u64)priv->flash->erasesize);
/*
@@ -427,6 +423,12 @@ static int mpfs_auto_update_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->sys_controller),
"Could not register as a sub device of the system controller\n");
+ priv->flash = mpfs_sys_controller_get_flash(priv->sys_controller);
+ if (IS_ERR_OR_NULL(priv->flash)) {
+ dev_dbg(dev, "No flash connected to the system controller, auto-update not supported\n");
+ return -ENODEV;
+ }
+
priv->dev = dev;
platform_set_drvdata(pdev, priv);
diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c
index 41da07c445a6..e1912108a0fe 100644
--- a/drivers/firmware/stratix10-rsu.c
+++ b/drivers/firmware/stratix10-rsu.c
@@ -768,7 +768,9 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
rsu_async_status_callback);
if (ret) {
dev_err(dev, "Error, getting RSU status %i\n", ret);
+ stratix10_svc_remove_async_client(priv->chan);
stratix10_svc_free_channel(priv->chan);
+ return ret;
}
/* get DCMF version from firmware */
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index 6f5c298582ab..e9e35d67ef96 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -37,15 +37,14 @@
* service layer will return error to FPGA manager when timeout occurs,
* timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC.
*/
-#define SVC_NUM_DATA_IN_FIFO 32
+#define SVC_NUM_DATA_IN_FIFO 8
#define SVC_NUM_CHANNEL 4
-#define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200
+#define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 2000
#define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30
#define BYTE_TO_WORD_SIZE 4
/* stratix10 service layer clients */
#define STRATIX10_RSU "stratix10-rsu"
-#define INTEL_FCS "intel-fcs"
/* Maximum number of SDM client IDs. */
#define MAX_SDM_CLIENT_IDS 16
@@ -105,11 +104,9 @@ struct stratix10_svc_chan;
/**
* struct stratix10_svc - svc private data
* @stratix10_svc_rsu: pointer to stratix10 RSU device
- * @intel_svc_fcs: pointer to the FCS device
*/
struct stratix10_svc {
struct platform_device *stratix10_svc_rsu;
- struct platform_device *intel_svc_fcs;
};
/**
@@ -251,12 +248,10 @@ struct stratix10_async_ctrl {
* @num_active_client: number of active service client
* @node: list management
* @genpool: memory pool pointing to the memory region
- * @task: pointer to the thread task which handles SMC or HVC call
- * @svc_fifo: a queue for storing service message data
* @complete_status: state for completion
- * @svc_fifo_lock: protect access to service message data queue
* @invoke_fn: function to issue secure monitor call or hypervisor call
* @svc: manages the list of client svc drivers
+ * @sdm_lock: only allows a single command single response to SDM
* @actrl: async control structure
*
* This struct is used to create communication channels for service clients, to
@@ -269,12 +264,10 @@ struct stratix10_svc_controller {
int num_active_client;
struct list_head node;
struct gen_pool *genpool;
- struct task_struct *task;
- struct kfifo svc_fifo;
struct completion complete_status;
- spinlock_t svc_fifo_lock;
svc_invoke_fn *invoke_fn;
struct stratix10_svc *svc;
+ struct mutex sdm_lock;
struct stratix10_async_ctrl actrl;
};
@@ -283,6 +276,9 @@ struct stratix10_svc_controller {
* @ctrl: pointer to service controller which is the provider of this channel
* @scl: pointer to service client which owns the channel
* @name: service client name associated with the channel
+ * @task: pointer to the thread task which handles SMC or HVC call
+ * @svc_fifo: a queue for storing service message data (separate fifo for every channel)
+ * @svc_fifo_lock: protect access to service message data queue (locking pending fifo)
* @lock: protect access to the channel
* @async_chan: reference to asynchronous channel object for this channel
*
@@ -293,6 +289,9 @@ struct stratix10_svc_chan {
struct stratix10_svc_controller *ctrl;
struct stratix10_svc_client *scl;
char *name;
+ struct task_struct *task;
+ struct kfifo svc_fifo;
+ spinlock_t svc_fifo_lock;
spinlock_t lock;
struct stratix10_async_chan *async_chan;
};
@@ -527,10 +526,10 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
*/
static int svc_normal_to_secure_thread(void *data)
{
- struct stratix10_svc_controller
- *ctrl = (struct stratix10_svc_controller *)data;
- struct stratix10_svc_data *pdata;
- struct stratix10_svc_cb_data *cbdata;
+ struct stratix10_svc_chan *chan = (struct stratix10_svc_chan *)data;
+ struct stratix10_svc_controller *ctrl = chan->ctrl;
+ struct stratix10_svc_data *pdata = NULL;
+ struct stratix10_svc_cb_data *cbdata = NULL;
struct arm_smccc_res res;
unsigned long a0, a1, a2, a3, a4, a5, a6, a7;
int ret_fifo = 0;
@@ -555,12 +554,12 @@ static int svc_normal_to_secure_thread(void *data)
a6 = 0;
a7 = 0;
- pr_debug("smc_hvc_shm_thread is running\n");
+ pr_debug("%s: %s: Thread is running!\n", __func__, chan->name);
while (!kthread_should_stop()) {
- ret_fifo = kfifo_out_spinlocked(&ctrl->svc_fifo,
+ ret_fifo = kfifo_out_spinlocked(&chan->svc_fifo,
pdata, sizeof(*pdata),
- &ctrl->svc_fifo_lock);
+ &chan->svc_fifo_lock);
if (!ret_fifo)
continue;
@@ -569,9 +568,25 @@ static int svc_normal_to_secure_thread(void *data)
(unsigned int)pdata->paddr, pdata->command,
(unsigned int)pdata->size);
+ /* SDM can only process one command at a time */
+ pr_debug("%s: %s: Thread is waiting for mutex!\n",
+ __func__, chan->name);
+ if (mutex_lock_interruptible(&ctrl->sdm_lock)) {
+ /* item already dequeued; notify client to unblock it */
+ cbdata->status = BIT(SVC_STATUS_ERROR);
+ cbdata->kaddr1 = NULL;
+ cbdata->kaddr2 = NULL;
+ cbdata->kaddr3 = NULL;
+ if (pdata->chan->scl)
+ pdata->chan->scl->receive_cb(pdata->chan->scl,
+ cbdata);
+ break;
+ }
+
switch (pdata->command) {
case COMMAND_RECONFIG_DATA_CLAIM:
svc_thread_cmd_data_claim(ctrl, pdata, cbdata);
+ mutex_unlock(&ctrl->sdm_lock);
continue;
case COMMAND_RECONFIG:
a0 = INTEL_SIP_SMC_FPGA_CONFIG_START;
@@ -700,10 +715,11 @@ static int svc_normal_to_secure_thread(void *data)
break;
default:
pr_warn("it shouldn't happen\n");
- break;
+ mutex_unlock(&ctrl->sdm_lock);
+ continue;
}
- pr_debug("%s: before SMC call -- a0=0x%016x a1=0x%016x",
- __func__,
+ pr_debug("%s: %s: before SMC call -- a0=0x%016x a1=0x%016x",
+ __func__, chan->name,
(unsigned int)a0,
(unsigned int)a1);
pr_debug(" a2=0x%016x\n", (unsigned int)a2);
@@ -712,8 +728,8 @@ static int svc_normal_to_secure_thread(void *data)
pr_debug(" a5=0x%016x\n", (unsigned int)a5);
ctrl->invoke_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res);
- pr_debug("%s: after SMC call -- res.a0=0x%016x",
- __func__, (unsigned int)res.a0);
+ pr_debug("%s: %s: after SMC call -- res.a0=0x%016x",
+ __func__, chan->name, (unsigned int)res.a0);
pr_debug(" res.a1=0x%016x, res.a2=0x%016x",
(unsigned int)res.a1, (unsigned int)res.a2);
pr_debug(" res.a3=0x%016x\n", (unsigned int)res.a3);
@@ -728,6 +744,7 @@ static int svc_normal_to_secure_thread(void *data)
cbdata->kaddr2 = NULL;
cbdata->kaddr3 = NULL;
pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata);
+ mutex_unlock(&ctrl->sdm_lock);
continue;
}
@@ -801,6 +818,8 @@ static int svc_normal_to_secure_thread(void *data)
break;
}
+
+ mutex_unlock(&ctrl->sdm_lock);
}
kfree(cbdata);
@@ -1696,22 +1715,33 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
if (!p_data)
return -ENOMEM;
- /* first client will create kernel thread */
- if (!chan->ctrl->task) {
- chan->ctrl->task =
- kthread_run_on_cpu(svc_normal_to_secure_thread,
- (void *)chan->ctrl,
- cpu, "svc_smc_hvc_thread");
- if (IS_ERR(chan->ctrl->task)) {
+ /* first caller creates the per-channel kthread */
+ if (!chan->task) {
+ struct task_struct *task;
+
+ task = kthread_run_on_cpu(svc_normal_to_secure_thread,
+ (void *)chan,
+ cpu, "svc_smc_hvc_thread");
+ if (IS_ERR(task)) {
dev_err(chan->ctrl->dev,
"failed to create svc_smc_hvc_thread\n");
kfree(p_data);
return -EINVAL;
}
+
+ spin_lock(&chan->lock);
+ if (chan->task) {
+ /* another caller won the race; discard our thread */
+ spin_unlock(&chan->lock);
+ kthread_stop(task);
+ } else {
+ chan->task = task;
+ spin_unlock(&chan->lock);
+ }
}
- pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__,
- p_msg->payload, p_msg->command,
+ pr_debug("%s: %s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__,
+ chan->name, p_msg->payload, p_msg->command,
(unsigned int)p_msg->payload_length);
if (list_empty(&svc_data_mem)) {
@@ -1747,12 +1777,16 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
p_data->arg[2] = p_msg->arg[2];
p_data->size = p_msg->payload_length;
p_data->chan = chan;
- pr_debug("%s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n", __func__,
- (unsigned int)p_data->paddr, p_data->command,
- (unsigned int)p_data->size);
- ret = kfifo_in_spinlocked(&chan->ctrl->svc_fifo, p_data,
+ pr_debug("%s: %s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n",
+ __func__,
+ chan->name,
+ (unsigned int)p_data->paddr,
+ p_data->command,
+ (unsigned int)p_data->size);
+
+ ret = kfifo_in_spinlocked(&chan->svc_fifo, p_data,
sizeof(*p_data),
- &chan->ctrl->svc_fifo_lock);
+ &chan->svc_fifo_lock);
kfree(p_data);
@@ -1773,11 +1807,12 @@ EXPORT_SYMBOL_GPL(stratix10_svc_send);
*/
void stratix10_svc_done(struct stratix10_svc_chan *chan)
{
- /* stop thread when thread is running AND only one active client */
- if (chan->ctrl->task && chan->ctrl->num_active_client <= 1) {
- pr_debug("svc_smc_hvc_shm_thread is stopped\n");
- kthread_stop(chan->ctrl->task);
- chan->ctrl->task = NULL;
+ /* stop thread when thread is running */
+ if (chan->task) {
+ pr_debug("%s: %s: svc_smc_hvc_shm_thread is stopping\n",
+ __func__, chan->name);
+ kthread_stop(chan->task);
+ chan->task = NULL;
}
}
EXPORT_SYMBOL_GPL(stratix10_svc_done);
@@ -1817,8 +1852,8 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
pmem->paddr = pa;
pmem->size = s;
list_add_tail(&pmem->node, &svc_data_mem);
- pr_debug("%s: va=%p, pa=0x%016x\n", __func__,
- pmem->vaddr, (unsigned int)pmem->paddr);
+ pr_debug("%s: %s: va=%p, pa=0x%016x\n", __func__,
+ chan->name, pmem->vaddr, (unsigned int)pmem->paddr);
return (void *)va;
}
@@ -1855,6 +1890,13 @@ static const struct of_device_id stratix10_svc_drv_match[] = {
{},
};
+static const char * const chan_names[SVC_NUM_CHANNEL] = {
+ SVC_CLIENT_FPGA,
+ SVC_CLIENT_RSU,
+ SVC_CLIENT_FCS,
+ SVC_CLIENT_HWMON
+};
+
static int stratix10_svc_drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1862,11 +1904,11 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
struct stratix10_svc_chan *chans;
struct gen_pool *genpool;
struct stratix10_svc_sh_memory *sh_memory;
- struct stratix10_svc *svc;
+ struct stratix10_svc *svc = NULL;
svc_invoke_fn *invoke_fn;
size_t fifo_size;
- int ret;
+ int ret, i = 0;
/* get SMC or HVC function */
invoke_fn = get_invoke_func(dev);
@@ -1905,8 +1947,8 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
controller->num_active_client = 0;
controller->chans = chans;
controller->genpool = genpool;
- controller->task = NULL;
controller->invoke_fn = invoke_fn;
+ INIT_LIST_HEAD(&controller->node);
init_completion(&controller->complete_status);
ret = stratix10_svc_async_init(controller);
@@ -1917,32 +1959,20 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
}
fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO;
- ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL);
- if (ret) {
- dev_err(dev, "failed to allocate FIFO\n");
- goto err_async_exit;
- }
- spin_lock_init(&controller->svc_fifo_lock);
-
- chans[0].scl = NULL;
- chans[0].ctrl = controller;
- chans[0].name = SVC_CLIENT_FPGA;
- spin_lock_init(&chans[0].lock);
+ mutex_init(&controller->sdm_lock);
- chans[1].scl = NULL;
- chans[1].ctrl = controller;
- chans[1].name = SVC_CLIENT_RSU;
- spin_lock_init(&chans[1].lock);
-
- chans[2].scl = NULL;
- chans[2].ctrl = controller;
- chans[2].name = SVC_CLIENT_FCS;
- spin_lock_init(&chans[2].lock);
-
- chans[3].scl = NULL;
- chans[3].ctrl = controller;
- chans[3].name = SVC_CLIENT_HWMON;
- spin_lock_init(&chans[3].lock);
+ for (i = 0; i < SVC_NUM_CHANNEL; i++) {
+ chans[i].scl = NULL;
+ chans[i].ctrl = controller;
+ chans[i].name = (char *)chan_names[i];
+ spin_lock_init(&chans[i].lock);
+ ret = kfifo_alloc(&chans[i].svc_fifo, fifo_size, GFP_KERNEL);
+ if (ret) {
+ dev_err(dev, "failed to allocate FIFO %d\n", i);
+ goto err_free_fifos;
+ }
+ spin_lock_init(&chans[i].svc_fifo_lock);
+ }
list_add_tail(&controller->node, &svc_ctrl);
platform_set_drvdata(pdev, controller);
@@ -1951,7 +1981,7 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL);
if (!svc) {
ret = -ENOMEM;
- goto err_free_kfifo;
+ goto err_free_fifos;
}
controller->svc = svc;
@@ -1959,51 +1989,43 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
if (!svc->stratix10_svc_rsu) {
dev_err(dev, "failed to allocate %s device\n", STRATIX10_RSU);
ret = -ENOMEM;
- goto err_free_kfifo;
+ goto err_free_fifos;
}
ret = platform_device_add(svc->stratix10_svc_rsu);
- if (ret) {
- platform_device_put(svc->stratix10_svc_rsu);
- goto err_free_kfifo;
- }
-
- svc->intel_svc_fcs = platform_device_alloc(INTEL_FCS, 1);
- if (!svc->intel_svc_fcs) {
- dev_err(dev, "failed to allocate %s device\n", INTEL_FCS);
- ret = -ENOMEM;
- goto err_unregister_rsu_dev;
- }
-
- ret = platform_device_add(svc->intel_svc_fcs);
- if (ret) {
- platform_device_put(svc->intel_svc_fcs);
- goto err_unregister_rsu_dev;
- }
+ if (ret)
+ goto err_put_device;
ret = of_platform_default_populate(dev_of_node(dev), NULL, dev);
if (ret)
- goto err_unregister_fcs_dev;
+ goto err_unregister_rsu_dev;
pr_info("Intel Service Layer Driver Initialized\n");
return 0;
-err_unregister_fcs_dev:
- platform_device_unregister(svc->intel_svc_fcs);
err_unregister_rsu_dev:
platform_device_unregister(svc->stratix10_svc_rsu);
-err_free_kfifo:
- kfifo_free(&controller->svc_fifo);
-err_async_exit:
+ goto err_free_fifos;
+err_put_device:
+ platform_device_put(svc->stratix10_svc_rsu);
+err_free_fifos:
+ /* only remove from list if list_add_tail() was reached */
+ if (!list_empty(&controller->node))
+ list_del(&controller->node);
+ /* free only the FIFOs that were successfully allocated */
+ while (i--)
+ kfifo_free(&chans[i].svc_fifo);
stratix10_svc_async_exit(controller);
err_destroy_pool:
gen_pool_destroy(genpool);
+
return ret;
}
static void stratix10_svc_drv_remove(struct platform_device *pdev)
{
+ int i;
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
struct stratix10_svc *svc = ctrl->svc;
@@ -2011,14 +2033,16 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
of_platform_depopulate(ctrl->dev);
- platform_device_unregister(svc->intel_svc_fcs);
platform_device_unregister(svc->stratix10_svc_rsu);
- kfifo_free(&ctrl->svc_fifo);
- if (ctrl->task) {
- kthread_stop(ctrl->task);
- ctrl->task = NULL;
+ for (i = 0; i < SVC_NUM_CHANNEL; i++) {
+ if (ctrl->chans[i].task) {
+ kthread_stop(ctrl->chans[i].task);
+ ctrl->chans[i].task = NULL;
+ }
+ kfifo_free(&ctrl->chans[i].svc_fifo);
}
+
if (ctrl->genpool)
gen_pool_destroy(ctrl->genpool);
list_del(&ctrl->node);
diff --git a/drivers/firmware/thead,th1520-aon.c b/drivers/firmware/thead,th1520-aon.c
index a35fd5e2a07f..d7f19b5b5f46 100644
--- a/drivers/firmware/thead,th1520-aon.c
+++ b/drivers/firmware/thead,th1520-aon.c
@@ -170,10 +170,9 @@ int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc,
hdr->func = TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE;
hdr->size = TH1520_AON_RPC_MSG_NUM;
- RPC_SET_BE16(&msg.resource, 0, rsrc);
- RPC_SET_BE16(&msg.resource, 2,
- (power_on ? TH1520_AON_PM_PW_MODE_ON :
- TH1520_AON_PM_PW_MODE_OFF));
+ msg.resource = cpu_to_be16(rsrc);
+ msg.mode = cpu_to_be16(power_on ? TH1520_AON_PM_PW_MODE_ON :
+ TH1520_AON_PM_PW_MODE_OFF);
ret = th1520_aon_call_rpc(aon_chan, &msg);
if (ret)
diff --git a/drivers/gpib/Kconfig b/drivers/gpib/Kconfig
index eeb50956ce85..d43a28c62ed7 100644
--- a/drivers/gpib/Kconfig
+++ b/drivers/gpib/Kconfig
@@ -122,6 +122,7 @@ config GPIB_FLUKE
depends on OF
select GPIB_COMMON
select GPIB_NEC7210
+ depends on HAS_IOMEM
help
GPIB driver for Fluke based cda devices.
diff --git a/drivers/gpib/common/gpib_os.c b/drivers/gpib/common/gpib_os.c
index be757db993a5..97c98f0a7a43 100644
--- a/drivers/gpib/common/gpib_os.c
+++ b/drivers/gpib/common/gpib_os.c
@@ -888,10 +888,6 @@ static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo
if (read_cmd.completed_transfer_count > read_cmd.requested_transfer_count)
return -EINVAL;
- desc = handle_to_descriptor(file_priv, read_cmd.handle);
- if (!desc)
- return -EINVAL;
-
if (WARN_ON_ONCE(sizeof(userbuf) > sizeof(read_cmd.buffer_ptr)))
return -EFAULT;
@@ -904,6 +900,17 @@ static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo
if (!access_ok(userbuf, remain))
return -EFAULT;
+ /* Lock descriptors to prevent concurrent close from freeing descriptor */
+ if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+ return -ERESTARTSYS;
+ desc = handle_to_descriptor(file_priv, read_cmd.handle);
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
+
atomic_set(&desc->io_in_progress, 1);
/* Read buffer loads till we fill the user supplied buffer */
@@ -937,6 +944,7 @@ static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo
retval = copy_to_user((void __user *)arg, &read_cmd, sizeof(read_cmd));
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
if (retval)
@@ -964,10 +972,6 @@ static int command_ioctl(struct gpib_file_private *file_priv,
if (cmd.completed_transfer_count > cmd.requested_transfer_count)
return -EINVAL;
- desc = handle_to_descriptor(file_priv, cmd.handle);
- if (!desc)
- return -EINVAL;
-
userbuf = (u8 __user *)(unsigned long)cmd.buffer_ptr;
userbuf += cmd.completed_transfer_count;
@@ -980,6 +984,17 @@ static int command_ioctl(struct gpib_file_private *file_priv,
if (!access_ok(userbuf, remain))
return -EFAULT;
+ /* Lock descriptors to prevent concurrent close from freeing descriptor */
+ if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+ return -ERESTARTSYS;
+ desc = handle_to_descriptor(file_priv, cmd.handle);
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
+
/*
* Write buffer loads till we empty the user supplied buffer.
* Call drivers at least once, even if remain is zero, in
@@ -1003,6 +1018,7 @@ static int command_ioctl(struct gpib_file_private *file_priv,
userbuf += bytes_written;
if (retval < 0) {
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
break;
@@ -1022,6 +1038,7 @@ static int command_ioctl(struct gpib_file_private *file_priv,
*/
if (!no_clear_io_in_prog || fault)
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
if (fault)
@@ -1047,10 +1064,6 @@ static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *b
if (write_cmd.completed_transfer_count > write_cmd.requested_transfer_count)
return -EINVAL;
- desc = handle_to_descriptor(file_priv, write_cmd.handle);
- if (!desc)
- return -EINVAL;
-
userbuf = (u8 __user *)(unsigned long)write_cmd.buffer_ptr;
userbuf += write_cmd.completed_transfer_count;
@@ -1060,6 +1073,17 @@ static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *b
if (!access_ok(userbuf, remain))
return -EFAULT;
+ /* Lock descriptors to prevent concurrent close from freeing descriptor */
+ if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
+ return -ERESTARTSYS;
+ desc = handle_to_descriptor(file_priv, write_cmd.handle);
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
+
atomic_set(&desc->io_in_progress, 1);
/* Write buffer loads till we empty the user supplied buffer */
@@ -1094,6 +1118,7 @@ static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *b
fault = copy_to_user((void __user *)arg, &write_cmd, sizeof(write_cmd));
atomic_set(&desc->io_in_progress, 0);
+ atomic_dec(&desc->descriptor_busy);
wake_up_interruptible(&board->wait);
if (fault)
@@ -1276,6 +1301,9 @@ static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigne
{
struct gpib_close_dev_ioctl cmd;
struct gpib_file_private *file_priv = filep->private_data;
+ struct gpib_descriptor *desc;
+ unsigned int pad;
+ int sad;
int retval;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
@@ -1284,19 +1312,27 @@ static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigne
if (cmd.handle >= GPIB_MAX_NUM_DESCRIPTORS)
return -EINVAL;
- if (!file_priv->descriptors[cmd.handle])
- return -EINVAL;
- retval = decrement_open_device_count(board, &board->device_list,
- file_priv->descriptors[cmd.handle]->pad,
- file_priv->descriptors[cmd.handle]->sad);
- if (retval < 0)
- return retval;
-
- kfree(file_priv->descriptors[cmd.handle]);
+ mutex_lock(&file_priv->descriptors_mutex);
+ desc = file_priv->descriptors[cmd.handle];
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EINVAL;
+ }
+ if (atomic_read(&desc->descriptor_busy)) {
+ mutex_unlock(&file_priv->descriptors_mutex);
+ return -EBUSY;
+ }
+ /* Remove from table while holding lock to prevent new IO from starting */
file_priv->descriptors[cmd.handle] = NULL;
+ pad = desc->pad;
+ sad = desc->sad;
+ mutex_unlock(&file_priv->descriptors_mutex);
- return 0;
+ retval = decrement_open_device_count(board, &board->device_list, pad, sad);
+
+ kfree(desc);
+ return retval;
}
static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg)
@@ -1331,12 +1367,25 @@ static int wait_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo
if (retval)
return -EFAULT;
+ /*
+ * Lock descriptors to prevent concurrent close from freeing
+ * descriptor. ibwait() releases big_gpib_mutex when wait_mask
+ * is non-zero, so desc must be pinned with descriptor_busy.
+ */
+ mutex_lock(&file_priv->descriptors_mutex);
desc = handle_to_descriptor(file_priv, wait_cmd.handle);
- if (!desc)
+ if (!desc) {
+ mutex_unlock(&file_priv->descriptors_mutex);
return -EINVAL;
+ }
+ atomic_inc(&desc->descriptor_busy);
+ mutex_unlock(&file_priv->descriptors_mutex);
retval = ibwait(board, wait_cmd.wait_mask, wait_cmd.clear_mask,
wait_cmd.set_mask, &wait_cmd.ibsta, wait_cmd.usec_timeout, desc);
+
+ atomic_dec(&desc->descriptor_busy);
+
if (retval < 0)
return retval;
@@ -2035,6 +2084,7 @@ void init_gpib_descriptor(struct gpib_descriptor *desc)
desc->is_board = 0;
desc->autopoll_enabled = 0;
atomic_set(&desc->io_in_progress, 0);
+ atomic_set(&desc->descriptor_busy, 0);
}
int gpib_register_driver(struct gpib_interface *interface, struct module *provider_module)
diff --git a/drivers/gpib/include/gpib_types.h b/drivers/gpib/include/gpib_types.h
index 5a0978ae27e7..28b73157ffb7 100644
--- a/drivers/gpib/include/gpib_types.h
+++ b/drivers/gpib/include/gpib_types.h
@@ -364,6 +364,14 @@ struct gpib_descriptor {
unsigned int pad; /* primary gpib address */
int sad; /* secondary gpib address (negative means disabled) */
atomic_t io_in_progress;
+ /*
+ * Kernel-only reference count to prevent descriptor from being
+ * freed while IO handlers hold a pointer to it. Incremented
+ * before each IO operation, decremented when done. Unlike
+ * io_in_progress, this cannot be modified from userspace via
+ * general_ibstatus().
+ */
+ atomic_t descriptor_busy;
unsigned is_board : 1;
unsigned autopoll_enabled : 1;
};
diff --git a/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c b/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c
index 6fc4e3452b88..0f9d385bc50b 100644
--- a/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c
+++ b/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c
@@ -38,8 +38,10 @@ MODULE_DESCRIPTION("GPIB driver for LPVO usb devices");
/*
* Table of devices that work with this driver.
*
- * Currently, only one device is known to be used in the
- * lpvo_usb_gpib adapter (FTDI 0403:6001).
+ * Currently, only one device is known to be used in the lpvo_usb_gpib
+ * adapter (FTDI 0403:6001) but as this device id is already handled by the
+ * ftdi_sio USB serial driver the LPVO driver must not bind to it by default.
+ *
* If your adapter uses a different chip, insert a line
* in the following table with proper <Vendor-id>, <Product-id>.
*
@@ -50,7 +52,6 @@ MODULE_DESCRIPTION("GPIB driver for LPVO usb devices");
*/
static const struct usb_device_id skel_table[] = {
- { USB_DEVICE(0x0403, 0x6001) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, skel_table);
@@ -405,7 +406,7 @@ static int usb_gpib_attach(struct gpib_board *board, const struct gpib_board_con
for (j = 0 ; j < MAX_DEV ; j++) {
if ((assigned_usb_minors & 1 << j) == 0)
continue;
- udev = usb_get_dev(interface_to_usbdev(lpvo_usb_interfaces[j]));
+ udev = interface_to_usbdev(lpvo_usb_interfaces[j]);
device_path = kobject_get_path(&udev->dev.kobj, GFP_KERNEL);
match = gpib_match_device_path(&lpvo_usb_interfaces[j]->dev,
config->device_path);
@@ -420,7 +421,7 @@ static int usb_gpib_attach(struct gpib_board *board, const struct gpib_board_con
for (j = 0 ; j < MAX_DEV ; j++) {
if ((assigned_usb_minors & 1 << j) == 0)
continue;
- udev = usb_get_dev(interface_to_usbdev(lpvo_usb_interfaces[j]));
+ udev = interface_to_usbdev(lpvo_usb_interfaces[j]);
DIA_LOG(1, "dev. %d: bus %d -> %d dev: %d -> %d\n", j,
udev->bus->busnum, config->pci_bus, udev->devnum, config->pci_slot);
if (config->pci_bus == udev->bus->busnum &&
diff --git a/drivers/gpio/gpio-bd72720.c b/drivers/gpio/gpio-bd72720.c
index 6549dbf4c7ad..d0f936ed80af 100644
--- a/drivers/gpio/gpio-bd72720.c
+++ b/drivers/gpio/gpio-bd72720.c
@@ -256,6 +256,8 @@ static int gpo_bd72720_probe(struct platform_device *pdev)
g->dev = dev;
g->chip.parent = parent;
g->regmap = dev_get_regmap(parent, NULL);
+ if (!g->regmap)
+ return -ENODEV;
return devm_gpiochip_add_data(dev, &g->chip, g);
}
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index d7666fe9dbf8..647b6f4861b7 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -584,12 +584,13 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
unsigned long config;
bool ret = false;
int i, type;
+ bool is_imx8qm = of_device_is_compatible(port->dev->of_node, "fsl,imx8qm-gpio");
static const u32 pad_type_map[] = {
IMX_SCU_WAKEUP_OFF, /* 0 */
IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_RISING */
IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_FALLING */
- IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_BOTH */
+ IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_BOTH */
IMX_SCU_WAKEUP_HIGH_LVL, /* IRQ_TYPE_LEVEL_HIGH */
IMX_SCU_WAKEUP_OFF, /* 5 */
IMX_SCU_WAKEUP_OFF, /* 6 */
@@ -604,6 +605,13 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
config = pad_type_map[type];
else
config = IMX_SCU_WAKEUP_OFF;
+
+ if (is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) {
+ dev_warn_once(port->dev,
+ "No falling-edge support for wakeup on i.MX8QM\n");
+ config = IMX_SCU_WAKEUP_OFF;
+ }
+
ret |= mxc_gpio_generic_config(port, i, config);
}
}
diff --git a/drivers/gpio/gpio-qixis-fpga.c b/drivers/gpio/gpio-qixis-fpga.c
index 6e67f43ac0bd..3ced47db1521 100644
--- a/drivers/gpio/gpio-qixis-fpga.c
+++ b/drivers/gpio/gpio-qixis-fpga.c
@@ -60,8 +60,8 @@ static int qixis_cpld_gpio_probe(struct platform_device *pdev)
return PTR_ERR(reg);
regmap = devm_regmap_init_mmio(&pdev->dev, reg, &regmap_config_8r_8v);
- if (!regmap)
- return -ENODEV;
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
/* In this case, the offset of our register is 0 inside the
* regmap area that we just created.
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 15a5762a82c2..df06b56a2ade 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -595,7 +595,7 @@ static void tegra_gpio_irq_release_resources(struct irq_data *d)
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
gpiochip_relres_irq(chip, d->hwirq);
- tegra_gpio_enable(tgi, d->hwirq);
+ tegra_gpio_disable(tgi, d->hwirq);
}
static void tegra_gpio_irq_print_chip(struct irq_data *d, struct seq_file *s)
@@ -698,7 +698,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
if (!tgi)
- return -ENODEV;
+ return -ENOMEM;
tgi->soc = of_device_get_match_data(&pdev->dev);
tgi->dev = &pdev->dev;
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index d2614ace4de1..e02d6b93a4ab 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -443,8 +443,8 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer,
}
#endif /* CONFIG_RESET_GPIO */
-int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
- unsigned long lflags)
+int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *fwnode,
+ const char *con_id, unsigned long lflags)
{
const char *dev_id = dev_name(consumer);
struct gpiod_lookup_table *lookup;
@@ -458,7 +458,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) {
if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
continue;
- } else if (!device_match_fwnode(consumer, ref->fwnode)) {
+ } else if (fwnode != ref->fwnode) {
continue;
}
@@ -506,8 +506,9 @@ static void gpio_shared_remove_adev(struct auxiliary_device *adev)
auxiliary_device_uninit(adev);
}
-int gpio_device_setup_shared(struct gpio_device *gdev)
+int gpiochip_setup_shared(struct gpio_chip *gc)
{
+ struct gpio_device *gdev = gc->gpiodev;
struct gpio_shared_entry *entry;
struct gpio_shared_ref *ref;
struct gpio_desc *desc;
@@ -538,20 +539,42 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
if (list_count_nodes(&entry->refs) <= 1)
continue;
- desc = &gdev->descs[entry->offset];
+ scoped_guard(mutex, &entry->lock) {
+#if IS_ENABLED(CONFIG_OF)
+ if (is_of_node(entry->fwnode) && gc->of_xlate) {
+ /*
+ * This is the earliest that we can tranlate the
+ * devicetree offset to the chip offset.
+ */
+ struct of_phandle_args gpiospec = { };
- __set_bit(GPIOD_FLAG_SHARED, &desc->flags);
- /*
- * Shared GPIOs are not requested via the normal path. Make
- * them inaccessible to anyone even before we register the
- * chip.
- */
- ret = gpiod_request_commit(desc, "shared");
- if (ret)
- return ret;
+ gpiospec.np = to_of_node(entry->fwnode);
+ gpiospec.args_count = 2;
+ gpiospec.args[0] = entry->offset;
+
+ ret = gc->of_xlate(gc, &gpiospec, NULL);
+ if (ret < 0)
+ return ret;
+
+ entry->offset = ret;
+ }
+#endif /* CONFIG_OF */
- pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
- entry->offset, gpio_device_get_label(gdev));
+ desc = &gdev->descs[entry->offset];
+
+ __set_bit(GPIOD_FLAG_SHARED, &desc->flags);
+ /*
+ * Shared GPIOs are not requested via the normal path. Make
+ * them inaccessible to anyone even before we register the
+ * chip.
+ */
+ ret = gpiod_request_commit(desc, "shared");
+ if (ret)
+ return ret;
+
+ pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
+ entry->offset, gpio_device_get_label(gdev));
+ }
list_for_each_entry(ref, &entry->refs, list) {
pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n",
@@ -575,6 +598,8 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
struct gpio_shared_ref *ref;
list_for_each_entry(entry, &gpio_shared_list, list) {
+ guard(mutex)(&entry->lock);
+
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
continue;
@@ -748,14 +773,14 @@ static bool gpio_shared_entry_is_really_shared(struct gpio_shared_entry *entry)
static void gpio_shared_free_exclusive(void)
{
struct gpio_shared_entry *entry, *epos;
+ struct gpio_shared_ref *ref, *rpos;
list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) {
if (gpio_shared_entry_is_really_shared(entry))
continue;
- gpio_shared_drop_ref(list_first_entry(&entry->refs,
- struct gpio_shared_ref,
- list));
+ list_for_each_entry_safe(ref, rpos, &entry->refs, list)
+ gpio_shared_drop_ref(ref);
gpio_shared_drop_entry(entry);
}
}
diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h
index 40568ef7364c..15e72a8dcdb1 100644
--- a/drivers/gpio/gpiolib-shared.h
+++ b/drivers/gpio/gpiolib-shared.h
@@ -11,17 +11,19 @@
struct gpio_device;
struct gpio_desc;
struct device;
+struct fwnode_handle;
#if IS_ENABLED(CONFIG_GPIO_SHARED)
-int gpio_device_setup_shared(struct gpio_device *gdev);
+int gpiochip_setup_shared(struct gpio_chip *gc);
void gpio_device_teardown_shared(struct gpio_device *gdev);
-int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
- unsigned long lflags);
+int gpio_shared_add_proxy_lookup(struct device *consumer,
+ struct fwnode_handle *fwnode,
+ const char *con_id, unsigned long lflags);
#else
-static inline int gpio_device_setup_shared(struct gpio_device *gdev)
+static inline int gpiochip_setup_shared(struct gpio_chip *gc)
{
return 0;
}
@@ -29,6 +31,7 @@ static inline int gpio_device_setup_shared(struct gpio_device *gdev)
static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { }
static inline int gpio_shared_add_proxy_lookup(struct device *consumer,
+ struct fwnode_handle *fwnode,
const char *con_id,
unsigned long lflags)
{
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 86a171e96b0e..300de30fd920 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -892,13 +892,15 @@ static const struct device_type gpio_dev_type = {
#define gcdev_unregister(gdev) device_del(&(gdev)->dev)
#endif
+/*
+ * An initial reference count has been held in gpiochip_add_data_with_key().
+ * The caller should drop the reference via gpio_device_put() on errors.
+ */
static int gpiochip_setup_dev(struct gpio_device *gdev)
{
struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
int ret;
- device_initialize(&gdev->dev);
-
/*
* If fwnode doesn't belong to another device, it's safe to clear its
* initialized flag.
@@ -964,9 +966,11 @@ static void gpiochip_setup_devs(void)
list_for_each_entry_srcu(gdev, &gpio_devices, list,
srcu_read_lock_held(&gpio_devices_srcu)) {
ret = gpiochip_setup_dev(gdev);
- if (ret)
+ if (ret) {
+ gpio_device_put(gdev);
dev_err(&gdev->dev,
"Failed to initialize gpio device (%d)\n", ret);
+ }
}
}
@@ -1047,71 +1051,72 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
int base = 0;
int ret;
- /*
- * First: allocate and populate the internal stat container, and
- * set up the struct device.
- */
gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
if (!gdev)
return -ENOMEM;
-
- gdev->dev.type = &gpio_dev_type;
- gdev->dev.bus = &gpio_bus_type;
- gdev->dev.parent = gc->parent;
- rcu_assign_pointer(gdev->chip, gc);
-
gc->gpiodev = gdev;
gpiochip_set_data(gc, data);
- device_set_node(&gdev->dev, gpiochip_choose_fwnode(gc));
-
ret = ida_alloc(&gpio_ida, GFP_KERNEL);
if (ret < 0)
goto err_free_gdev;
gdev->id = ret;
- ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id);
+ ret = init_srcu_struct(&gdev->srcu);
if (ret)
goto err_free_ida;
+ rcu_assign_pointer(gdev->chip, gc);
- if (gc->parent && gc->parent->driver)
- gdev->owner = gc->parent->driver->owner;
- else if (gc->owner)
- /* TODO: remove chip->owner */
- gdev->owner = gc->owner;
- else
- gdev->owner = THIS_MODULE;
+ ret = init_srcu_struct(&gdev->desc_srcu);
+ if (ret)
+ goto err_cleanup_gdev_srcu;
+
+ ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id);
+ if (ret)
+ goto err_cleanup_desc_srcu;
+
+ device_initialize(&gdev->dev);
+ /*
+ * After this point any allocated resources to `gdev` will be
+ * free():ed by gpiodev_release(). If you add new resources
+ * then make sure they get free():ed there.
+ */
+ gdev->dev.type = &gpio_dev_type;
+ gdev->dev.bus = &gpio_bus_type;
+ gdev->dev.parent = gc->parent;
+ device_set_node(&gdev->dev, gpiochip_choose_fwnode(gc));
ret = gpiochip_get_ngpios(gc, &gdev->dev);
if (ret)
- goto err_free_dev_name;
+ goto err_put_device;
+ gdev->ngpio = gc->ngpio;
gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL);
if (!gdev->descs) {
ret = -ENOMEM;
- goto err_free_dev_name;
+ goto err_put_device;
}
gdev->label = kstrdup_const(gc->label ?: "unknown", GFP_KERNEL);
if (!gdev->label) {
ret = -ENOMEM;
- goto err_free_descs;
+ goto err_put_device;
}
- gdev->ngpio = gc->ngpio;
gdev->can_sleep = gc->can_sleep;
-
rwlock_init(&gdev->line_state_lock);
RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
-
- ret = init_srcu_struct(&gdev->srcu);
- if (ret)
- goto err_free_label;
-
- ret = init_srcu_struct(&gdev->desc_srcu);
- if (ret)
- goto err_cleanup_gdev_srcu;
+#ifdef CONFIG_PINCTRL
+ INIT_LIST_HEAD(&gdev->pin_ranges);
+#endif
+ if (gc->parent && gc->parent->driver)
+ gdev->owner = gc->parent->driver->owner;
+ else if (gc->owner)
+ /* TODO: remove chip->owner */
+ gdev->owner = gc->owner;
+ else
+ gdev->owner = THIS_MODULE;
scoped_guard(mutex, &gpio_devices_lock) {
/*
@@ -1127,7 +1132,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
if (base < 0) {
ret = base;
base = 0;
- goto err_cleanup_desc_srcu;
+ goto err_put_device;
}
/*
@@ -1147,14 +1152,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
ret = gpiodev_add_to_list_unlocked(gdev);
if (ret) {
gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n");
- goto err_cleanup_desc_srcu;
+ goto err_put_device;
}
}
-#ifdef CONFIG_PINCTRL
- INIT_LIST_HEAD(&gdev->pin_ranges);
-#endif
-
if (gc->names)
gpiochip_set_desc_names(gc);
@@ -1210,7 +1211,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
if (ret)
goto err_remove_irqchip_mask;
- ret = gpio_device_setup_shared(gdev);
+ ret = gpiochip_setup_shared(gc);
if (ret)
goto err_remove_irqchip;
@@ -1248,25 +1249,19 @@ err_remove_from_list:
scoped_guard(mutex, &gpio_devices_lock)
list_del_rcu(&gdev->list);
synchronize_srcu(&gpio_devices_srcu);
- if (gdev->dev.release) {
- /* release() has been registered by gpiochip_setup_dev() */
- gpio_device_put(gdev);
- goto err_print_message;
- }
+err_put_device:
+ gpio_device_put(gdev);
+ goto err_print_message;
+
err_cleanup_desc_srcu:
cleanup_srcu_struct(&gdev->desc_srcu);
err_cleanup_gdev_srcu:
cleanup_srcu_struct(&gdev->srcu);
-err_free_label:
- kfree_const(gdev->label);
-err_free_descs:
- kfree(gdev->descs);
-err_free_dev_name:
- kfree(dev_name(&gdev->dev));
err_free_ida:
ida_free(&gpio_ida, gdev->id);
err_free_gdev:
kfree(gdev);
+
err_print_message:
/* failures here can mean systems won't boot... */
if (ret != -EPROBE_DEFER) {
@@ -2465,8 +2460,10 @@ int gpiod_request_commit(struct gpio_desc *desc, const char *label)
return -EBUSY;
offset = gpiod_hwgpio(desc);
- if (!gpiochip_line_is_valid(guard.gc, offset))
- return -EINVAL;
+ if (!gpiochip_line_is_valid(guard.gc, offset)) {
+ ret = -EINVAL;
+ goto out_clear_bit;
+ }
/* NOTE: gpio_request() can be called in early boot,
* before IRQs are enabled, for non-sleeping (SOC) GPIOs.
@@ -3267,8 +3264,12 @@ static int gpiochip_get(struct gpio_chip *gc, unsigned int offset)
/* Make sure this is called after checking for gc->get(). */
ret = gc->get(gc, offset);
- if (ret > 1)
- ret = -EBADE;
+ if (ret > 1) {
+ gpiochip_warn(gc,
+ "invalid return value from gc->get(): %d, consider fixing the driver\n",
+ ret);
+ ret = !!ret;
+ }
return ret;
}
@@ -4713,8 +4714,8 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer,
* lookup table for the proxy device as previously
* we only knew the consumer's fwnode.
*/
- ret = gpio_shared_add_proxy_lookup(consumer, con_id,
- lookupflags);
+ ret = gpio_shared_add_proxy_lookup(consumer, fwnode,
+ con_id, lookupflags);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
index afe5ca81beec..db7858fe0c3d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
@@ -641,6 +641,7 @@ static void aca_error_fini(struct aca_error *aerr)
aca_bank_error_remove(aerr, bank_error);
out_unlock:
+ mutex_unlock(&aerr->lock);
mutex_destroy(&aerr->lock);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 40c22438b1d2..4f27c75abedb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -692,9 +692,9 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev,
goto err_ib_sched;
}
- /* Drop the initial kref_init count (see drm_sched_main as example) */
- dma_fence_put(f);
ret = dma_fence_wait(f, false);
+ /* Drop the returned fence reference after the wait completes */
+ dma_fence_put(f);
err_ib_sched:
amdgpu_job_free(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 06c1913d5a3f..29b400cdd6d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -1439,7 +1439,10 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
*process_info = info;
}
- vm->process_info = *process_info;
+ if (cmpxchg(&vm->process_info, NULL, *process_info) != NULL) {
+ ret = -EINVAL;
+ goto already_acquired;
+ }
/* Validate page directory and attach eviction fence */
ret = amdgpu_bo_reserve(vm->root.bo, true);
@@ -1479,6 +1482,7 @@ validate_pd_fail:
amdgpu_bo_unreserve(vm->root.bo);
reserve_pd_fail:
vm->process_info = NULL;
+already_acquired:
if (info) {
dma_fence_put(&info->eviction_fence->base);
*process_info = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index 4662bfbe70b2..43864df8af04 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -36,6 +36,7 @@
#define AMDGPU_BO_LIST_MAX_PRIORITY 32u
#define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1)
+#define AMDGPU_BO_LIST_MAX_ENTRIES (128 * 1024)
static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
{
@@ -188,6 +189,9 @@ int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in,
const uint32_t bo_number = in->bo_number;
struct drm_amdgpu_bo_list_entry *info;
+ if (bo_number > AMDGPU_BO_LIST_MAX_ENTRIES)
+ return -EINVAL;
+
/* copy the handle array from userspace to a kernel buffer */
if (likely(info_size == bo_info_size)) {
info = vmemdup_array_user(uptr, bo_number, info_size);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index d9789e0b5201..6d8531f9b882 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -2690,8 +2690,10 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
break;
default:
r = amdgpu_discovery_set_ip_blocks(adev);
- if (r)
+ if (r) {
+ adev->num_ip_blocks = 0;
return r;
+ }
break;
}
@@ -3247,6 +3249,8 @@ int amdgpu_device_set_cg_state(struct amdgpu_device *adev,
i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
if (!adev->ip_blocks[i].status.late_initialized)
continue;
+ if (!adev->ip_blocks[i].version)
+ continue;
/* skip CG for GFX, SDMA on S0ix */
if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
@@ -3286,6 +3290,8 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev,
i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
if (!adev->ip_blocks[i].status.late_initialized)
continue;
+ if (!adev->ip_blocks[i].version)
+ continue;
/* skip PG for GFX, SDMA on S0ix */
if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
@@ -3493,6 +3499,8 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!adev->ip_blocks[i].version)
+ continue;
if (!adev->ip_blocks[i].version->funcs->early_fini)
continue;
@@ -3570,6 +3578,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
if (!adev->ip_blocks[i].status.sw)
continue;
+ if (!adev->ip_blocks[i].version)
+ continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
amdgpu_ucode_free_bo(adev);
amdgpu_free_static_csa(&adev->virt.csa_obj);
@@ -3596,6 +3606,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_blocks[i].status.late_initialized)
continue;
+ if (!adev->ip_blocks[i].version)
+ continue;
if (adev->ip_blocks[i].version->funcs->late_fini)
adev->ip_blocks[i].version->funcs->late_fini(&adev->ip_blocks[i]);
adev->ip_blocks[i].status.late_initialized = false;
@@ -4195,7 +4207,8 @@ fail:
static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
{
- char *input = amdgpu_lockup_timeout;
+ char buf[AMDGPU_MAX_TIMEOUT_PARAM_LENGTH];
+ char *input = buf;
char *timeout_setting = NULL;
int index = 0;
long timeout;
@@ -4205,9 +4218,17 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
adev->gfx_timeout = adev->compute_timeout = adev->sdma_timeout =
adev->video_timeout = msecs_to_jiffies(2000);
- if (!strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH))
+ if (!strnlen(amdgpu_lockup_timeout, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH))
return 0;
+ /*
+ * strsep() destructively modifies its input by replacing delimiters
+ * with '\0'. Use a stack copy so the global module parameter buffer
+ * remains intact for multi-GPU systems where this function is called
+ * once per device.
+ */
+ strscpy(buf, amdgpu_lockup_timeout, sizeof(buf));
+
while ((timeout_setting = strsep(&input, ",")) &&
strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
ret = kstrtol(timeout_setting, 0, &timeout);
@@ -7059,6 +7080,15 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)
dev_info(adev->dev, "PCI error: slot reset callback!!\n");
memset(&reset_context, 0, sizeof(reset_context));
+ INIT_LIST_HEAD(&device_list);
+ hive = amdgpu_get_xgmi_hive(adev);
+ if (hive) {
+ mutex_lock(&hive->hive_lock);
+ list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head)
+ list_add_tail(&tmp_adev->reset_list, &device_list);
+ } else {
+ list_add_tail(&adev->reset_list, &device_list);
+ }
if (adev->pcie_reset_ctx.swus)
link_dev = adev->pcie_reset_ctx.swus;
@@ -7099,19 +7129,13 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)
reset_context.reset_req_dev = adev;
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);
- INIT_LIST_HEAD(&device_list);
- hive = amdgpu_get_xgmi_hive(adev);
if (hive) {
- mutex_lock(&hive->hive_lock);
reset_context.hive = hive;
- list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
+ list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head)
tmp_adev->pcie_reset_ctx.in_link_reset = true;
- list_add_tail(&tmp_adev->reset_list, &device_list);
- }
} else {
set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags);
- list_add_tail(&adev->reset_list, &device_list);
}
r = amdgpu_device_asic_reset(adev, &device_list, &reset_context);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 95d26f086d54..c91638e65174 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2703,8 +2703,12 @@ static int amdgpu_pmops_freeze(struct device *dev)
if (r)
return r;
- if (amdgpu_acpi_should_gpu_reset(adev))
- return amdgpu_asic_reset(adev);
+ if (amdgpu_acpi_should_gpu_reset(adev)) {
+ amdgpu_device_lock_reset_domain(adev->reset_domain);
+ r = amdgpu_asic_reset(adev);
+ amdgpu_device_unlock_reset_domain(adev->reset_domain);
+ return r;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
index e2d32c29668a..bc772ca3dab7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c
@@ -404,6 +404,50 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
}
/**
+ * amdgpu_gart_map_gfx9_mqd - map mqd and ctrl_stack dma_addresses into GART entries
+ *
+ * @adev: amdgpu_device pointer
+ * @offset: offset into the GPU's gart aperture
+ * @pages: number of pages to bind
+ * @dma_addr: DMA addresses of pages
+ * @flags: page table entry flags
+ *
+ * Map the MQD and control stack addresses into GART entries with the correct
+ * memory types on gfxv9. The MQD occupies the first 4KB and is followed by
+ * the control stack. The MQD uses UC (uncached) memory, while the control stack
+ * uses NC (non-coherent) memory.
+ */
+void amdgpu_gart_map_gfx9_mqd(struct amdgpu_device *adev, uint64_t offset,
+ int pages, dma_addr_t *dma_addr, uint64_t flags)
+{
+ uint64_t page_base;
+ unsigned int i, j, t;
+ int idx;
+ uint64_t ctrl_flags = AMDGPU_PTE_MTYPE_VG10(flags, AMDGPU_MTYPE_NC);
+ void *dst;
+
+ if (!adev->gart.ptr)
+ return;
+
+ if (!drm_dev_enter(adev_to_drm(adev), &idx))
+ return;
+
+ t = offset / AMDGPU_GPU_PAGE_SIZE;
+ dst = adev->gart.ptr;
+ for (i = 0; i < pages; i++) {
+ page_base = dma_addr[i];
+ for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) {
+ if ((i == 0) && (j == 0))
+ amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags);
+ else
+ amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, ctrl_flags);
+ page_base += AMDGPU_GPU_PAGE_SIZE;
+ }
+ }
+ drm_dev_exit(idx);
+}
+
+/**
* amdgpu_gart_bind - bind pages into the gart page table
*
* @adev: amdgpu_device pointer
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
index d3118275ddae..6ebd2da32ea6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h
@@ -62,6 +62,8 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset,
int pages, dma_addr_t *dma_addr, uint64_t flags,
void *dst);
+void amdgpu_gart_map_gfx9_mqd(struct amdgpu_device *adev, uint64_t offset,
+ int pages, dma_addr_t *dma_addr, uint64_t flags);
void amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
int pages, dma_addr_t *dma_addr, uint64_t flags);
void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 64c519cd7395..569c5a89ff10 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -35,10 +35,13 @@
* PASIDs are global address space identifiers that can be shared
* between the GPU, an IOMMU and the driver. VMs on different devices
* may use the same PASID if they share the same address
- * space. Therefore PASIDs are allocated using a global IDA. VMs are
- * looked up from the PASID per amdgpu_device.
+ * space. Therefore PASIDs are allocated using IDR cyclic allocator
+ * (similar to kernel PID allocation) which naturally delays reuse.
+ * VMs are looked up from the PASID per amdgpu_device.
*/
-static DEFINE_IDA(amdgpu_pasid_ida);
+
+static DEFINE_IDR(amdgpu_pasid_idr);
+static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock);
/* Helper to free pasid from a fence callback */
struct amdgpu_pasid_cb {
@@ -50,8 +53,8 @@ struct amdgpu_pasid_cb {
* amdgpu_pasid_alloc - Allocate a PASID
* @bits: Maximum width of the PASID in bits, must be at least 1
*
- * Allocates a PASID of the given width while keeping smaller PASIDs
- * available if possible.
+ * Uses kernel's IDR cyclic allocator (same as PID allocation).
+ * Allocates sequentially with automatic wrap-around.
*
* Returns a positive integer on success. Returns %-EINVAL if bits==0.
* Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
@@ -59,14 +62,18 @@ struct amdgpu_pasid_cb {
*/
int amdgpu_pasid_alloc(unsigned int bits)
{
- int pasid = -EINVAL;
+ int pasid;
- for (bits = min(bits, 31U); bits > 0; bits--) {
- pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1),
- (1U << bits) - 1, GFP_KERNEL);
- if (pasid != -ENOSPC)
- break;
- }
+ if (bits == 0)
+ return -EINVAL;
+
+ spin_lock(&amdgpu_pasid_idr_lock);
+ /* TODO: Need to replace the idr with an xarry, and then
+ * handle the internal locking with ATOMIC safe paths.
+ */
+ pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1,
+ 1U << bits, GFP_ATOMIC);
+ spin_unlock(&amdgpu_pasid_idr_lock);
if (pasid >= 0)
trace_amdgpu_pasid_allocated(pasid);
@@ -81,7 +88,10 @@ int amdgpu_pasid_alloc(unsigned int bits)
void amdgpu_pasid_free(u32 pasid)
{
trace_amdgpu_pasid_freed(pasid);
- ida_free(&amdgpu_pasid_ida, pasid);
+
+ spin_lock(&amdgpu_pasid_idr_lock);
+ idr_remove(&amdgpu_pasid_idr, pasid);
+ spin_unlock(&amdgpu_pasid_idr_lock);
}
static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -616,3 +626,15 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
}
}
}
+
+/**
+ * amdgpu_pasid_mgr_cleanup - cleanup PASID manager
+ *
+ * Cleanup the IDR allocator.
+ */
+void amdgpu_pasid_mgr_cleanup(void)
+{
+ spin_lock(&amdgpu_pasid_idr_lock);
+ idr_destroy(&amdgpu_pasid_idr);
+ spin_unlock(&amdgpu_pasid_idr_lock);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
index b3649cd3af56..a57919478d3b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h
@@ -74,6 +74,7 @@ int amdgpu_pasid_alloc(unsigned int bits);
void amdgpu_pasid_free(u32 pasid);
void amdgpu_pasid_free_delayed(struct dma_resv *resv,
u32 pasid);
+void amdgpu_pasid_mgr_cleanup(void);
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
struct amdgpu_vmid *id);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 77e2133de5cf..7f19554b9ad1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -83,7 +83,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev)
{
struct amdgpu_device *adev = drm_to_adev(dev);
- if (adev == NULL)
+ if (adev == NULL || !adev->num_ip_blocks)
return;
amdgpu_unregister_gpu_instance(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index dc8d2f52c7d6..e244c12ceb23 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -368,15 +368,15 @@ struct amdgpu_mode_info {
struct drm_property *plane_ctm_property;
/**
- * @shaper_lut_property: Plane property to set pre-blending shaper LUT
- * that converts color content before 3D LUT. If
- * plane_shaper_tf_property != Identity TF, AMD color module will
+ * @plane_shaper_lut_property: Plane property to set pre-blending
+ * shaper LUT that converts color content before 3D LUT.
+ * If plane_shaper_tf_property != Identity TF, AMD color module will
* combine the user LUT values with pre-defined TF into the LUT
* parameters to be programmed.
*/
struct drm_property *plane_shaper_lut_property;
/**
- * @shaper_lut_size_property: Plane property for the size of
+ * @plane_shaper_lut_size_property: Plane property for the size of
* pre-blending shaper LUT as supported by the driver (read-only).
*/
struct drm_property *plane_shaper_lut_size_property;
@@ -400,10 +400,10 @@ struct amdgpu_mode_info {
*/
struct drm_property *plane_lut3d_property;
/**
- * @plane_degamma_lut_size_property: Plane property to define the max
- * size of 3D LUT as supported by the driver (read-only). The max size
- * is the max size of one dimension and, therefore, the max number of
- * entries for 3D LUT array is the 3D LUT size cubed;
+ * @plane_lut3d_size_property: Plane property to define the max size
+ * of 3D LUT as supported by the driver (read-only). The max size is
+ * the max size of one dimension and, therefore, the max number of
+ * entries for 3D LUT array is the 3D LUT size cubed.
*/
struct drm_property *plane_lut3d_size_property;
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c
index 6e8aad91bcd3..0d3c18f04ac3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c
@@ -332,13 +332,13 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
if (!context || !context->initialized) {
dev_err(adev->dev, "TA is not initialized\n");
ret = -EINVAL;
- goto err_free_shared_buf;
+ goto free_shared_buf;
}
if (!psp->ta_funcs || !psp->ta_funcs->fn_ta_invoke) {
dev_err(adev->dev, "Unsupported function to invoke TA\n");
ret = -EOPNOTSUPP;
- goto err_free_shared_buf;
+ goto free_shared_buf;
}
context->session_id = ta_id;
@@ -346,7 +346,7 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
mutex_lock(&psp->ras_context.mutex);
ret = prep_ta_mem_context(&context->mem_context, shared_buf, shared_buf_len);
if (ret)
- goto err_free_shared_buf;
+ goto unlock;
ret = psp_fn_ta_invoke(psp, cmd_id);
if (ret || context->resp_status) {
@@ -354,15 +354,17 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size
ret, context->resp_status);
if (!ret) {
ret = -EINVAL;
- goto err_free_shared_buf;
+ goto unlock;
}
}
if (copy_to_user((char *)&buf[copy_pos], context->mem_context.shared_buf, shared_buf_len))
ret = -EFAULT;
-err_free_shared_buf:
+unlock:
mutex_unlock(&psp->ras_context.mutex);
+
+free_shared_buf:
kfree(shared_buf);
return ret;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index eeaa56c8d129..0ccb31788b20 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -853,25 +853,15 @@ static void amdgpu_ttm_gart_bind_gfx9_mqd(struct amdgpu_device *adev,
int num_xcc = max(1U, adev->gfx.num_xcc_per_xcp);
uint64_t page_idx, pages_per_xcc;
int i;
- uint64_t ctrl_flags = AMDGPU_PTE_MTYPE_VG10(flags, AMDGPU_MTYPE_NC);
pages_per_xcc = total_pages;
do_div(pages_per_xcc, num_xcc);
for (i = 0, page_idx = 0; i < num_xcc; i++, page_idx += pages_per_xcc) {
- /* MQD page: use default flags */
- amdgpu_gart_bind(adev,
+ amdgpu_gart_map_gfx9_mqd(adev,
gtt->offset + (page_idx << PAGE_SHIFT),
- 1, &gtt->ttm.dma_address[page_idx], flags);
- /*
- * Ctrl pages - modify the memory type to NC (ctrl_flags) from
- * the second page of the BO onward.
- */
- amdgpu_gart_bind(adev,
- gtt->offset + ((page_idx + 1) << PAGE_SHIFT),
- pages_per_xcc - 1,
- &gtt->ttm.dma_address[page_idx + 1],
- ctrl_flags);
+ pages_per_xcc, &gtt->ttm.dma_address[page_idx],
+ flags);
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 9d67b770bcc2..0a1b93259887 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -446,8 +446,7 @@ static int amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue)
return ret;
}
-static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
- int queue_id)
+static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
@@ -461,7 +460,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
uq_funcs->mqd_destroy(queue);
amdgpu_userq_fence_driver_free(queue);
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
- xa_erase_irq(&uq_mgr->userq_xa, (unsigned long)queue_id);
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
queue->userq_mgr = NULL;
list_del(&queue->userq_va_list);
@@ -470,12 +468,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
up_read(&adev->reset_domain->sem);
}
-static struct amdgpu_usermode_queue *
-amdgpu_userq_find(struct amdgpu_userq_mgr *uq_mgr, int qid)
-{
- return xa_load(&uq_mgr->userq_xa, qid);
-}
-
void
amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_eviction_fence_mgr *evf_mgr)
@@ -608,6 +600,13 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
goto unpin_bo;
}
+ /* Validate doorbell_offset is within the doorbell BO */
+ if ((u64)db_info->doorbell_offset * db_size + db_size >
+ amdgpu_bo_size(db_obj->obj)) {
+ r = -EINVAL;
+ goto unpin_bo;
+ }
+
index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj,
db_info->doorbell_offset, db_size);
drm_dbg_driver(adev_to_drm(uq_mgr->adev),
@@ -625,22 +624,13 @@ unref_bo:
}
static int
-amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
+amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue)
{
- struct amdgpu_fpriv *fpriv = filp->driver_priv;
- struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
- struct amdgpu_usermode_queue *queue;
int r = 0;
cancel_delayed_work_sync(&uq_mgr->resume_work);
mutex_lock(&uq_mgr->userq_mutex);
- queue = amdgpu_userq_find(uq_mgr, queue_id);
- if (!queue) {
- drm_dbg_driver(adev_to_drm(uq_mgr->adev), "Invalid queue id to destroy\n");
- mutex_unlock(&uq_mgr->userq_mutex);
- return -EINVAL;
- }
amdgpu_userq_wait_for_last_fence(queue);
/* Cancel any pending hang detection work and cleanup */
if (queue->hang_detect_fence) {
@@ -672,7 +662,7 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n");
queue->state = AMDGPU_USERQ_STATE_HUNG;
}
- amdgpu_userq_cleanup(queue, queue_id);
+ amdgpu_userq_cleanup(queue);
mutex_unlock(&uq_mgr->userq_mutex);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -680,6 +670,37 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
return r;
}
+static void amdgpu_userq_kref_destroy(struct kref *kref)
+{
+ int r;
+ struct amdgpu_usermode_queue *queue =
+ container_of(kref, struct amdgpu_usermode_queue, refcount);
+ struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
+
+ r = amdgpu_userq_destroy(uq_mgr, queue);
+ if (r)
+ drm_file_err(uq_mgr->file, "Failed to destroy usermode queue %d\n", r);
+}
+
+struct amdgpu_usermode_queue *amdgpu_userq_get(struct amdgpu_userq_mgr *uq_mgr, u32 qid)
+{
+ struct amdgpu_usermode_queue *queue;
+
+ xa_lock(&uq_mgr->userq_xa);
+ queue = xa_load(&uq_mgr->userq_xa, qid);
+ if (queue)
+ kref_get(&queue->refcount);
+ xa_unlock(&uq_mgr->userq_xa);
+
+ return queue;
+}
+
+void amdgpu_userq_put(struct amdgpu_usermode_queue *queue)
+{
+ if (queue)
+ kref_put(&queue->refcount, amdgpu_userq_kref_destroy);
+}
+
static int amdgpu_userq_priority_permit(struct drm_file *filp,
int priority)
{
@@ -834,6 +855,9 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
goto unlock;
}
+ /* drop this refcount during queue destroy */
+ kref_init(&queue->refcount);
+
/* Wait for mode-1 reset to complete */
down_read(&adev->reset_domain->sem);
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
@@ -985,7 +1009,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
union drm_amdgpu_userq *args = data;
- int r;
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+ struct amdgpu_usermode_queue *queue;
+ int r = 0;
if (!amdgpu_userq_enabled(dev))
return -ENOTSUPP;
@@ -1000,11 +1026,16 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
drm_file_err(filp, "Failed to create usermode queue\n");
break;
- case AMDGPU_USERQ_OP_FREE:
- r = amdgpu_userq_destroy(filp, args->in.queue_id);
- if (r)
- drm_file_err(filp, "Failed to destroy usermode queue\n");
+ case AMDGPU_USERQ_OP_FREE: {
+ xa_lock(&fpriv->userq_mgr.userq_xa);
+ queue = __xa_erase(&fpriv->userq_mgr.userq_xa, args->in.queue_id);
+ xa_unlock(&fpriv->userq_mgr.userq_xa);
+ if (!queue)
+ return -ENOENT;
+
+ amdgpu_userq_put(queue);
break;
+ }
default:
drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op);
@@ -1023,16 +1054,23 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
/* Resume all the queues for this process */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
+ queue = amdgpu_userq_get(uq_mgr, queue_id);
+ if (!queue)
+ continue;
+
if (!amdgpu_userq_buffer_vas_mapped(queue)) {
drm_file_err(uq_mgr->file,
"trying restore queue without va mapping\n");
queue->state = AMDGPU_USERQ_STATE_INVALID_VA;
+ amdgpu_userq_put(queue);
continue;
}
r = amdgpu_userq_restore_helper(queue);
if (r)
ret = r;
+
+ amdgpu_userq_put(queue);
}
if (ret)
@@ -1266,9 +1304,13 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
amdgpu_userq_detect_and_reset_queues(uq_mgr);
/* Try to unmap all the queues in this process ctx */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
+ queue = amdgpu_userq_get(uq_mgr, queue_id);
+ if (!queue)
+ continue;
r = amdgpu_userq_preempt_helper(queue);
if (r)
ret = r;
+ amdgpu_userq_put(queue);
}
if (ret)
@@ -1301,16 +1343,24 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
int ret;
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
+ queue = amdgpu_userq_get(uq_mgr, queue_id);
+ if (!queue)
+ continue;
+
struct dma_fence *f = queue->last_fence;
- if (!f || dma_fence_is_signaled(f))
+ if (!f || dma_fence_is_signaled(f)) {
+ amdgpu_userq_put(queue);
continue;
+ }
ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100));
if (ret <= 0) {
drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
f->context, f->seqno);
+ amdgpu_userq_put(queue);
return -ETIMEDOUT;
}
+ amdgpu_userq_put(queue);
}
return 0;
@@ -1361,20 +1411,23 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
{
struct amdgpu_usermode_queue *queue;
- unsigned long queue_id;
+ unsigned long queue_id = 0;
+
+ for (;;) {
+ xa_lock(&userq_mgr->userq_xa);
+ queue = xa_find(&userq_mgr->userq_xa, &queue_id, ULONG_MAX,
+ XA_PRESENT);
+ if (queue)
+ __xa_erase(&userq_mgr->userq_xa, queue_id);
+ xa_unlock(&userq_mgr->userq_xa);
- cancel_delayed_work_sync(&userq_mgr->resume_work);
+ if (!queue)
+ break;
- mutex_lock(&userq_mgr->userq_mutex);
- amdgpu_userq_detect_and_reset_queues(userq_mgr);
- xa_for_each(&userq_mgr->userq_xa, queue_id, queue) {
- amdgpu_userq_wait_for_last_fence(queue);
- amdgpu_userq_unmap_helper(queue);
- amdgpu_userq_cleanup(queue, queue_id);
+ amdgpu_userq_put(queue);
}
xa_destroy(&userq_mgr->userq_xa);
- mutex_unlock(&userq_mgr->userq_mutex);
mutex_destroy(&userq_mgr->userq_mutex);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index 5845d8959034..736c1d38297c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -74,6 +74,7 @@ struct amdgpu_usermode_queue {
struct dentry *debugfs_queue;
struct delayed_work hang_detect_work;
struct dma_fence *hang_detect_fence;
+ struct kref refcount;
struct list_head userq_va_list;
};
@@ -112,6 +113,9 @@ struct amdgpu_db_info {
struct amdgpu_userq_obj *db_obj;
};
+struct amdgpu_usermode_queue *amdgpu_userq_get(struct amdgpu_userq_mgr *uq_mgr, u32 qid);
+void amdgpu_userq_put(struct amdgpu_usermode_queue *queue);
+
int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
index 8013260e29dc..5239b06b9ab0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
@@ -35,6 +35,8 @@
static const struct dma_fence_ops amdgpu_userq_fence_ops;
static struct kmem_cache *amdgpu_userq_fence_slab;
+#define AMDGPU_USERQ_MAX_HANDLES (1U << 16)
+
int amdgpu_userq_fence_slab_init(void)
{
amdgpu_userq_fence_slab = kmem_cache_create("amdgpu_userq_fence",
@@ -464,7 +466,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
struct drm_amdgpu_userq_signal *args = data;
struct drm_gem_object **gobj_write = NULL;
struct drm_gem_object **gobj_read = NULL;
- struct amdgpu_usermode_queue *queue;
+ struct amdgpu_usermode_queue *queue = NULL;
struct amdgpu_userq_fence *userq_fence;
struct drm_syncobj **syncobj = NULL;
u32 *bo_handles_write, num_write_bo_handles;
@@ -478,6 +480,11 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
if (!amdgpu_userq_enabled(dev))
return -ENOTSUPP;
+ if (args->num_syncobj_handles > AMDGPU_USERQ_MAX_HANDLES ||
+ args->num_bo_write_handles > AMDGPU_USERQ_MAX_HANDLES ||
+ args->num_bo_read_handles > AMDGPU_USERQ_MAX_HANDLES)
+ return -EINVAL;
+
num_syncobj_handles = args->num_syncobj_handles;
syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles),
size_mul(sizeof(u32), num_syncobj_handles));
@@ -546,7 +553,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
}
/* Retrieve the user queue */
- queue = xa_load(&userq_mgr->userq_xa, args->queue_id);
+ queue = amdgpu_userq_get(userq_mgr, args->queue_id);
if (!queue) {
r = -ENOENT;
goto put_gobj_write;
@@ -641,6 +648,9 @@ free_syncobj:
free_syncobj_handles:
kfree(syncobj_handles);
+ if (queue)
+ amdgpu_userq_put(queue);
+
return r;
}
@@ -653,7 +663,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
struct drm_amdgpu_userq_wait *wait_info = data;
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr;
- struct amdgpu_usermode_queue *waitq;
+ struct amdgpu_usermode_queue *waitq = NULL;
struct drm_gem_object **gobj_write;
struct drm_gem_object **gobj_read;
struct dma_fence **fences = NULL;
@@ -664,6 +674,11 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
if (!amdgpu_userq_enabled(dev))
return -ENOTSUPP;
+ if (wait_info->num_syncobj_handles > AMDGPU_USERQ_MAX_HANDLES ||
+ wait_info->num_bo_write_handles > AMDGPU_USERQ_MAX_HANDLES ||
+ wait_info->num_bo_read_handles > AMDGPU_USERQ_MAX_HANDLES)
+ return -EINVAL;
+
num_read_bo_handles = wait_info->num_bo_read_handles;
bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles),
size_mul(sizeof(u32), num_read_bo_handles));
@@ -833,7 +848,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
dma_resv_for_each_fence(&resv_cursor, gobj_read[i]->resv,
DMA_RESV_USAGE_READ, fence) {
- if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+ if (num_fences >= wait_info->num_fences) {
r = -EINVAL;
goto free_fences;
}
@@ -850,7 +865,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
dma_resv_for_each_fence(&resv_cursor, gobj_write[i]->resv,
DMA_RESV_USAGE_WRITE, fence) {
- if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+ if (num_fences >= wait_info->num_fences) {
r = -EINVAL;
goto free_fences;
}
@@ -874,8 +889,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
goto free_fences;
dma_fence_unwrap_for_each(f, &iter, fence) {
- if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+ if (num_fences >= wait_info->num_fences) {
r = -EINVAL;
+ dma_fence_put(fence);
goto free_fences;
}
@@ -898,8 +914,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
if (r)
goto free_fences;
- if (WARN_ON_ONCE(num_fences >= wait_info->num_fences)) {
+ if (num_fences >= wait_info->num_fences) {
r = -EINVAL;
+ dma_fence_put(fence);
goto free_fences;
}
@@ -912,7 +929,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
*/
num_fences = dma_fence_dedup_array(fences, num_fences);
- waitq = xa_load(&userq_mgr->userq_xa, wait_info->waitq_id);
+ waitq = amdgpu_userq_get(userq_mgr, wait_info->waitq_id);
if (!waitq) {
r = -EINVAL;
goto free_fences;
@@ -969,32 +986,14 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
r = -EFAULT;
goto free_fences;
}
-
- kfree(fences);
- kfree(fence_info);
}
- drm_exec_fini(&exec);
- for (i = 0; i < num_read_bo_handles; i++)
- drm_gem_object_put(gobj_read[i]);
- kfree(gobj_read);
-
- for (i = 0; i < num_write_bo_handles; i++)
- drm_gem_object_put(gobj_write[i]);
- kfree(gobj_write);
-
- kfree(timeline_points);
- kfree(timeline_handles);
- kfree(syncobj_handles);
- kfree(bo_handles_write);
- kfree(bo_handles_read);
-
- return 0;
-
free_fences:
- while (num_fences-- > 0)
- dma_fence_put(fences[num_fences]);
- kfree(fences);
+ if (fences) {
+ while (num_fences-- > 0)
+ dma_fence_put(fences[num_fences]);
+ kfree(fences);
+ }
free_fence_info:
kfree(fence_info);
exec_fini:
@@ -1018,5 +1017,8 @@ free_bo_handles_write:
free_bo_handles_read:
kfree(bo_handles_read);
+ if (waitq)
+ amdgpu_userq_put(waitq);
+
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index f2beb980e3c3..a677e38a493b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1069,7 +1069,10 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params,
}
/* Prepare a TLB flush fence to be attached to PTs */
- if (!params->unlocked) {
+ /* The check for need_tlb_fence should be dropped once we
+ * sort out the issues with KIQ/MES TLB invalidation timeouts.
+ */
+ if (!params->unlocked && vm->need_tlb_fence) {
amdgpu_vm_tlb_fence_create(params->adev, vm, fence);
/* Makes sure no PD/PT is freed before the flush */
@@ -2602,6 +2605,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
ttm_lru_bulk_move_init(&vm->lru_bulk_move);
vm->is_compute_context = false;
+ vm->need_tlb_fence = amdgpu_userq_enabled(&adev->ddev);
vm->use_cpu_for_update = !!(adev->vm_manager.vm_update_mode &
AMDGPU_VM_USE_CPU_FOR_GFX);
@@ -2739,6 +2743,7 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm)
dma_fence_put(vm->last_update);
vm->last_update = dma_fence_get_stub();
vm->is_compute_context = true;
+ vm->need_tlb_fence = true;
unreserve_bo:
amdgpu_bo_unreserve(vm->root.bo);
@@ -2893,6 +2898,7 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
xa_destroy(&adev->vm_manager.pasids);
amdgpu_vmid_mgr_fini(adev);
+ amdgpu_pasid_mgr_cleanup();
}
/**
@@ -2968,14 +2974,14 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
if (!root)
return false;
- addr /= AMDGPU_GPU_PAGE_SIZE;
-
if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid,
- node_id, addr, ts, write_fault)) {
+ node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
amdgpu_bo_unref(&root);
return true;
}
+ addr /= AMDGPU_GPU_PAGE_SIZE;
+
r = amdgpu_bo_reserve(root, true);
if (r)
goto error_unref;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 806d62ed61ef..d5b7061556ba 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -173,7 +173,7 @@ struct amdgpu_bo_vm;
#define AMDGPU_VA_RESERVED_SEQ64_SIZE (2ULL << 20)
#define AMDGPU_VA_RESERVED_SEQ64_START(adev) (AMDGPU_VA_RESERVED_CSA_START(adev) \
- AMDGPU_VA_RESERVED_SEQ64_SIZE)
-#define AMDGPU_VA_RESERVED_TRAP_SIZE (2ULL << 12)
+#define AMDGPU_VA_RESERVED_TRAP_SIZE (1ULL << 16)
#define AMDGPU_VA_RESERVED_TRAP_START(adev) (AMDGPU_VA_RESERVED_SEQ64_START(adev) \
- AMDGPU_VA_RESERVED_TRAP_SIZE)
#define AMDGPU_VA_RESERVED_BOTTOM (1ULL << 16)
@@ -441,6 +441,8 @@ struct amdgpu_vm {
struct ttm_lru_bulk_move lru_bulk_move;
/* Flag to indicate if VM is used for compute */
bool is_compute_context;
+ /* Flag to indicate if VM needs a TLB fence (KFD or KGD) */
+ bool need_tlb_fence;
/* Memory partition number, -1 means any partition */
int8_t mem_id;
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index e35ed0cc2ec6..8eba99aa0f8f 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -662,28 +662,35 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
} else {
switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
case IP_VERSION(9, 0, 0):
- mmhub_cid = mmhub_client_ids_vega10[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vega10) ?
+ mmhub_client_ids_vega10[cid][rw] : NULL;
break;
case IP_VERSION(9, 3, 0):
- mmhub_cid = mmhub_client_ids_vega12[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vega12) ?
+ mmhub_client_ids_vega12[cid][rw] : NULL;
break;
case IP_VERSION(9, 4, 0):
- mmhub_cid = mmhub_client_ids_vega20[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vega20) ?
+ mmhub_client_ids_vega20[cid][rw] : NULL;
break;
case IP_VERSION(9, 4, 1):
- mmhub_cid = mmhub_client_ids_arcturus[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_arcturus) ?
+ mmhub_client_ids_arcturus[cid][rw] : NULL;
break;
case IP_VERSION(9, 1, 0):
case IP_VERSION(9, 2, 0):
- mmhub_cid = mmhub_client_ids_raven[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_raven) ?
+ mmhub_client_ids_raven[cid][rw] : NULL;
break;
case IP_VERSION(1, 5, 0):
case IP_VERSION(2, 4, 0):
- mmhub_cid = mmhub_client_ids_renoir[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_renoir) ?
+ mmhub_client_ids_renoir[cid][rw] : NULL;
break;
case IP_VERSION(1, 8, 0):
case IP_VERSION(9, 4, 2):
- mmhub_cid = mmhub_client_ids_aldebaran[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_aldebaran) ?
+ mmhub_client_ids_aldebaran[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
index b3590b33cab9..485ecdec9618 100644
--- a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
@@ -129,7 +129,7 @@ static int isp_genpd_add_device(struct device *dev, void *data)
if (!pdev)
return -EINVAL;
- if (!dev->type->name) {
+ if (!dev->type || !dev->type->name) {
drm_dbg(&adev->ddev, "Invalid device type to add\n");
goto exit;
}
@@ -165,7 +165,7 @@ static int isp_genpd_remove_device(struct device *dev, void *data)
if (!pdev)
return -EINVAL;
- if (!dev->type->name) {
+ if (!dev->type || !dev->type->name) {
drm_dbg(&adev->ddev, "Invalid device type to remove\n");
goto exit;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 8c74894254f7..faac21ee5739 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -324,8 +324,10 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va,
2048);
- if (r)
+ if (r) {
+ kfree(compute_mqd);
goto free_mqd;
+ }
userq_props->eop_gpu_addr = compute_mqd->eop_va;
userq_props->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_NORMAL;
@@ -365,12 +367,16 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va,
shadow_info.shadow_size);
- if (r)
+ if (r) {
+ kfree(mqd_gfx_v11);
goto free_mqd;
+ }
r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va,
shadow_info.csa_size);
- if (r)
+ if (r) {
+ kfree(mqd_gfx_v11);
goto free_mqd;
+ }
kfree(mqd_gfx_v11);
} else if (queue->queue_type == AMDGPU_HW_IP_DMA) {
@@ -390,8 +396,10 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
}
r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va,
32);
- if (r)
+ if (r) {
+ kfree(mqd_sdma_v11);
goto free_mqd;
+ }
userq_props->csa_addr = mqd_sdma_v11->csa_va;
kfree(mqd_sdma_v11);
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
index 09ebb13ca5e8..a926a330700e 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
@@ -720,11 +720,6 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes)
mes_set_hw_res_pkt.enable_reg_active_poll = 1;
mes_set_hw_res_pkt.enable_level_process_quantum_check = 1;
mes_set_hw_res_pkt.oversubscription_timer = 50;
- if ((mes->adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x7f)
- mes_set_hw_res_pkt.enable_lr_compute_wa = 1;
- else
- dev_info_once(mes->adev->dev,
- "MES FW version must be >= 0x7f to enable LR compute workaround.\n");
if (amdgpu_mes_log_enable) {
mes_set_hw_res_pkt.enable_mes_event_int_logging = 1;
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
index b1c864dc79a8..023c7345ea54 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
@@ -731,6 +731,9 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe)
int i;
struct amdgpu_device *adev = mes->adev;
union MESAPI_SET_HW_RESOURCES mes_set_hw_res_pkt;
+ uint32_t mes_rev = (pipe == AMDGPU_MES_SCHED_PIPE) ?
+ (mes->sched_version & AMDGPU_MES_VERSION_MASK) :
+ (mes->kiq_version & AMDGPU_MES_VERSION_MASK);
memset(&mes_set_hw_res_pkt, 0, sizeof(mes_set_hw_res_pkt));
@@ -779,18 +782,13 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe)
mes_set_hw_res_pkt.use_different_vmid_compute = 1;
mes_set_hw_res_pkt.enable_reg_active_poll = 1;
mes_set_hw_res_pkt.enable_level_process_quantum_check = 1;
- if ((mes->adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x82)
- mes_set_hw_res_pkt.enable_lr_compute_wa = 1;
- else
- dev_info_once(adev->dev,
- "MES FW version must be >= 0x82 to enable LR compute workaround.\n");
/*
* Keep oversubscribe timer for sdma . When we have unmapped doorbell
* handling support, other queue will not use the oversubscribe timer.
* handling mode - 0: disabled; 1: basic version; 2: basic+ version
*/
- mes_set_hw_res_pkt.oversubscription_timer = 50;
+ mes_set_hw_res_pkt.oversubscription_timer = mes_rev < 0x8b ? 0 : 50;
mes_set_hw_res_pkt.unmapped_doorbell_handling = 1;
if (amdgpu_mes_log_enable) {
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
index a0cc8e218ca1..534cb4c544dc 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
@@ -154,14 +154,17 @@ mmhub_v2_0_print_l2_protection_fault_status(struct amdgpu_device *adev,
switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
case IP_VERSION(2, 0, 0):
case IP_VERSION(2, 0, 2):
- mmhub_cid = mmhub_client_ids_navi1x[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_navi1x) ?
+ mmhub_client_ids_navi1x[cid][rw] : NULL;
break;
case IP_VERSION(2, 1, 0):
case IP_VERSION(2, 1, 1):
- mmhub_cid = mmhub_client_ids_sienna_cichlid[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_sienna_cichlid) ?
+ mmhub_client_ids_sienna_cichlid[cid][rw] : NULL;
break;
case IP_VERSION(2, 1, 2):
- mmhub_cid = mmhub_client_ids_beige_goby[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_beige_goby) ?
+ mmhub_client_ids_beige_goby[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
index 5eb8122e2746..ceb2f6b46de5 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
@@ -94,7 +94,8 @@ mmhub_v2_3_print_l2_protection_fault_status(struct amdgpu_device *adev,
case IP_VERSION(2, 3, 0):
case IP_VERSION(2, 4, 0):
case IP_VERSION(2, 4, 1):
- mmhub_cid = mmhub_client_ids_vangogh[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_vangogh) ?
+ mmhub_client_ids_vangogh[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
index 7d5242df58a5..ab966e69a342 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
@@ -110,7 +110,8 @@ mmhub_v3_0_print_l2_protection_fault_status(struct amdgpu_device *adev,
switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
case IP_VERSION(3, 0, 0):
case IP_VERSION(3, 0, 1):
- mmhub_cid = mmhub_client_ids_v3_0_0[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_0_0) ?
+ mmhub_client_ids_v3_0_0[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
index 910337dc28d1..14a742d3a99d 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
@@ -117,7 +117,8 @@ mmhub_v3_0_1_print_l2_protection_fault_status(struct amdgpu_device *adev,
switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
case IP_VERSION(3, 0, 1):
- mmhub_cid = mmhub_client_ids_v3_0_1[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_0_1) ?
+ mmhub_client_ids_v3_0_1[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
index f0f182f033b9..e1f07f2a1852 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
@@ -108,7 +108,8 @@ mmhub_v3_0_2_print_l2_protection_fault_status(struct amdgpu_device *adev,
"MMVM_L2_PROTECTION_FAULT_STATUS:0x%08X\n",
status);
- mmhub_cid = mmhub_client_ids_v3_0_2[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_0_2) ?
+ mmhub_client_ids_v3_0_2[cid][rw] : NULL;
dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
mmhub_cid ? mmhub_cid : "unknown", cid);
dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
index 951998454b25..88bfe321f83a 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c
@@ -102,7 +102,8 @@ mmhub_v4_1_0_print_l2_protection_fault_status(struct amdgpu_device *adev,
status);
switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
case IP_VERSION(4, 1, 0):
- mmhub_cid = mmhub_client_ids_v4_1_0[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v4_1_0) ?
+ mmhub_client_ids_v4_1_0[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c
index a72770e3d0e9..2532ca80f735 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_2_0.c
@@ -688,7 +688,8 @@ mmhub_v4_2_0_print_l2_protection_fault_status(struct amdgpu_device *adev,
status);
switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
case IP_VERSION(4, 2, 0):
- mmhub_cid = mmhub_client_ids_v4_2_0[cid][rw];
+ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v4_2_0) ?
+ mmhub_client_ids_v4_2_0[cid][rw] : NULL;
break;
default:
mmhub_cid = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
index 9aa988982304..fb7aaf5ae05c 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -170,7 +170,8 @@ static int psp_v11_0_wait_for_bootloader(struct psp_context *psp)
int retry_loop;
/* For a reset done at the end of S3, only wait for TOS to be unloaded */
- if (adev->in_s3 && !(adev->flags & AMD_IS_APU) && amdgpu_in_reset(adev))
+ if ((adev->in_s4 || adev->in_s3) && !(adev->flags & AMD_IS_APU) &&
+ amdgpu_in_reset(adev))
return psp_v11_wait_for_tos_unload(psp);
for (retry_loop = 0; retry_loop < 20; retry_loop++) {
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
index 723ddae17644..73a709773e85 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
@@ -69,12 +69,12 @@ static int psp_v15_0_0_ring_stop(struct psp_context *psp,
0x80000000, 0x80000000, false);
} else {
/* Write the ring destroy command*/
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64,
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64,
GFX_CTRL_CMD_ID_DESTROY_RINGS);
/* there might be handshake issue with hardware which needs delay */
mdelay(20);
/* Wait for response flag (bit 31) */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x80000000, false);
}
@@ -116,7 +116,7 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
} else {
/* Wait for sOS ready for ring creation */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x80000000, false);
if (ret) {
DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
@@ -125,23 +125,23 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
/* Write low address of the ring to C2PMSG_69 */
psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_69, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_69, psp_ring_reg);
/* Write high address of the ring to C2PMSG_70 */
psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr);
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_70, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_70, psp_ring_reg);
/* Write size of ring to C2PMSG_71 */
psp_ring_reg = ring->ring_size;
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_71, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_71, psp_ring_reg);
/* Write the ring initialization command to C2PMSG_64 */
psp_ring_reg = ring_type;
psp_ring_reg = psp_ring_reg << 16;
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64, psp_ring_reg);
/* there might be handshake issue with hardware which needs delay */
mdelay(20);
/* Wait for response flag (bit 31) in C2PMSG_64 */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x8000FFFF, false);
}
@@ -174,7 +174,7 @@ static uint32_t psp_v15_0_0_ring_get_wptr(struct psp_context *psp)
if (amdgpu_sriov_vf(adev))
data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_102);
else
- data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67);
+ data = RREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67);
return data;
}
@@ -188,7 +188,7 @@ static void psp_v15_0_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_101,
GFX_CTRL_CMD_ID_CONSUME_CMD);
} else
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67, value);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67, value);
}
static const struct psp_funcs psp_v15_0_0_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
index 8122a5cacf07..a0ad1f8a76f0 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
@@ -858,7 +858,9 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block)
AMD_CG_SUPPORT_IH_CG |
AMD_CG_SUPPORT_BIF_MGCG |
AMD_CG_SUPPORT_BIF_LS;
- adev->pg_flags = AMD_PG_SUPPORT_VCN |
+ adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG |
+ AMD_PG_SUPPORT_VCN |
+ AMD_PG_SUPPORT_JPEG_DPG |
AMD_PG_SUPPORT_JPEG |
AMD_PG_SUPPORT_GFX_PG;
adev->external_rev_id = adev->rev_id + 0x1;
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 0202df5db1e1..6109124f852e 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -174,6 +174,10 @@ static int vcn_v5_0_0_sw_init(struct amdgpu_ip_block *ip_block)
fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE);
fw_shared->sq.is_enabled = 1;
+ fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG);
+ fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ?
+ AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU;
+
if (amdgpu_vcnfw_log)
amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 09dabb3b3297..462a32abf720 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -3170,11 +3170,11 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v
struct kfd_process *process;
int ret;
- /* Each FD owns only one kfd_process */
- if (p->context_id != KFD_CONTEXT_ID_PRIMARY)
+ if (!filep->private_data || !p)
return -EINVAL;
- if (!filep->private_data || !p)
+ /* Each FD owns only one kfd_process */
+ if (p->context_id != KFD_CONTEXT_ID_PRIMARY)
return -EINVAL;
mutex_lock(&kfd_processes_mutex);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index d5c234f30e8d..a535f151cb5f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -42,9 +42,16 @@ static uint64_t mqd_stride_v9(struct mqd_manager *mm,
struct queue_properties *q)
{
if (mm->dev->kfd->cwsr_enabled &&
- q->type == KFD_QUEUE_TYPE_COMPUTE)
- return ALIGN(q->ctl_stack_size, PAGE_SIZE) +
- ALIGN(sizeof(struct v9_mqd), PAGE_SIZE);
+ q->type == KFD_QUEUE_TYPE_COMPUTE) {
+
+ /* On gfxv9, the MQD resides in the first 4K page,
+ * followed by the control stack. Align both to
+ * AMDGPU_GPU_PAGE_SIZE to maintain the required 4K boundary.
+ */
+
+ return ALIGN(ALIGN(q->ctl_stack_size, AMDGPU_GPU_PAGE_SIZE) +
+ ALIGN(sizeof(struct v9_mqd), AMDGPU_GPU_PAGE_SIZE), PAGE_SIZE);
+ }
return mm->mqd_size;
}
@@ -151,8 +158,8 @@ static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm,
if (!mqd_mem_obj)
return NULL;
retval = amdgpu_amdkfd_alloc_kernel_mem(node->adev,
- (ALIGN(q->ctl_stack_size, PAGE_SIZE) +
- ALIGN(sizeof(struct v9_mqd), PAGE_SIZE)) *
+ (ALIGN(ALIGN(q->ctl_stack_size, AMDGPU_GPU_PAGE_SIZE) +
+ ALIGN(sizeof(struct v9_mqd), AMDGPU_GPU_PAGE_SIZE), PAGE_SIZE)) *
NUM_XCC(node->xcc_mask),
mqd_on_vram(node->adev) ? AMDGPU_GEM_DOMAIN_VRAM :
AMDGPU_GEM_DOMAIN_GTT,
@@ -360,7 +367,7 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
struct kfd_context_save_area_header header;
/* Control stack is located one page after MQD. */
- void *mqd_ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE);
+ void *mqd_ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE);
m = get_mqd(mqd);
@@ -397,7 +404,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi
{
struct v9_mqd *m;
/* Control stack is located one page after MQD. */
- void *ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE);
+ void *ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE);
m = get_mqd(mqd);
@@ -443,7 +450,7 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
*gart_addr = addr;
/* Control stack is located one page after MQD. */
- ctl_stack = (void *)((uintptr_t)*mqd + PAGE_SIZE);
+ ctl_stack = (void *)((uintptr_t)*mqd + AMDGPU_GPU_PAGE_SIZE);
memcpy(ctl_stack, ctl_stack_src, ctl_stack_size);
m->cp_hqd_pq_doorbell_control =
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index e5b56412931b..035687a17d89 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -102,8 +102,8 @@
* The first chunk is the TBA used for the CWSR ISA code. The second
* chunk is used as TMA for user-mode trap handler setup in daisy-chain mode.
*/
-#define KFD_CWSR_TBA_TMA_SIZE (PAGE_SIZE * 2)
-#define KFD_CWSR_TMA_OFFSET (PAGE_SIZE + 2048)
+#define KFD_CWSR_TBA_TMA_SIZE (AMDGPU_GPU_PAGE_SIZE * 2)
+#define KFD_CWSR_TMA_OFFSET (AMDGPU_GPU_PAGE_SIZE + 2048)
#define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE \
(KFD_MAX_NUM_OF_PROCESSES * \
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index 8ea31699d38b..f5d2847e1cbb 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -593,6 +593,7 @@ int pqm_update_queue_properties(struct process_queue_manager *pqm,
p->queue_size)) {
pr_debug("ring buf 0x%llx size 0x%llx not mapped on GPU\n",
p->queue_address, p->queue_size);
+ amdgpu_bo_unreserve(vm->root.bo);
return -EFAULT;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
index bbe869ceae3f..28354a4e5dd5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
@@ -249,10 +249,10 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
topo_dev->node_props.gfx_target_version < 90000)
/* metadata_queue_size not supported on GFX7/GFX8 */
expected_queue_size =
- properties->queue_size / 2;
+ PAGE_ALIGN(properties->queue_size / 2);
else
expected_queue_size =
- properties->queue_size + properties->metadata_queue_size;
+ PAGE_ALIGN(properties->queue_size + properties->metadata_queue_size);
vm = drm_priv_to_vm(pdd->drm_priv);
err = amdgpu_bo_reserve(vm->root.bo, false);
@@ -492,10 +492,11 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev)
cu_num = props->simd_count / props->simd_per_cu / NUM_XCC(dev->gpu->xcc_mask);
wave_num = get_num_waves(props, gfxv, cu_num);
- wg_data_size = ALIGN(cu_num * WG_CONTEXT_DATA_SIZE_PER_CU(gfxv, props), PAGE_SIZE);
+ wg_data_size = ALIGN(cu_num * WG_CONTEXT_DATA_SIZE_PER_CU(gfxv, props),
+ AMDGPU_GPU_PAGE_SIZE);
ctl_stack_size = wave_num * CNTL_STACK_BYTES_PER_WAVE(gfxv) + 8;
ctl_stack_size = ALIGN(SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER + ctl_stack_size,
- PAGE_SIZE);
+ AMDGPU_GPU_PAGE_SIZE);
if ((gfxv / 10000 * 10000) == 100000) {
/* HW design limits control stack size to 0x7000.
@@ -507,7 +508,7 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev)
props->ctl_stack_size = ctl_stack_size;
props->debug_memory_size = ALIGN(wave_num * DEBUGGER_BYTES_PER_WAVE, DEBUGGER_BYTES_ALIGN);
- props->cwsr_size = ctl_stack_size + wg_data_size;
+ props->cwsr_size = ALIGN(ctl_stack_size + wg_data_size, PAGE_SIZE);
if (gfxv == 80002) /* GFX_VERSION_TONGA */
props->eop_buffer_size = 0x8000;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index b3d6f2cd8ab6..2328c1aa0ead 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2554,7 +2554,7 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
PSP_HEADER_BYTES_256;
- fw_meta_info_params.fw_bss_data = region_params.bss_data_size ? adev->dm.dmub_fw->data +
+ fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
le32_to_cpu(hdr->inst_const_bytes) : NULL;
fw_meta_info_params.custom_psp_footer_size = 0;
@@ -3909,8 +3909,9 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->dc_sink = sink;
dc_sink_retain(aconnector->dc_sink);
+ drm_edid_free(aconnector->drm_edid);
+ aconnector->drm_edid = NULL;
if (sink->dc_edid.length == 0) {
- aconnector->drm_edid = NULL;
hdmi_cec_unset_edid(aconnector);
if (aconnector->dc_link->aux_mode) {
drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
@@ -5422,7 +5423,7 @@ static void setup_backlight_device(struct amdgpu_display_manager *dm,
caps = &dm->backlight_caps[aconnector->bl_idx];
/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */
- if (!caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
+ if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
drm_object_attach_property(&aconnector->base.base,
dm->adev->mode_info.abm_level_property,
ABM_SYSFS_CONTROL);
@@ -12524,6 +12525,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
if (dc_resource_is_dsc_encoding_supported(dc)) {
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed;
+ }
+
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
ret = add_affected_mst_dsc_crtcs(state, crtc);
if (ret) {
@@ -13119,7 +13125,7 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
u16 min_vfreq;
u16 max_vfreq;
- if (edid == NULL || edid->extensions == 0)
+ if (!edid || !edid->extensions)
return;
/* Find DisplayID extension */
@@ -13129,7 +13135,7 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector,
break;
}
- if (edid_ext == NULL)
+ if (i == edid->extensions)
return;
while (j < EDID_LENGTH) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 800813671748..d15812d51d72 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -984,6 +984,7 @@ struct dm_crtc_state {
bool freesync_vrr_info_changed;
+ bool mode_changed_independent_from_dsc;
bool dsc_force_changed;
bool vrr_supported;
struct mod_freesync_config freesync_config;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 2ba98f384685..cd1e58b8defc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1706,6 +1706,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
struct drm_atomic_state *state = plane_state->state;
const struct amdgpu_device *adev = drm_to_adev(colorop->dev);
+ bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
const struct drm_device *dev = colorop->dev;
const struct drm_color_lut32 *lut3d;
uint32_t lut3d_size;
@@ -1722,7 +1723,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
}
if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_3D_LUT) {
- if (!adev->dm.dc->caps.color.dpp.hw_3d_lut) {
+ if (!has_3dlut) {
drm_dbg(dev, "3D LUT is not supported by hardware\n");
return -EINVAL;
}
@@ -1875,6 +1876,7 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
struct drm_colorop *colorop = plane_state->color_pipeline;
struct drm_device *dev = plane_state->plane->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
+ bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
int ret;
/* 1D Curve - DEGAM TF */
@@ -1907,7 +1909,7 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
if (ret)
return ret;
- if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
+ if (has_3dlut) {
/* 1D Curve & LUT - SHAPER TF & LUT */
colorop = colorop->next;
if (!colorop) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index f25c0ede7199..aa4658867e55 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -37,19 +37,19 @@ const u64 amdgpu_dm_supported_degam_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
- BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
+ BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
const u64 amdgpu_dm_supported_shaper_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_BT2020_OETF) |
- BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
+ BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
const u64 amdgpu_dm_supported_blnd_tfs =
BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_PQ_125_EOTF) |
BIT(DRM_COLOROP_1D_CURVE_BT2020_INV_OETF) |
- BIT(DRM_COLOROP_1D_CURVE_GAMMA22_INV);
+ BIT(DRM_COLOROP_1D_CURVE_GAMMA22);
#define MAX_COLOR_PIPELINE_OPS 10
@@ -60,6 +60,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
struct drm_device *dev = plane->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
+ bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
int ret;
int i = 0;
@@ -112,7 +113,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
i++;
- if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
+ if (has_3dlut) {
/* 1D curve - SHAPER TF */
ops[i] = kzalloc_obj(*ops[0]);
if (!ops[i]) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 130190e8a1b2..304437c2284d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -765,15 +765,15 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
dm->adev->mode_info.crtcs[crtc_index] = acrtc;
/* Don't enable DRM CRTC degamma property for
- * 1. Degamma is replaced by color pipeline.
- * 2. DCE since it doesn't support programmable degamma anywhere.
- * 3. DCN401 since pre-blending degamma LUT doesn't apply to cursor.
+ * 1. DCE since it doesn't support programmable degamma anywhere.
+ * 2. DCN401 since pre-blending degamma LUT doesn't apply to cursor.
+ * Note: DEGAMMA properties are created even if the primary plane has the
+ * COLOR_PIPELINE property. User space can use either the DEGAMMA properties
+ * or the COLOR_PIPELINE property. An atomic commit which attempts to enable
+ * both is rejected.
*/
- if (plane->color_pipeline_property)
- has_degamma = false;
- else
- has_degamma = dm->adev->dm.dc->caps.color.dpp.dcn_arch &&
- dm->adev->dm.dc->ctx->dce_version != DCN_VERSION_4_01;
+ has_degamma = dm->adev->dm.dc->caps.color.dpp.dcn_arch &&
+ dm->adev->dm.dc->ctx->dce_version != DCN_VERSION_4_01;
drm_crtc_enable_color_mgmt(&acrtc->base, has_degamma ? MAX_COLOR_LUT_ENTRIES : 0,
true, MAX_COLOR_LUT_ENTRIES);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 7be50e8c0636..5d8c4c7020b1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1744,9 +1744,11 @@ int pre_validate_dsc(struct drm_atomic_state *state,
int ind = find_crtc_index_in_state_by_stream(state, stream);
if (ind >= 0) {
+ struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(state->crtcs[ind].new_state);
+
DRM_INFO_ONCE("%s:%d MST_DSC no mode changed for stream 0x%p\n",
__func__, __LINE__, stream);
- state->crtcs[ind].new_state->mode_changed = 0;
+ dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc;
}
}
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 70587e5a8d46..127207e18dcb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1256,6 +1256,14 @@ static int amdgpu_dm_plane_atomic_check(struct drm_plane *plane,
if (ret)
return ret;
+ /* Reject commits that attempt to use both COLOR_PIPELINE and CRTC DEGAMMA_LUT */
+ if (new_plane_state->color_pipeline && new_crtc_state->degamma_lut) {
+ drm_dbg_atomic(plane->dev,
+ "[PLANE:%d:%s] COLOR_PIPELINE and CRTC DEGAMMA_LUT cannot be enabled simultaneously\n",
+ plane->base.id, plane->name);
+ return -EINVAL;
+ }
+
ret = amdgpu_dm_plane_fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
index 08d0e05a313e..d237d7b41dfd 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
@@ -255,6 +255,10 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
BREAK_TO_DEBUGGER();
return NULL;
}
+ if (ctx->dce_version == DCN_VERSION_2_01) {
+ dcn201_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
+ return &clk_mgr->base;
+ }
if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev)) {
dcn3_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
return &clk_mgr->base;
@@ -267,10 +271,6 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
dcn3_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
return &clk_mgr->base;
}
- if (ctx->dce_version == DCN_VERSION_2_01) {
- dcn201_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
- return &clk_mgr->base;
- }
dcn20_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
return &clk_mgr->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 246893d80f1f..baf820e6eae8 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -170,11 +170,11 @@ struct dc_stream_state *dc_create_stream_for_sink(
if (sink == NULL)
goto fail;
- stream = kzalloc_obj(struct dc_stream_state);
+ stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC);
if (stream == NULL)
goto fail;
- stream->update_scratch = kzalloc((int32_t) dc_update_scratch_space_size(), GFP_KERNEL);
+ stream->update_scratch = kzalloc((int32_t) dc_update_scratch_space_size(), GFP_ATOMIC);
if (stream->update_scratch == NULL)
goto fail;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h
index 3711d400773a..4c4e61bc91b5 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.h
@@ -38,7 +38,11 @@
DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0),\
DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1),\
SR(DISPCLK_FREQ_CHANGE_CNTL),\
- SR(DC_MEM_GLOBAL_PWR_REQ_CNTL)
+ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
+ SR(MICROSECOND_TIME_BASE_DIV),\
+ SR(MILLISECOND_TIME_BASE_DIV),\
+ SR(DCCG_GATE_DISABLE_CNTL),\
+ SR(DCCG_GATE_DISABLE_CNTL2)
#define DCCG_REG_LIST_DCN2() \
DCCG_COMMON_REG_LIST_DCN_BASE(),\
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
index 75c69348027e..c4d4eea140f3 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
@@ -96,6 +96,25 @@ static void dccg21_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppcl
dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk;
}
+/*
+ * On DCN21 S0i3 resume, BIOS programs MICROSECOND_TIME_BASE_DIV to
+ * 0x00120464 as a marker that golden init has already been done.
+ * dcn21_s0i3_golden_init_wa() reads this marker later in bios_golden_init()
+ * to decide whether to skip golden init.
+ *
+ * dccg2_init() unconditionally overwrites MICROSECOND_TIME_BASE_DIV to
+ * 0x00120264, destroying the marker before it can be read.
+ *
+ * Guard the call: if the S0i3 marker is present, skip dccg2_init() so the
+ * WA can function correctly. bios_golden_init() will handle init in that case.
+ */
+static void dccg21_init(struct dccg *dccg)
+{
+ if (dccg2_is_s0i3_golden_init_wa_done(dccg))
+ return;
+
+ dccg2_init(dccg);
+}
static const struct dccg_funcs dccg21_funcs = {
.update_dpp_dto = dccg21_update_dpp_dto,
@@ -103,7 +122,7 @@ static const struct dccg_funcs dccg21_funcs = {
.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
.otg_add_pixel = dccg2_otg_add_pixel,
.otg_drop_pixel = dccg2_otg_drop_pixel,
- .dccg_init = dccg2_init,
+ .dccg_init = dccg21_init,
.refclk_setup = dccg2_refclk_setup, /* Deprecated - for backward compatibility only */
.allow_clock_gating = dccg2_allow_clock_gating,
.enable_memory_low_power = dccg2_enable_memory_low_power,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.h
index 067e49cb238e..e2381ca0be0b 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.h
@@ -34,7 +34,13 @@
DCCG_SRII(DTO_PARAM, DPPCLK, 1),\
DCCG_SRII(DTO_PARAM, DPPCLK, 2),\
DCCG_SRII(DTO_PARAM, DPPCLK, 3),\
- SR(REFCLK_CNTL)
+ SR(REFCLK_CNTL),\
+ SR(DISPCLK_FREQ_CHANGE_CNTL),\
+ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
+ SR(MICROSECOND_TIME_BASE_DIV),\
+ SR(MILLISECOND_TIME_BASE_DIV),\
+ SR(DCCG_GATE_DISABLE_CNTL),\
+ SR(DCCG_GATE_DISABLE_CNTL2)
#define DCCG_MASK_SH_LIST_DCN301(mask_sh) \
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
index bf659920d4cc..b5e3849ef12a 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.h
@@ -64,9 +64,12 @@
SR(DSCCLK1_DTO_PARAM),\
SR(DSCCLK2_DTO_PARAM),\
SR(DSCCLK_DTO_CTRL),\
+ SR(DCCG_GATE_DISABLE_CNTL),\
SR(DCCG_GATE_DISABLE_CNTL2),\
SR(DCCG_GATE_DISABLE_CNTL3),\
- SR(HDMISTREAMCLK0_DTO_PARAM)
+ SR(HDMISTREAMCLK0_DTO_PARAM),\
+ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
+ SR(MICROSECOND_TIME_BASE_DIV)
#define DCCG_MASK_SH_LIST_DCN31(mask_sh) \
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.h
index a609635f35db..ecbdc05f7c45 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.h
@@ -70,11 +70,14 @@
SR(DSCCLK2_DTO_PARAM),\
SR(DSCCLK3_DTO_PARAM),\
SR(DSCCLK_DTO_CTRL),\
+ SR(DCCG_GATE_DISABLE_CNTL),\
SR(DCCG_GATE_DISABLE_CNTL2),\
SR(DCCG_GATE_DISABLE_CNTL3),\
SR(HDMISTREAMCLK0_DTO_PARAM),\
SR(OTG_PIXEL_RATE_DIV),\
- SR(DTBCLK_P_CNTL)
+ SR(DTBCLK_P_CNTL),\
+ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),\
+ SR(MICROSECOND_TIME_BASE_DIV)
#define DCCG_MASK_SH_LIST_DCN314_COMMON(mask_sh) \
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index b91517b9fedc..4dfb6c865831 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -72,7 +72,11 @@ void dcn401_initialize_min_clocks(struct dc *dc)
* audio corruption. Read current DISPCLK from DENTIST and request the same
* freq to ensure that the timing is valid and unchanged.
*/
- clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
+ if (dc->clk_mgr->funcs->get_dispclk_from_dentist) {
+ clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
+ } else {
+ clocks->dispclk_khz = dc->clk_mgr->boot_snapshot.dispclk * 1000;
+ }
}
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
clocks->fclk_p_state_change_support = true;
@@ -143,6 +147,7 @@ void dcn401_init_hw(struct dc *dc)
int edp_num;
uint32_t backlight = MAX_BACKLIGHT_LEVEL;
uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+ bool dchub_ref_freq_changed;
int current_dchub_ref_freq = 0;
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
@@ -356,14 +361,18 @@ void dcn401_init_hw(struct dc *dc)
dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
+
+ /* sw and fw FAMS versions must match for support */
dc->debug.fams2_config.bits.enable &=
- dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support
- if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box)
- || res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) {
+ dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver;
+ dchub_ref_freq_changed =
+ res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq;
+ if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) &&
+ dc->res_pool->funcs->update_bw_bounding_box &&
+ dc->clk_mgr && dc->clk_mgr->bw_params) {
/* update bounding box if FAMS2 disabled, or if dchub clk has changed */
- if (dc->clk_mgr)
- dc->res_pool->funcs->update_bw_bounding_box(dc,
- dc->clk_mgr->bw_params);
+ dc->res_pool->funcs->update_bw_bounding_box(dc,
+ dc->clk_mgr->bw_params);
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c
index 92c123aca0c9..fdcf8db6be50 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c
@@ -650,9 +650,6 @@ static struct link_encoder *dce100_link_encoder_create(
return &enc110->base;
}
- if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
- return NULL;
-
link_regs_id =
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
@@ -661,7 +658,8 @@ static struct link_encoder *dce100_link_encoder_create(
&link_enc_feature,
&link_enc_regs[link_regs_id],
&link_enc_aux_regs[enc_init_data->channel - 1],
- &link_enc_hpd_regs[enc_init_data->hpd_source]);
+ enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
+ NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c
index 95852d277c22..ab71f645c90e 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c
@@ -671,7 +671,7 @@ static struct link_encoder *dce110_link_encoder_create(
kzalloc_obj(struct dce110_link_encoder);
int link_regs_id;
- if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
+ if (!enc110)
return NULL;
link_regs_id =
@@ -682,7 +682,8 @@ static struct link_encoder *dce110_link_encoder_create(
&link_enc_feature,
&link_enc_regs[link_regs_id],
&link_enc_aux_regs[enc_init_data->channel - 1],
- &link_enc_hpd_regs[enc_init_data->hpd_source]);
+ enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
+ NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c
index 58c6a00397cf..b7051bfd4326 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c
@@ -632,7 +632,7 @@ static struct link_encoder *dce112_link_encoder_create(
kzalloc_obj(struct dce110_link_encoder);
int link_regs_id;
- if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
+ if (!enc110)
return NULL;
link_regs_id =
@@ -643,7 +643,8 @@ static struct link_encoder *dce112_link_encoder_create(
&link_enc_feature,
&link_enc_regs[link_regs_id],
&link_enc_aux_regs[enc_init_data->channel - 1],
- &link_enc_hpd_regs[enc_init_data->hpd_source]);
+ enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
+ NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c
index 71d76b021375..7ee70f7b3aa7 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c
@@ -716,7 +716,7 @@ static struct link_encoder *dce120_link_encoder_create(
kzalloc_obj(struct dce110_link_encoder);
int link_regs_id;
- if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
+ if (!enc110)
return NULL;
link_regs_id =
@@ -727,7 +727,8 @@ static struct link_encoder *dce120_link_encoder_create(
&link_enc_feature,
&link_enc_regs[link_regs_id],
&link_enc_aux_regs[enc_init_data->channel - 1],
- &link_enc_hpd_regs[enc_init_data->hpd_source]);
+ enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
+ NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c
index c27645708286..3d52973dd7f2 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c
@@ -746,18 +746,16 @@ static struct link_encoder *dce60_link_encoder_create(
return &enc110->base;
}
- if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
- return NULL;
-
link_regs_id =
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
dce60_link_encoder_construct(enc110,
- enc_init_data,
- &link_enc_feature,
- &link_enc_regs[link_regs_id],
- &link_enc_aux_regs[enc_init_data->channel - 1],
- &link_enc_hpd_regs[enc_init_data->hpd_source]);
+ enc_init_data,
+ &link_enc_feature,
+ &link_enc_regs[link_regs_id],
+ &link_enc_aux_regs[enc_init_data->channel - 1],
+ enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
+ NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c
index d66d8ac6d897..89927727a0d9 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c
@@ -752,9 +752,6 @@ static struct link_encoder *dce80_link_encoder_create(
return &enc110->base;
}
- if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
- return NULL;
-
link_regs_id =
map_transmitter_id_to_phy_instance(enc_init_data->transmitter);
@@ -763,7 +760,8 @@ static struct link_encoder *dce80_link_encoder_create(
&link_enc_feature,
&link_enc_regs[link_regs_id],
&link_enc_aux_regs[enc_init_data->channel - 1],
- &link_enc_hpd_regs[enc_init_data->hpd_source]);
+ enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ?
+ NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);
return &enc110->base;
}
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c
index bbe185e15eb6..4663456a736a 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c
@@ -71,6 +71,7 @@
#include "dce/dce_dmcu.h"
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
+#include "dio/dcn10/dcn10_dio.h"
#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f
@@ -444,6 +445,33 @@ static const struct dcn_hubbub_mask hubbub_mask = {
HUBBUB_MASK_SH_LIST_DCN10(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn10_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static int map_transmitter_id_to_phy_instance(
enum transmitter transmitter)
{
@@ -917,6 +945,11 @@ static void dcn10_resource_destruct(struct dcn10_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.opps[i] != NULL)
pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]);
@@ -1653,6 +1686,14 @@ static bool dcn10_resource_construct(
goto fail;
}
+ /* DIO */
+ pool->base.dio = dcn10_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto fail;
+ }
+
if (!resource_construct(num_virtual_links, dc, &pool->base,
&res_create_funcs))
goto fail;
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
index 8b555187ac75..74e8d229c9dd 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c
@@ -82,6 +82,7 @@
#include "dce/dce_dmcu.h"
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "vm_helper.h"
#include "link_enc_cfg.h"
@@ -550,6 +551,33 @@ static const struct dcn_hubbub_mask hubbub_mask = {
HUBBUB_MASK_SH_LIST_DCN20(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn20_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
#define vmid_regs(id)\
[id] = {\
DCN20_VMID_REG_LIST(id)\
@@ -1104,6 +1132,12 @@ static void dcn20_resource_destruct(struct dcn20_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn20_dpp_destroy(&pool->base.dpps[i]);
@@ -2692,6 +2726,14 @@ static bool dcn20_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn20_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn20_dsc_create(ctx, i);
if (pool->base.dscs[i] == NULL) {
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
index 4ea76e46ab15..e289be70efb5 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c
@@ -56,6 +56,7 @@
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
#include "dcn10/dcn10_resource.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "cyan_skillfish_ip_offset.h"
@@ -755,6 +756,33 @@ static struct hubbub *dcn201_hubbub_create(struct dc_context *ctx)
return &hubbub->base;
}
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn201_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct timing_generator *dcn201_timing_generator_create(
struct dc_context *ctx,
uint32_t instance)
@@ -930,6 +958,11 @@ static void dcn201_resource_destruct(struct dcn201_resource_pool *pool)
pool->base.hubbub = NULL;
}
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn201_dpp_destroy(&pool->base.dpps[i]);
@@ -1276,6 +1309,14 @@ static bool dcn201_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn201_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
if (!resource_construct(num_virtual_links, dc, &pool->base,
&res_create_funcs))
goto create_fail;
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
index 0f4307f8f3dd..4333baac96ad 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
@@ -84,6 +84,7 @@
#include "dce/dce_dmcu.h"
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dcn21_resource.h"
#include "vm_helper.h"
#include "dcn20/dcn20_vmid.h"
@@ -329,6 +330,25 @@ static const struct dcn_hubbub_mask hubbub_mask = {
HUBBUB_MASK_SH_LIST_DCN21(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+static const struct dcn_dio_shift dio_shift = { 0 };
+
+static const struct dcn_dio_mask dio_mask = { 0 };
+
+static struct dio *dcn21_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
#define vmid_regs(id)\
[id] = {\
@@ -677,6 +697,12 @@ static void dcn21_resource_destruct(struct dcn21_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn20_dpp_destroy(&pool->base.dpps[i]);
@@ -1654,6 +1680,14 @@ static bool dcn21_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn21_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn21_dsc_create(ctx, i);
if (pool->base.dscs[i] == NULL) {
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
index 2fa86b9587ed..87b7b4ee04c6 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c
@@ -60,6 +60,7 @@
#include "dml/display_mode_vba.h"
#include "dcn30/dcn30_dccg.h"
#include "dcn10/dcn10_resource.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "link_service.h"
#include "dce/dce_panel_cntl.h"
@@ -886,6 +887,33 @@ static struct hubbub *dcn30_hubbub_create(struct dc_context *ctx)
return &hubbub3->base;
}
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn30_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct timing_generator *dcn30_timing_generator_create(
struct dc_context *ctx,
uint32_t instance)
@@ -1095,6 +1123,12 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn30_dpp_destroy(&pool->base.dpps[i]);
@@ -2464,6 +2498,14 @@ static bool dcn30_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn30_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn30_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c
index 7842bee57e63..6bb1c62124bb 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c
@@ -59,6 +59,7 @@
#include "dml/display_mode_vba.h"
#include "dcn301/dcn301_dccg.h"
#include "dcn10/dcn10_resource.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dcn30/dcn30_dio_stream_encoder.h"
#include "dcn301/dcn301_dio_link_encoder.h"
#include "dcn301/dcn301_panel_cntl.h"
@@ -843,6 +844,33 @@ static struct hubbub *dcn301_hubbub_create(struct dc_context *ctx)
return &hubbub3->base;
}
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn301_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct timing_generator *dcn301_timing_generator_create(
struct dc_context *ctx, uint32_t instance)
{
@@ -1066,6 +1094,12 @@ static void dcn301_destruct(struct dcn301_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn301_dpp_destroy(&pool->base.dpps[i]);
@@ -1582,6 +1616,14 @@ static bool dcn301_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn301_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
j = 0;
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c
index 1874d5d6b782..d02aafd06fd4 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c
@@ -46,6 +46,7 @@
#include "dml/dcn30/dcn30_fpu.h"
#include "dcn10/dcn10_resource.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "link_service.h"
@@ -253,6 +254,33 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn302_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn302_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1022,6 +1050,11 @@ static void dcn302_resource_destruct(struct resource_pool *pool)
pool->hubbub = NULL;
}
+ if (pool->dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->dio));
+ pool->dio = NULL;
+ }
+
for (i = 0; i < pool->pipe_count; i++) {
if (pool->dpps[i] != NULL) {
kfree(TO_DCN20_DPP(pool->dpps[i]));
@@ -1372,6 +1405,14 @@ static bool dcn302_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->dio = dcn302_dio_create(ctx);
+ if (pool->dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->pipe_count; i++) {
pool->hubps[i] = dcn302_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c
index d52201cb359f..30b1403112c6 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c
@@ -46,6 +46,7 @@
#include "dml/dcn30/dcn30_fpu.h"
#include "dcn10/dcn10_resource.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "link_service.h"
@@ -249,6 +250,33 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
+static struct dio *dcn303_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn303_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -966,6 +994,11 @@ static void dcn303_resource_destruct(struct resource_pool *pool)
pool->hubbub = NULL;
}
+ if (pool->dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->dio));
+ pool->dio = NULL;
+ }
+
for (i = 0; i < pool->pipe_count; i++) {
if (pool->dpps[i] != NULL) {
kfree(TO_DCN20_DPP(pool->dpps[i]));
@@ -1304,6 +1337,14 @@ static bool dcn303_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->dio = dcn303_dio_create(ctx);
+ if (pool->dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->pipe_count; i++) {
pool->hubps[i] = dcn303_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
index 2055f1f8af65..4e9c041c707a 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
@@ -64,6 +64,7 @@
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dio/virtual/virtual_stream_encoder.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
@@ -810,6 +811,21 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn31 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -1021,6 +1037,18 @@ static struct mpc *dcn31_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn31_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1396,6 +1424,10 @@ static void dcn31_resource_destruct(struct dcn31_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn31_dpp_destroy(&pool->base.dpps[i]);
@@ -2063,6 +2095,14 @@ static bool dcn31_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn31_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn31_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
index 1939f720ba29..e26a6427916a 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c
@@ -66,6 +66,7 @@
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dio/virtual/virtual_stream_encoder.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
@@ -822,6 +823,21 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn314 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -1079,6 +1095,18 @@ static struct mpc *dcn31_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn314_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1455,6 +1483,10 @@ static void dcn314_resource_destruct(struct dcn314_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn31_dpp_destroy(&pool->base.dpps[i]);
@@ -1987,6 +2019,14 @@ static bool dcn314_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn314_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn31_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
index e8377c190f63..131a6cd4c735 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
@@ -63,6 +63,7 @@
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dio/virtual/virtual_stream_encoder.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
@@ -809,6 +810,21 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn31 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -1020,6 +1036,18 @@ static struct mpc *dcn31_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn315_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1397,6 +1425,10 @@ static void dcn315_resource_destruct(struct dcn315_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn31_dpp_destroy(&pool->base.dpps[i]);
@@ -2012,6 +2044,14 @@ static bool dcn315_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn315_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn31_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
index 045ce01bd74e..c8c0ce6efcfd 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
@@ -63,6 +63,7 @@
#include "dce/dce_audio.h"
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dio/virtual/virtual_stream_encoder.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
@@ -804,6 +805,21 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static const struct dcn_dio_registers dio_regs = {
+ DIO_REG_LIST_DCN10()
+};
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn31 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -1013,6 +1029,18 @@ static struct mpc *dcn31_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn316_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1392,6 +1420,10 @@ static void dcn316_resource_destruct(struct dcn316_resource_pool *pool)
kfree(pool->base.hubbub);
pool->base.hubbub = NULL;
}
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
for (i = 0; i < pool->base.pipe_count; i++) {
if (pool->base.dpps[i] != NULL)
dcn31_dpp_destroy(&pool->base.dpps[i]);
@@ -1887,6 +1919,14 @@ static bool dcn316_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn316_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn31_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
index 7ebb7d1193af..c3a6ae14de18 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
@@ -66,6 +66,7 @@
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
#include "dio/virtual/virtual_stream_encoder.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dml/display_mode_vba.h"
#include "dcn32/dcn32_dccg.h"
#include "dcn10/dcn10_resource.h"
@@ -643,6 +644,19 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static struct dcn_dio_registers dio_regs;
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn32 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -833,6 +847,22 @@ static struct clock_source *dcn32_clock_source_create(
return NULL;
}
+static struct dio *dcn32_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dio_regs
+ DIO_REG_LIST_DCN10();
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1494,6 +1524,11 @@ static void dcn32_resource_destruct(struct dcn32_resource_pool *pool)
if (pool->base.dccg != NULL)
dcn_dccg_destroy(&pool->base.dccg);
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
if (pool->base.oem_device != NULL) {
struct dc *dc = pool->base.oem_device->ctx->dc;
@@ -1785,7 +1820,10 @@ static bool dml1_validate(struct dc *dc, struct dc_state *context, enum dc_valid
dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
+ DC_FP_START();
dcn32_override_min_req_memclk(dc, context);
+ DC_FP_END();
+
dcn32_override_min_req_dcfclk(dc, context);
BW_VAL_TRACE_END_WATERMARKS();
@@ -2370,6 +2408,14 @@ static bool dcn32_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn32_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs, TGs, ABMs */
for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) {
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
index c1582c27ac87..990aec7eb3d0 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
@@ -69,6 +69,7 @@
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
#include "dio/virtual/virtual_stream_encoder.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dml/display_mode_vba.h"
#include "dcn32/dcn32_dccg.h"
#include "dcn10/dcn10_resource.h"
@@ -639,6 +640,19 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static struct dcn_dio_registers dio_regs;
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn321 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -827,6 +841,22 @@ static struct clock_source *dcn321_clock_source_create(
return NULL;
}
+static struct dio *dcn321_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dio_regs
+ DIO_REG_LIST_DCN10();
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn321_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1474,6 +1504,11 @@ static void dcn321_resource_destruct(struct dcn321_resource_pool *pool)
if (pool->base.dccg != NULL)
dcn_dccg_destroy(&pool->base.dccg);
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
+
if (pool->base.oem_device != NULL) {
struct dc *dc = pool->base.oem_device->ctx->dc;
@@ -1872,6 +1907,14 @@ static bool dcn321_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn321_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs, TGs, ABMs */
for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) {
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
index 3494a40cea99..598b2f25881d 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
@@ -71,6 +71,7 @@
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
#include "dio/virtual/virtual_stream_encoder.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
#include "dcn35/dcn35_dccg.h"
@@ -664,6 +665,19 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static struct dcn_dio_registers dio_regs;
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn35 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -973,6 +987,22 @@ static struct mpc *dcn35_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn35_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dio_regs
+ DIO_REG_LIST_DCN10();
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1563,6 +1593,11 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool)
if (pool->base.dccg != NULL)
dcn_dccg_destroy(&pool->base.dccg);
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
}
static struct hubp *dcn35_hubp_create(
@@ -2033,6 +2068,14 @@ static bool dcn35_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn35_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn35_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
index 080bc7f24ffa..7e15d07df7a3 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
@@ -50,6 +50,7 @@
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
#include "dio/virtual/virtual_stream_encoder.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
#include "dcn35/dcn35_dccg.h"
@@ -644,6 +645,19 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static struct dcn_dio_registers dio_regs;
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn351 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -953,6 +967,22 @@ static struct mpc *dcn35_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn351_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dio_regs
+ DIO_REG_LIST_DCN10();
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1543,6 +1573,11 @@ static void dcn351_resource_destruct(struct dcn351_resource_pool *pool)
if (pool->base.dccg != NULL)
dcn_dccg_destroy(&pool->base.dccg);
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
}
static struct hubp *dcn35_hubp_create(
@@ -2005,6 +2040,14 @@ static bool dcn351_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn351_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn35_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
index af51ac4ea59e..83fee2ca61bf 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
@@ -50,6 +50,7 @@
#include "dce/dce_hwseq.h"
#include "clk_mgr.h"
#include "dio/virtual/virtual_stream_encoder.h"
+#include "dio/dcn10/dcn10_dio.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
#include "dcn35/dcn35_dccg.h"
@@ -651,6 +652,19 @@ static const struct dcn20_vmid_mask vmid_masks = {
DCN20_VMID_MASK_SH_LIST(_MASK)
};
+static struct dcn_dio_registers dio_regs;
+
+#define DIO_MASK_SH_LIST(mask_sh)\
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh)
+
+static const struct dcn_dio_shift dio_shift = {
+ DIO_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn_dio_mask dio_mask = {
+ DIO_MASK_SH_LIST(_MASK)
+};
+
static const struct resource_caps res_cap_dcn36 = {
.num_timing_generator = 4,
.num_opp = 4,
@@ -960,6 +974,22 @@ static struct mpc *dcn35_mpc_create(
return &mpc30->base;
}
+static struct dio *dcn36_dio_create(struct dc_context *ctx)
+{
+ struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio);
+
+ if (!dio10)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dio_regs
+ DIO_REG_LIST_DCN10();
+
+ dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask);
+
+ return &dio10->base;
+}
+
static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx)
{
int i;
@@ -1550,6 +1580,11 @@ static void dcn36_resource_destruct(struct dcn36_resource_pool *pool)
if (pool->base.dccg != NULL)
dcn_dccg_destroy(&pool->base.dccg);
+
+ if (pool->base.dio != NULL) {
+ kfree(TO_DCN10_DIO(pool->base.dio));
+ pool->base.dio = NULL;
+ }
}
static struct hubp *dcn35_hubp_create(
@@ -2012,6 +2047,14 @@ static bool dcn36_resource_construct(
goto create_fail;
}
+ /* DIO */
+ pool->base.dio = dcn36_dio_create(ctx);
+ if (pool->base.dio == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dio!\n");
+ goto create_fail;
+ }
+
/* HUBPs, DPPs, OPPs and TGs */
for (i = 0; i < pool->base.pipe_count; i++) {
pool->base.hubps[i] = dcn35_hubp_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h
index 0e4c195297a4..fe97943b9b97 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h
@@ -82,6 +82,24 @@
#define regMPASP_SMN_IH_SW_INT_CTRL 0x0142
#define regMPASP_SMN_IH_SW_INT_CTRL_BASE_IDX 0
+// addressBlock: mp_SmuMpASPPub_PcruDec
+// base address: 0x3800000
+#define regMPASP_PCRU1_MPASP_C2PMSG_64 0x4280
+#define regMPASP_PCRU1_MPASP_C2PMSG_64_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_65 0x4281
+#define regMPASP_PCRU1_MPASP_C2PMSG_65_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_66 0x4282
+#define regMPASP_PCRU1_MPASP_C2PMSG_66_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_67 0x4283
+#define regMPASP_PCRU1_MPASP_C2PMSG_67_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_68 0x4284
+#define regMPASP_PCRU1_MPASP_C2PMSG_68_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_69 0x4285
+#define regMPASP_PCRU1_MPASP_C2PMSG_69_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_70 0x4286
+#define regMPASP_PCRU1_MPASP_C2PMSG_70_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_71 0x4287
+#define regMPASP_PCRU1_MPASP_C2PMSG_71_BASE_IDX 3
// addressBlock: mp_SmuMp1_SmnDec
// base address: 0x0
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index 61b1c5aa74cb..36942467d4ad 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -3454,9 +3454,11 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev,
if (adev->asic_type == CHIP_HAINAN) {
if ((adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0xC3) ||
+ (adev->pdev->device == 0x6660) ||
(adev->pdev->device == 0x6664) ||
(adev->pdev->device == 0x6665) ||
- (adev->pdev->device == 0x6667)) {
+ (adev->pdev->device == 0x6667) ||
+ (adev->pdev->device == 0x666F)) {
max_sclk = 75000;
}
if ((adev->pdev->revision == 0xC3) ||
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index 12b052d920f5..7ca8fdd23206 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -262,7 +262,6 @@ int smu_v11_0_check_fw_version(struct smu_context *smu)
"smu fw program = %d, version = 0x%08x (%d.%d.%d)\n",
smu->smc_driver_if_version, if_version,
smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(smu->adev->dev, "SMU driver if version not matched\n");
}
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
index 2c20624caca4..ac5e44dff6c9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
@@ -101,7 +101,6 @@ int smu_v12_0_check_fw_version(struct smu_context *smu)
"smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
smu->smc_driver_if_version, if_version,
smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(smu->adev->dev, "SMU driver if version not matched\n");
}
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index e030f1e186cb..554f616328c3 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -59,6 +59,10 @@
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
+ int od_feature_bit,
+ int32_t *min, int32_t *max);
+
static const struct smu_feature_bits smu_v13_0_0_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
@@ -1043,8 +1047,35 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
const OverDriveLimits_t * const overdrive_upperlimits =
&pptable->SkuTable.OverDriveLimitsBasicMax;
+ int32_t min_value, max_value;
+ bool feature_enabled;
- return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
+ switch (od_feature_bit) {
+ case PP_OD_FEATURE_FAN_CURVE_BIT:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ if (feature_enabled) {
+ smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+
+ smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+ }
+ break;
+ default:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ break;
+ }
+
+out:
+ return feature_enabled;
}
static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
@@ -2034,6 +2065,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetricsExternal_t metrics_ext;
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
+ uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
int ret = 0;
ret = smu_cmn_get_metrics_table(smu,
@@ -2058,7 +2090,12 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+
+ if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) ||
+ (mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800))
+ gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+ else
+ gpu_metrics->energy_accumulator = UINT_MAX;
if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
@@ -2216,7 +2253,8 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu)
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
BIT(PP_OD_FEATURE_UCLK_BIT) |
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
- BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ BIT(PP_OD_FEATURE_FAN_CURVE_BIT) |
+ BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table);
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
if (res == 0)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
index 896b51c8a9a7..870bcc86fd79 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
@@ -1391,7 +1391,7 @@ static int smu_v13_0_6_emit_clk_levels(struct smu_context *smu,
break;
case SMU_OD_MCLK:
if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX)))
- return 0;
+ return -EOPNOTSUPP;
size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK");
size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
@@ -2122,6 +2122,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
{
struct smu_dpm_context *smu_dpm = &(smu->smu_dpm);
struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context;
+ struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table;
struct smu_umd_pstate_table *pstate_table = &smu->pstate_table;
uint32_t min_clk;
uint32_t max_clk;
@@ -2221,14 +2222,16 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu,
if (ret)
return ret;
- min_clk = SMU_DPM_TABLE_MIN(
- &dpm_context->dpm_tables.uclk_table);
- max_clk = SMU_DPM_TABLE_MAX(
- &dpm_context->dpm_tables.uclk_table);
- ret = smu_v13_0_6_set_soft_freq_limited_range(
- smu, SMU_UCLK, min_clk, max_clk, false);
- if (ret)
- return ret;
+ if (SMU_DPM_TABLE_MAX(uclk_table) !=
+ pstate_table->uclk_pstate.curr.max) {
+ min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table);
+ max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table);
+ ret = smu_v13_0_6_set_soft_freq_limited_range(smu,
+ SMU_UCLK, min_clk,
+ max_clk, false);
+ if (ret)
+ return ret;
+ }
smu_v13_0_reset_custom_level(smu);
}
break;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index af0482c9caa7..f331e87858c9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -59,6 +59,10 @@
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
+ int od_feature_bit,
+ int32_t *min, int32_t *max);
+
static const struct smu_feature_bits smu_v13_0_7_dpm_features = {
.bits = {
SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
@@ -1053,8 +1057,35 @@ static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
const OverDriveLimits_t * const overdrive_upperlimits =
&pptable->SkuTable.OverDriveLimitsBasicMax;
+ int32_t min_value, max_value;
+ bool feature_enabled;
- return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
+ switch (od_feature_bit) {
+ case PP_OD_FEATURE_FAN_CURVE_BIT:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ if (feature_enabled) {
+ smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+
+ smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+ }
+ break;
+ default:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ break;
+ }
+
+out:
+ return feature_enabled;
}
static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
@@ -2065,7 +2096,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+ gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ?
+ metrics->EnergyAccumulator : UINT_MAX;
if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
@@ -2223,7 +2255,8 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu)
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
BIT(PP_OD_FEATURE_UCLK_BIT) |
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
- BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ BIT(PP_OD_FEATURE_FAN_CURVE_BIT) |
+ BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table);
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
if (res == 0)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index cec2df1ad0af..e38354c694c9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -284,7 +284,6 @@ int smu_v14_0_check_fw_version(struct smu_context *smu)
"smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
smu->smc_driver_if_version, if_version,
smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_info(adev->dev, "SMU driver if version not matched\n");
}
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index 9994d4369da8..c3ebfac062a7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -56,6 +56,10 @@
#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
+static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
+ int od_feature_bit,
+ int32_t *min, int32_t *max);
+
static const struct smu_feature_bits smu_v14_0_2_dpm_features = {
.bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT),
SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT),
@@ -922,8 +926,35 @@ static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu,
PPTable_t *pptable = smu->smu_table.driver_pptable;
const OverDriveLimits_t * const overdrive_upperlimits =
&pptable->SkuTable.OverDriveLimitsBasicMax;
+ int32_t min_value, max_value;
+ bool feature_enabled;
- return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit);
+ switch (od_feature_bit) {
+ case PP_OD_FEATURE_FAN_CURVE_BIT:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ if (feature_enabled) {
+ smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+
+ smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM,
+ &min_value, &max_value);
+ if (!min_value && !max_value) {
+ feature_enabled = false;
+ goto out;
+ }
+ }
+ break;
+ default:
+ feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit));
+ break;
+ }
+
+out:
+ return feature_enabled;
}
static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
@@ -2311,7 +2342,8 @@ static int smu_v14_0_2_restore_user_od_settings(struct smu_context *smu)
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
BIT(PP_OD_FEATURE_UCLK_BIT) |
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
- BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+ BIT(PP_OD_FEATURE_FAN_CURVE_BIT) |
+ BIT(PP_OD_FEATURE_ZERO_FAN_BIT);
res = smu_v14_0_2_upload_overdrive_table(smu, user_od_table);
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
if (res == 0)
diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index bdc79140875c..862675ac5bb2 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -480,18 +480,8 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
.start = start,
.end = end,
.pgmap_owner = pagemap->owner,
- /*
- * FIXME: MIGRATE_VMA_SELECT_DEVICE_PRIVATE intermittently
- * causes 'xe_exec_system_allocator --r *race*no*' to trigger aa
- * engine reset and a hard hang due to getting stuck on a folio
- * lock. This should work and needs to be root-caused. The only
- * downside of not selecting MIGRATE_VMA_SELECT_DEVICE_PRIVATE
- * is that device-to-device migrations won’t work; instead,
- * memory will bounce through system memory. This path should be
- * rare and only occur when the madvise attributes of memory are
- * changed or atomics are being used.
- */
- .flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT,
+ .flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT |
+ MIGRATE_VMA_SELECT_DEVICE_PRIVATE,
};
unsigned long i, npages = npages_in_range(start, end);
unsigned long own_pages = 0, migrated_pages = 0;
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 4cb753177fd8..c7fa014e0d50 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -137,7 +137,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder,
intel_dp->DP |= DP_SYNC_VS_HIGH;
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
- if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+ if (pipe_config->enhanced_framing)
intel_dp->DP |= DP_ENHANCED_FRAMING;
intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe);
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index fc265f71d72b..298b3a48197c 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -889,7 +889,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder,
* non-compressed link speeds, and simplifies down to the ratio between
* compressed and non-compressed bpp.
*/
- if (crtc_state->dsc.compression_enable) {
+ if (is_vid_mode(intel_dsi) && crtc_state->dsc.compression_enable) {
mul = fxp_q4_to_int(crtc_state->dsc.compressed_bpp_x16);
div = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
}
@@ -1503,7 +1503,7 @@ static void gen11_dsi_get_timings(struct intel_encoder *encoder,
struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode;
- if (pipe_config->dsc.compressed_bpp_x16) {
+ if (is_vid_mode(intel_dsi) && pipe_config->dsc.compressed_bpp_x16) {
int div = fxp_q4_to_int(pipe_config->dsc.compressed_bpp_x16);
int mul = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c
index 7ce8c674bb03..f4f1b68f7543 100644
--- a/drivers/gpu/drm/i915/display/intel_alpm.c
+++ b/drivers/gpu/drm/i915/display/intel_alpm.c
@@ -43,12 +43,6 @@ bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp,
void intel_alpm_init(struct intel_dp *intel_dp)
{
- u8 dpcd;
-
- if (drm_dp_dpcd_readb(&intel_dp->aux, DP_RECEIVER_ALPM_CAP, &dpcd) < 0)
- return;
-
- intel_dp->alpm_dpcd = dpcd;
mutex_init(&intel_dp->alpm.lock);
}
@@ -562,12 +556,7 @@ void intel_alpm_disable(struct intel_dp *intel_dp)
mutex_lock(&intel_dp->alpm.lock);
intel_de_rmw(display, ALPM_CTL(display, cpu_transcoder),
- ALPM_CTL_ALPM_ENABLE | ALPM_CTL_LOBF_ENABLE |
- ALPM_CTL_ALPM_AUX_LESS_ENABLE, 0);
-
- intel_de_rmw(display,
- PORT_ALPM_CTL(cpu_transcoder),
- PORT_ALPM_CTL_ALPM_AUX_LESS_ENABLE, 0);
+ ALPM_CTL_ALPM_ENABLE | ALPM_CTL_LOBF_ENABLE, 0);
drm_dbg_kms(display->drm, "Disabling ALPM\n");
mutex_unlock(&intel_dp->alpm.lock);
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index f5946e677c93..3d7b4b0795cd 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -2971,6 +2971,53 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state,
return 0;
}
+static int intel_cdclk_update_crtc_min_voltage_level(struct intel_atomic_state *state,
+ struct intel_crtc *crtc,
+ u8 old_min_voltage_level,
+ u8 new_min_voltage_level,
+ bool *need_cdclk_calc)
+{
+ struct intel_display *display = to_intel_display(state);
+ struct intel_cdclk_state *cdclk_state;
+ bool allow_voltage_level_decrease = intel_any_crtc_needs_modeset(state);
+ int ret;
+
+ if (new_min_voltage_level == old_min_voltage_level)
+ return 0;
+
+ if (!allow_voltage_level_decrease &&
+ new_min_voltage_level < old_min_voltage_level)
+ return 0;
+
+ cdclk_state = intel_atomic_get_cdclk_state(state);
+ if (IS_ERR(cdclk_state))
+ return PTR_ERR(cdclk_state);
+
+ old_min_voltage_level = cdclk_state->min_voltage_level[crtc->pipe];
+
+ if (new_min_voltage_level == old_min_voltage_level)
+ return 0;
+
+ if (!allow_voltage_level_decrease &&
+ new_min_voltage_level < old_min_voltage_level)
+ return 0;
+
+ cdclk_state->min_voltage_level[crtc->pipe] = new_min_voltage_level;
+
+ ret = intel_atomic_lock_global_state(&cdclk_state->base);
+ if (ret)
+ return ret;
+
+ *need_cdclk_calc = true;
+
+ drm_dbg_kms(display->drm,
+ "[CRTC:%d:%s] min voltage level: %d -> %d\n",
+ crtc->base.base.id, crtc->base.name,
+ old_min_voltage_level, new_min_voltage_level);
+
+ return 0;
+}
+
int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state,
int old_min_cdclk, int new_min_cdclk,
bool *need_cdclk_calc)
@@ -3386,6 +3433,13 @@ static int intel_crtcs_calc_min_cdclk(struct intel_atomic_state *state,
need_cdclk_calc);
if (ret)
return ret;
+
+ ret = intel_cdclk_update_crtc_min_voltage_level(state, crtc,
+ old_crtc_state->min_voltage_level,
+ new_crtc_state->min_voltage_level,
+ need_cdclk_calc);
+ if (ret)
+ return ret;
}
return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 3b8ba8ab76a1..0f82bf771a92 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -1614,7 +1614,6 @@ static void hsw_configure_cpu_transcoder(const struct intel_crtc_state *crtc_sta
}
intel_set_transcoder_timings(crtc_state);
- intel_vrr_set_transcoder_timings(crtc_state);
if (cpu_transcoder != TRANSCODER_EDP)
intel_de_write(display, TRANS_MULT(display, cpu_transcoder),
@@ -4603,6 +4602,7 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
struct intel_crtc_state *crtc_state =
intel_atomic_get_new_crtc_state(state, crtc);
struct intel_crtc_state *saved_state;
+ int err;
saved_state = intel_crtc_state_alloc(crtc);
if (!saved_state)
@@ -4611,7 +4611,12 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state,
/* free the old crtc_state->hw members */
intel_crtc_free_hw_state(crtc_state);
- intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
+ err = intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state);
+ if (err) {
+ kfree(saved_state);
+
+ return err;
+ }
/* FIXME: before the switch to atomic started, a new pipe_config was
* kzalloc'd. Code that depends on any field being zero should be
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c
index db185a859133..fba9fa41f827 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_well.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c
@@ -806,7 +806,7 @@ void gen9_set_dc_state(struct intel_display *display, u32 state)
power_domains->dc_state, val & mask);
enable_dc6 = state & DC_STATE_EN_UPTO_DC6;
- dc6_was_enabled = val & DC_STATE_EN_UPTO_DC6;
+ dc6_was_enabled = power_domains->dc_state & DC_STATE_EN_UPTO_DC6;
if (!dc6_was_enabled && enable_dc6)
intel_dmc_update_dc6_allowed_count(display, true);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 6b92f333e18b..ced0e5a5989b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1186,6 +1186,7 @@ struct intel_crtc_state {
u32 dc3co_exitline;
u16 su_y_granularity;
u8 active_non_psr_pipes;
+ u8 entry_setup_frames;
const char *no_psr_reason;
/*
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c
index 1006b060c3f3..0b15cb764b1d 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.c
+++ b/drivers/gpu/drm/i915/display/intel_dmc.c
@@ -1599,8 +1599,7 @@ static bool intel_dmc_get_dc6_allowed_count(struct intel_display *display, u32 *
return false;
mutex_lock(&power_domains->lock);
- dc6_enabled = intel_de_read(display, DC_STATE_EN) &
- DC_STATE_EN_UPTO_DC6;
+ dc6_enabled = power_domains->dc_state & DC_STATE_EN_UPTO_DC6;
if (dc6_enabled)
intel_dmc_update_dc6_allowed_count(display, false);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 559cf3bb23fd..696edf40b243 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4577,6 +4577,7 @@ static bool
intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector)
{
struct intel_display *display = to_intel_display(intel_dp);
+ int ret;
/* this function is meant to be called only once */
drm_WARN_ON(display->drm, intel_dp->dpcd[DP_DPCD_REV] != 0);
@@ -4616,6 +4617,12 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
*/
intel_dp_init_source_oui(intel_dp);
+ /* Read the ALPM DPCD caps */
+ ret = drm_dp_dpcd_read_byte(&intel_dp->aux, DP_RECEIVER_ALPM_CAP,
+ &intel_dp->alpm_dpcd);
+ if (ret < 0)
+ return false;
+
/*
* This has to be called after intel_dp->edp_dpcd is filled, PSR checks
* for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1]
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 83865c02d477..55b423fd6b6f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -621,19 +621,27 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
*
* Clear any DP tunnel stream BW requirement set by
* intel_dp_tunnel_atomic_compute_stream_bw().
+ *
+ * Returns 0 in case of success, a negative error code otherwise.
*/
-void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state)
+int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ int err;
if (!crtc_state->dp_tunnel_ref.tunnel)
- return;
+ return 0;
+
+ err = drm_dp_tunnel_atomic_set_stream_bw(&state->base,
+ crtc_state->dp_tunnel_ref.tunnel,
+ crtc->pipe, 0);
+ if (err)
+ return err;
- drm_dp_tunnel_atomic_set_stream_bw(&state->base,
- crtc_state->dp_tunnel_ref.tunnel,
- crtc->pipe, 0);
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
+
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
index 7f0f720e8dca..10ab9eebcef6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
@@ -40,8 +40,8 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
struct intel_dp *intel_dp,
const struct intel_connector *connector,
struct intel_crtc_state *crtc_state);
-void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state);
+int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state);
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
struct intel_crtc *crtc);
@@ -88,9 +88,12 @@ intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
return 0;
}
-static inline void
+static inline int
intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state) {}
+ struct intel_crtc_state *crtc_state)
+{
+ return 0;
+}
static inline int
intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index a7bce0c6a17e..264e6843bff1 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -496,8 +496,10 @@ gmbus_xfer_read_chunk(struct intel_display *display,
val = intel_de_read_fw(display, GMBUS3(display));
do {
- if (extra_byte_added && len == 1)
+ if (extra_byte_added && len == 1) {
+ len--;
break;
+ }
*buf++ = val & 0xff;
val >>= 8;
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index e06a0618b4c6..076b9b356481 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -436,11 +436,16 @@ void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
drm_framebuffer_get(plane_state->hw.fb);
}
+static void unlink_nv12_plane(struct intel_crtc_state *crtc_state,
+ struct intel_plane_state *plane_state);
+
void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ unlink_nv12_plane(crtc_state, plane_state);
+
crtc_state->active_planes &= ~BIT(plane->id);
crtc_state->scaled_planes &= ~BIT(plane->id);
crtc_state->nv12_planes &= ~BIT(plane->id);
@@ -1513,6 +1518,9 @@ static void unlink_nv12_plane(struct intel_crtc_state *crtc_state,
struct intel_display *display = to_intel_display(plane_state);
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+ if (!plane_state->planar_linked_plane)
+ return;
+
plane_state->planar_linked_plane = NULL;
if (!plane_state->is_y_plane)
@@ -1550,8 +1558,7 @@ static int icl_check_nv12_planes(struct intel_atomic_state *state,
if (plane->pipe != crtc->pipe)
continue;
- if (plane_state->planar_linked_plane)
- unlink_nv12_plane(crtc_state, plane_state);
+ unlink_nv12_plane(crtc_state, plane_state);
}
if (!crtc_state->nv12_planes)
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 62208ffc5101..097e18c1adb2 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1307,9 +1307,14 @@ static bool psr2_granularity_check(struct intel_crtc_state *crtc_state,
u16 sink_y_granularity = crtc_state->has_panel_replay ?
connector->dp.panel_replay_caps.su_y_granularity :
connector->dp.psr_caps.su_y_granularity;
- u16 sink_w_granularity = crtc_state->has_panel_replay ?
- connector->dp.panel_replay_caps.su_w_granularity :
- connector->dp.psr_caps.su_w_granularity;
+ u16 sink_w_granularity;
+
+ if (crtc_state->has_panel_replay)
+ sink_w_granularity = connector->dp.panel_replay_caps.su_w_granularity ==
+ DP_PANEL_REPLAY_FULL_LINE_GRANULARITY ?
+ crtc_hdisplay : connector->dp.panel_replay_caps.su_w_granularity;
+ else
+ sink_w_granularity = connector->dp.psr_caps.su_w_granularity;
/* PSR2 HW only send full lines so we only need to validate the width */
if (crtc_hdisplay % sink_w_granularity)
@@ -1712,7 +1717,7 @@ static bool _psr_compute_config(struct intel_dp *intel_dp,
entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, conn_state, adjusted_mode);
if (entry_setup_frames >= 0) {
- intel_dp->psr.entry_setup_frames = entry_setup_frames;
+ crtc_state->entry_setup_frames = entry_setup_frames;
} else {
crtc_state->no_psr_reason = "PSR setup timing not met";
drm_dbg_kms(display->drm,
@@ -1810,7 +1815,7 @@ static bool intel_psr_needs_wa_18037818876(struct intel_dp *intel_dp,
{
struct intel_display *display = to_intel_display(intel_dp);
- return (DISPLAY_VER(display) == 20 && intel_dp->psr.entry_setup_frames > 0 &&
+ return (DISPLAY_VER(display) == 20 && crtc_state->entry_setup_frames > 0 &&
!crtc_state->has_sel_update);
}
@@ -2184,6 +2189,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
intel_dp->psr.pkg_c_latency_used = crtc_state->pkg_c_latency_used;
intel_dp->psr.io_wake_lines = crtc_state->alpm_state.io_wake_lines;
intel_dp->psr.fast_wake_lines = crtc_state->alpm_state.fast_wake_lines;
+ intel_dp->psr.entry_setup_frames = crtc_state->entry_setup_frames;
if (!psr_interrupt_error_check(intel_dp))
return;
@@ -2614,6 +2620,12 @@ void intel_psr2_program_trans_man_trk_ctl(struct intel_dsb *dsb,
intel_de_write_dsb(display, dsb, PIPE_SRCSZ_ERLY_TPT(crtc->pipe),
crtc_state->pipe_srcsz_early_tpt);
+
+ if (!crtc_state->dsc.compression_enable)
+ return;
+
+ intel_dsc_su_et_parameters_configure(dsb, encoder, crtc_state,
+ drm_rect_height(&crtc_state->psr2_su_area));
}
static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
@@ -2666,9 +2678,9 @@ static u32 psr2_pipe_srcsz_early_tpt_calc(struct intel_crtc_state *crtc_state,
static void clip_area_update(struct drm_rect *overlap_damage_area,
struct drm_rect *damage_area,
- struct drm_rect *pipe_src)
+ struct drm_rect *display_area)
{
- if (!drm_rect_intersect(damage_area, pipe_src))
+ if (!drm_rect_intersect(damage_area, display_area))
return;
if (overlap_damage_area->y1 == -1) {
@@ -2684,11 +2696,12 @@ static void clip_area_update(struct drm_rect *overlap_damage_area,
overlap_damage_area->y2 = damage_area->y2;
}
-static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state)
+static bool intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
u16 y_alignment;
+ bool su_area_changed = false;
/* ADLP aligns the SU region to vdsc slice height in case dsc is enabled */
if (crtc_state->dsc.compression_enable &&
@@ -2697,10 +2710,18 @@ static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_st
else
y_alignment = crtc_state->su_y_granularity;
- crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment;
- if (crtc_state->psr2_su_area.y2 % y_alignment)
+ if (crtc_state->psr2_su_area.y1 % y_alignment) {
+ crtc_state->psr2_su_area.y1 -= crtc_state->psr2_su_area.y1 % y_alignment;
+ su_area_changed = true;
+ }
+
+ if (crtc_state->psr2_su_area.y2 % y_alignment) {
crtc_state->psr2_su_area.y2 = ((crtc_state->psr2_su_area.y2 /
y_alignment) + 1) * y_alignment;
+ su_area_changed = true;
+ }
+
+ return su_area_changed;
}
/*
@@ -2710,6 +2731,7 @@ static void intel_psr2_sel_fetch_pipe_alignment(struct intel_crtc_state *crtc_st
static void
intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state,
struct intel_crtc *crtc,
+ struct drm_rect *display_area,
bool *cursor_in_su_area)
{
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
@@ -2737,7 +2759,7 @@ intel_psr2_sel_fetch_et_alignment(struct intel_atomic_state *state,
continue;
clip_area_update(&crtc_state->psr2_su_area, &new_plane_state->uapi.dst,
- &crtc_state->pipe_src);
+ display_area);
*cursor_in_su_area = true;
}
}
@@ -2834,7 +2856,13 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
struct intel_plane_state *new_plane_state, *old_plane_state;
struct intel_plane *plane;
- bool full_update = false, cursor_in_su_area = false;
+ struct drm_rect display_area = {
+ .x1 = 0,
+ .y1 = 0,
+ .x2 = crtc_state->hw.adjusted_mode.crtc_hdisplay,
+ .y2 = crtc_state->hw.adjusted_mode.crtc_vdisplay,
+ };
+ bool full_update = false, su_area_changed;
int i, ret;
if (!crtc_state->enable_psr2_sel_fetch)
@@ -2847,7 +2875,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
crtc_state->psr2_su_area.x1 = 0;
crtc_state->psr2_su_area.y1 = -1;
- crtc_state->psr2_su_area.x2 = drm_rect_width(&crtc_state->pipe_src);
+ crtc_state->psr2_su_area.x2 = drm_rect_width(&display_area);
crtc_state->psr2_su_area.y2 = -1;
/*
@@ -2885,14 +2913,14 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.y1 = old_plane_state->uapi.dst.y1;
damaged_area.y2 = old_plane_state->uapi.dst.y2;
clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
- &crtc_state->pipe_src);
+ &display_area);
}
if (new_plane_state->uapi.visible) {
damaged_area.y1 = new_plane_state->uapi.dst.y1;
damaged_area.y2 = new_plane_state->uapi.dst.y2;
clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
- &crtc_state->pipe_src);
+ &display_area);
}
continue;
} else if (new_plane_state->uapi.alpha != old_plane_state->uapi.alpha) {
@@ -2900,7 +2928,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.y1 = new_plane_state->uapi.dst.y1;
damaged_area.y2 = new_plane_state->uapi.dst.y2;
clip_area_update(&crtc_state->psr2_su_area, &damaged_area,
- &crtc_state->pipe_src);
+ &display_area);
continue;
}
@@ -2916,7 +2944,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
damaged_area.x1 += new_plane_state->uapi.dst.x1 - src.x1;
damaged_area.x2 += new_plane_state->uapi.dst.x1 - src.x1;
- clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &crtc_state->pipe_src);
+ clip_area_update(&crtc_state->psr2_su_area, &damaged_area, &display_area);
}
/*
@@ -2941,15 +2969,33 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
if (ret)
return ret;
- /*
- * Adjust su area to cover cursor fully as necessary (early
- * transport). This needs to be done after
- * drm_atomic_add_affected_planes to ensure visible cursor is added into
- * affected planes even when cursor is not updated by itself.
- */
- intel_psr2_sel_fetch_et_alignment(state, crtc, &cursor_in_su_area);
+ do {
+ bool cursor_in_su_area;
+
+ /*
+ * Adjust su area to cover cursor fully as necessary
+ * (early transport). This needs to be done after
+ * drm_atomic_add_affected_planes to ensure visible
+ * cursor is added into affected planes even when
+ * cursor is not updated by itself.
+ */
+ intel_psr2_sel_fetch_et_alignment(state, crtc, &display_area,
+ &cursor_in_su_area);
- intel_psr2_sel_fetch_pipe_alignment(crtc_state);
+ su_area_changed = intel_psr2_sel_fetch_pipe_alignment(crtc_state);
+
+ /*
+ * If the cursor was outside the SU area before
+ * alignment, the alignment step (which only expands
+ * SU) may pull the cursor partially inside, so we
+ * must run ET alignment again to fully cover it. But
+ * if the cursor was already fully inside before
+ * alignment, expanding the SU area won't change that,
+ * so no further work is needed.
+ */
+ if (cursor_in_su_area)
+ break;
+ } while (su_area_changed);
/*
* Now that we have the pipe damaged area check if it intersect with
@@ -3009,6 +3055,10 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
}
skip_sel_fetch_set_loop:
+ if (full_update)
+ clip_area_update(&crtc_state->psr2_su_area, &display_area,
+ &display_area);
+
psr2_man_trk_ctl_calc(crtc_state, full_update);
crtc_state->pipe_srcsz_early_tpt =
psr2_pipe_srcsz_early_tpt_calc(crtc_state, full_update);
@@ -3068,6 +3118,8 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state,
* - Display WA #1136: skl, bxt
*/
if (intel_crtc_needs_modeset(new_crtc_state) ||
+ new_crtc_state->update_m_n ||
+ new_crtc_state->update_lrr ||
!new_crtc_state->has_psr ||
!new_crtc_state->active_planes ||
new_crtc_state->has_sel_update != psr->sel_update_enabled ||
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index 5493082f30a7..2065dac1e3fd 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -767,6 +767,29 @@ void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
sizeof(dp_dsc_pps_sdp));
}
+void intel_dsc_su_et_parameters_configure(struct intel_dsb *dsb, struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state, int su_lines)
+{
+ struct intel_display *display = to_intel_display(crtc_state);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config;
+ enum pipe pipe = crtc->pipe;
+ int vdsc_instances_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state);
+ int slice_row_per_frame = su_lines / vdsc_cfg->slice_height;
+ u32 val;
+
+ drm_WARN_ON_ONCE(display->drm, su_lines % vdsc_cfg->slice_height);
+ drm_WARN_ON_ONCE(display->drm, vdsc_instances_per_pipe > 2);
+
+ val = DSC_SUPS0_SU_SLICE_ROW_PER_FRAME(slice_row_per_frame);
+ val |= DSC_SUPS0_SU_PIC_HEIGHT(su_lines);
+
+ intel_de_write_dsb(display, dsb, LNL_DSC0_SU_PARAMETER_SET_0(pipe), val);
+
+ if (vdsc_instances_per_pipe == 2)
+ intel_de_write_dsb(display, dsb, LNL_DSC1_SU_PARAMETER_SET_0(pipe), val);
+}
+
static i915_reg_t dss_ctl1_reg(struct intel_crtc *crtc, enum transcoder cpu_transcoder)
{
return is_pipe_dsc(crtc, cpu_transcoder) ?
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h
index 99f64ac54b27..99bb9042592a 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.h
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.h
@@ -13,6 +13,7 @@ struct drm_printer;
enum transcoder;
struct intel_crtc;
struct intel_crtc_state;
+struct intel_dsb;
struct intel_encoder;
bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state);
@@ -31,6 +32,8 @@ void intel_dsc_dsi_pps_write(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
void intel_dsc_dp_pps_write(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state);
+void intel_dsc_su_et_parameters_configure(struct intel_dsb *dsb, struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state, int su_lines);
void intel_vdsc_state_dump(struct drm_printer *p, int indent,
const struct intel_crtc_state *crtc_state);
int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h
index 2d478a84b07c..2b2e3c1b8138 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_vdsc_regs.h
@@ -196,6 +196,18 @@
#define DSC_PPS18_NSL_BPG_OFFSET(offset) REG_FIELD_PREP(DSC_PPS18_NSL_BPG_OFFSET_MASK, offset)
#define DSC_PPS18_SL_OFFSET_ADJ(offset) REG_FIELD_PREP(DSC_PPS18_SL_OFFSET_ADJ_MASK, offset)
+#define _LNL_DSC0_SU_PARAMETER_SET_0_PA 0x78064
+#define _LNL_DSC1_SU_PARAMETER_SET_0_PA 0x78164
+#define _LNL_DSC0_SU_PARAMETER_SET_0_PB 0x78264
+#define _LNL_DSC1_SU_PARAMETER_SET_0_PB 0x78364
+#define LNL_DSC0_SU_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe), _LNL_DSC0_SU_PARAMETER_SET_0_PA, _LNL_DSC0_SU_PARAMETER_SET_0_PB)
+#define LNL_DSC1_SU_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe), _LNL_DSC1_SU_PARAMETER_SET_0_PA, _LNL_DSC1_SU_PARAMETER_SET_0_PB)
+
+#define DSC_SUPS0_SU_SLICE_ROW_PER_FRAME_MASK REG_GENMASK(31, 20)
+#define DSC_SUPS0_SU_SLICE_ROW_PER_FRAME(rows) REG_FIELD_PREP(DSC_SUPS0_SU_SLICE_ROW_PER_FRAME_MASK, (rows))
+#define DSC_SUPS0_SU_PIC_HEIGHT_MASK REG_GENMASK(15, 0)
+#define DSC_SUPS0_SU_PIC_HEIGHT(h) REG_FIELD_PREP(DSC_SUPS0_SU_PIC_HEIGHT_MASK, (h))
+
/* Icelake Rate Control Buffer Threshold Registers */
#define DSCA_RC_BUF_THRESH_0 _MMIO(0x6B230)
#define DSCA_RC_BUF_THRESH_0_UDW _MMIO(0x6B230 + 4)
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index db74744ddb31..bea005752327 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -598,6 +598,18 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
return;
/*
+ * Bspec says:
+ * "(note: VRR needs to be programmed after
+ * TRANS_DDI_FUNC_CTL and before TRANS_CONF)."
+ *
+ * In practice it turns out that ICL can hang if
+ * TRANS_VRR_VMAX/FLIPLINE are written before
+ * enabling TRANS_DDI_FUNC_CTL.
+ */
+ drm_WARN_ON(display->drm,
+ !(intel_de_read(display, TRANS_DDI_FUNC_CTL(display, cpu_transcoder)) & TRANS_DDI_FUNC_ENABLE));
+
+ /*
* This bit seems to have two meanings depending on the platform:
* TGL: generate VRR "safe window" for DSB vblank waits
* ADL/DG2: make TRANS_SET_CONTEXT_LATENCY effective with VRR
@@ -939,6 +951,8 @@ void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(crtc_state);
+ intel_vrr_set_transcoder_timings(crtc_state);
+
if (!intel_vrr_possible(crtc_state))
return;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index e7918f896a26..65ce54b20ec2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -896,8 +896,10 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle)
rcu_read_lock();
vma = radix_tree_lookup(&eb->gem_context->handles_vma, handle);
- if (likely(vma && vma->vm == vm))
+ if (likely(vma))
vma = i915_vma_tryget(vma);
+ else
+ vma = NULL;
rcu_read_unlock();
if (likely(vma))
return vma;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index c6c64ba29bc4..720a9ad39aa2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -153,8 +153,12 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
}
} while (1);
- nr_pages = min_t(unsigned long,
- folio_nr_pages(folio), page_count - i);
+ nr_pages = min_array(((unsigned long[]) {
+ folio_nr_pages(folio),
+ page_count - i,
+ max_segment / PAGE_SIZE,
+ }), 3);
+
if (!i ||
sg->length >= max_segment ||
folio_pfn(folio) != next_pfn) {
@@ -164,7 +168,9 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
st->nents++;
sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0);
} else {
- /* XXX: could overflow? */
+ nr_pages = min_t(unsigned long, nr_pages,
+ (max_segment - sg->length) / PAGE_SIZE);
+
sg->length += nr_pages * PAGE_SIZE;
}
next_pfn = folio_pfn(folio) + nr_pages;
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index d37966ec7a92..54c9571327e7 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -1967,7 +1967,8 @@ void intel_engines_reset_default_submission(struct intel_gt *gt)
if (engine->sanitize)
engine->sanitize(engine);
- engine->set_default_submission(engine);
+ if (engine->set_default_submission)
+ engine->set_default_submission(engine);
}
}
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
index b279878dca29..6424ecce8bcb 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c
@@ -148,10 +148,12 @@ static void heartbeat(struct work_struct *wrk)
/* Just in case everything has gone horribly wrong, give it a kick */
intel_engine_flush_submission(engine);
- rq = engine->heartbeat.systole;
- if (rq && i915_request_completed(rq)) {
- i915_request_put(rq);
- engine->heartbeat.systole = NULL;
+ rq = xchg(&engine->heartbeat.systole, NULL);
+ if (rq) {
+ if (i915_request_completed(rq))
+ i915_request_put(rq);
+ else
+ engine->heartbeat.systole = rq;
}
if (!intel_engine_pm_get_if_awake(engine))
@@ -232,8 +234,11 @@ static void heartbeat(struct work_struct *wrk)
unlock:
mutex_unlock(&ce->timeline->mutex);
out:
- if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine))
- i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
+ if (!engine->i915->params.enable_hangcheck || !next_heartbeat(engine)) {
+ rq = xchg(&engine->heartbeat.systole, NULL);
+ if (rq)
+ i915_request_put(rq);
+ }
intel_engine_pm_put(engine);
}
@@ -247,8 +252,13 @@ void intel_engine_unpark_heartbeat(struct intel_engine_cs *engine)
void intel_engine_park_heartbeat(struct intel_engine_cs *engine)
{
- if (cancel_delayed_work(&engine->heartbeat.work))
- i915_request_put(fetch_and_zero(&engine->heartbeat.systole));
+ if (cancel_delayed_work(&engine->heartbeat.work)) {
+ struct i915_request *rq;
+
+ rq = xchg(&engine->heartbeat.systole, NULL);
+ if (rq)
+ i915_request_put(rq);
+ }
}
void intel_gt_unpark_heartbeats(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/i915_wait_util.h b/drivers/gpu/drm/i915/i915_wait_util.h
index 7376898e3bf8..e1ed7921ec70 100644
--- a/drivers/gpu/drm/i915/i915_wait_util.h
+++ b/drivers/gpu/drm/i915/i915_wait_util.h
@@ -25,9 +25,9 @@
might_sleep(); \
for (;;) { \
const bool expired__ = ktime_after(ktime_get_raw(), end__); \
- OP; \
/* Guarantee COND check prior to timeout */ \
barrier(); \
+ OP; \
if (COND) { \
ret__ = 0; \
break; \
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 17c67f02016b..aaf6c9ebd319 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -1236,6 +1236,11 @@ static int mtk_dsi_probe(struct platform_device *pdev)
dsi->host.ops = &mtk_dsi_ops;
dsi->host.dev = dev;
+
+ init_waitqueue_head(&dsi->irq_wait_queue);
+
+ platform_set_drvdata(pdev, dsi);
+
ret = mipi_dsi_host_register(&dsi->host);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to register DSI host\n");
@@ -1247,10 +1252,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n");
}
- init_waitqueue_head(&dsi->irq_wait_queue);
-
- platform_set_drvdata(pdev, dsi);
-
dsi->bridge.of_node = dev->of_node;
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c
index d77b4774d414..e2225c5ba647 100644
--- a/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpummu.c
@@ -78,7 +78,7 @@ static void a2xx_gpummu_destroy(struct msm_mmu *mmu)
{
struct a2xx_gpummu *gpummu = to_a2xx_gpummu(mmu);
- dma_free_attrs(mmu->dev, TABLE_SIZE, gpummu->table, gpummu->pt_base,
+ dma_free_attrs(mmu->dev, TABLE_SIZE + 32, gpummu->table, gpummu->pt_base,
DMA_ATTR_FORCE_CONTIGUOUS);
kfree(gpummu);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
index 550a53a7865e..38561f26837e 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c
@@ -1759,7 +1759,7 @@ static const u32 x285_protect_regs[] = {
A6XX_PROTECT_NORDWR(0x27c06, 0x0000),
};
-DECLARE_ADRENO_PROTECT(x285_protect, 64);
+DECLARE_ADRENO_PROTECT(x285_protect, 15);
static const struct adreno_reglist_pipe a840_nonctxt_regs[] = {
{ REG_A8XX_CP_SMMU_STREAM_ID_LPAC, 0x00000101, BIT(PIPE_NONE) },
@@ -1966,5 +1966,4 @@ static inline __always_unused void __build_asserts(void)
BUILD_BUG_ON(a660_protect.count > a660_protect.count_max);
BUILD_BUG_ON(a690_protect.count > a690_protect.count_max);
BUILD_BUG_ON(a730_protect.count > a730_protect.count_max);
- BUILD_BUG_ON(a840_protect.count > a840_protect.count_max);
}
diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
index 5a320f5bde41..b1887e0cf698 100644
--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c
@@ -310,11 +310,21 @@ static void a8xx_set_ubwc_config(struct msm_gpu *gpu)
hbb = cfg->highest_bank_bit - 13;
hbb_hi = hbb >> 2;
hbb_lo = hbb & 3;
- a8xx_write_pipe(gpu, PIPE_BV, REG_A8XX_GRAS_NC_MODE_CNTL, hbb << 5);
- a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_GRAS_NC_MODE_CNTL, hbb << 5);
+
+ a8xx_write_pipe(gpu, PIPE_BV, REG_A8XX_GRAS_NC_MODE_CNTL,
+ hbb << 5 |
+ level3_swizzling_dis << 4 |
+ level2_swizzling_dis << 3);
+
+ a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_GRAS_NC_MODE_CNTL,
+ hbb << 5 |
+ level3_swizzling_dis << 4 |
+ level2_swizzling_dis << 3);
a8xx_write_pipe(gpu, PIPE_BR, REG_A8XX_RB_CCU_NC_MODE_CNTL,
yuvnotcomptofc << 6 |
+ level3_swizzling_dis << 5 |
+ level2_swizzling_dis << 4 |
hbb_hi << 3 |
hbb_lo << 1);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 554d746f115b..4edfe80c5be7 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -302,6 +302,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,kgsl-3d0" },
{}
};
+MODULE_DEVICE_TABLE(of, dt_match);
static int adreno_runtime_resume(struct device *dev)
{
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h
index 303d33dc7783..9f2bceca1789 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h
@@ -133,7 +133,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = {
static const struct dpu_lm_cfg sc8280xp_lm[] = {
{
.name = "lm_0", .id = LM_0,
- .base = 0x44000, .len = 0x320,
+ .base = 0x44000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_1,
@@ -141,7 +141,7 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = {
.dspp = DSPP_0,
}, {
.name = "lm_1", .id = LM_1,
- .base = 0x45000, .len = 0x320,
+ .base = 0x45000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_0,
@@ -149,7 +149,7 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = {
.dspp = DSPP_1,
}, {
.name = "lm_2", .id = LM_2,
- .base = 0x46000, .len = 0x320,
+ .base = 0x46000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_3,
@@ -157,7 +157,7 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = {
.dspp = DSPP_2,
}, {
.name = "lm_3", .id = LM_3,
- .base = 0x47000, .len = 0x320,
+ .base = 0x47000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_2,
@@ -165,14 +165,14 @@ static const struct dpu_lm_cfg sc8280xp_lm[] = {
.dspp = DSPP_3,
}, {
.name = "lm_4", .id = LM_4,
- .base = 0x48000, .len = 0x320,
+ .base = 0x48000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_5,
.pingpong = PINGPONG_4,
}, {
.name = "lm_5", .id = LM_5,
- .base = 0x49000, .len = 0x320,
+ .base = 0x49000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_4,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h
index b09a6af4c474..04b22167f93d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h
@@ -134,7 +134,7 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = {
static const struct dpu_lm_cfg sm8450_lm[] = {
{
.name = "lm_0", .id = LM_0,
- .base = 0x44000, .len = 0x320,
+ .base = 0x44000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_1,
@@ -142,7 +142,7 @@ static const struct dpu_lm_cfg sm8450_lm[] = {
.dspp = DSPP_0,
}, {
.name = "lm_1", .id = LM_1,
- .base = 0x45000, .len = 0x320,
+ .base = 0x45000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_0,
@@ -150,7 +150,7 @@ static const struct dpu_lm_cfg sm8450_lm[] = {
.dspp = DSPP_1,
}, {
.name = "lm_2", .id = LM_2,
- .base = 0x46000, .len = 0x320,
+ .base = 0x46000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_3,
@@ -158,7 +158,7 @@ static const struct dpu_lm_cfg sm8450_lm[] = {
.dspp = DSPP_2,
}, {
.name = "lm_3", .id = LM_3,
- .base = 0x47000, .len = 0x320,
+ .base = 0x47000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_2,
@@ -166,14 +166,14 @@ static const struct dpu_lm_cfg sm8450_lm[] = {
.dspp = DSPP_3,
}, {
.name = "lm_4", .id = LM_4,
- .base = 0x48000, .len = 0x320,
+ .base = 0x48000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_5,
.pingpong = PINGPONG_4,
}, {
.name = "lm_5", .id = LM_5,
- .base = 0x49000, .len = 0x320,
+ .base = 0x49000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_4,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h
index 0f7b4a224e4c..42cf3bd5a12a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h
@@ -366,8 +366,8 @@ static const struct dpu_intf_cfg sa8775p_intf[] = {
.type = INTF_NONE,
.controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */
.prog_fetch_lines_worst_case = 24,
- .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17),
- .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16),
+ .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16),
+ .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17),
}, {
.name = "intf_7", .id = INTF_7,
.base = 0x3b000, .len = 0x280,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h
index 465b6460f875..4c7eb55d474c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h
@@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sm8550_sspp[] = {
static const struct dpu_lm_cfg sm8550_lm[] = {
{
.name = "lm_0", .id = LM_0,
- .base = 0x44000, .len = 0x320,
+ .base = 0x44000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_1,
@@ -139,7 +139,7 @@ static const struct dpu_lm_cfg sm8550_lm[] = {
.dspp = DSPP_0,
}, {
.name = "lm_1", .id = LM_1,
- .base = 0x45000, .len = 0x320,
+ .base = 0x45000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_0,
@@ -147,7 +147,7 @@ static const struct dpu_lm_cfg sm8550_lm[] = {
.dspp = DSPP_1,
}, {
.name = "lm_2", .id = LM_2,
- .base = 0x46000, .len = 0x320,
+ .base = 0x46000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_3,
@@ -155,7 +155,7 @@ static const struct dpu_lm_cfg sm8550_lm[] = {
.dspp = DSPP_2,
}, {
.name = "lm_3", .id = LM_3,
- .base = 0x47000, .len = 0x320,
+ .base = 0x47000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_2,
@@ -163,14 +163,14 @@ static const struct dpu_lm_cfg sm8550_lm[] = {
.dspp = DSPP_3,
}, {
.name = "lm_4", .id = LM_4,
- .base = 0x48000, .len = 0x320,
+ .base = 0x48000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_5,
.pingpong = PINGPONG_4,
}, {
.name = "lm_5", .id = LM_5,
- .base = 0x49000, .len = 0x320,
+ .base = 0x49000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_4,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h
index 6caa7d40f368..dec83ea8167d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h
@@ -131,7 +131,7 @@ static const struct dpu_sspp_cfg sar2130p_sspp[] = {
static const struct dpu_lm_cfg sar2130p_lm[] = {
{
.name = "lm_0", .id = LM_0,
- .base = 0x44000, .len = 0x320,
+ .base = 0x44000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_1,
@@ -139,7 +139,7 @@ static const struct dpu_lm_cfg sar2130p_lm[] = {
.dspp = DSPP_0,
}, {
.name = "lm_1", .id = LM_1,
- .base = 0x45000, .len = 0x320,
+ .base = 0x45000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_0,
@@ -147,7 +147,7 @@ static const struct dpu_lm_cfg sar2130p_lm[] = {
.dspp = DSPP_1,
}, {
.name = "lm_2", .id = LM_2,
- .base = 0x46000, .len = 0x320,
+ .base = 0x46000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_3,
@@ -155,7 +155,7 @@ static const struct dpu_lm_cfg sar2130p_lm[] = {
.dspp = DSPP_2,
}, {
.name = "lm_3", .id = LM_3,
- .base = 0x47000, .len = 0x320,
+ .base = 0x47000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_2,
@@ -163,14 +163,14 @@ static const struct dpu_lm_cfg sar2130p_lm[] = {
.dspp = DSPP_3,
}, {
.name = "lm_4", .id = LM_4,
- .base = 0x48000, .len = 0x320,
+ .base = 0x48000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_5,
.pingpong = PINGPONG_4,
}, {
.name = "lm_5", .id = LM_5,
- .base = 0x49000, .len = 0x320,
+ .base = 0x49000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_4,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h
index 7243eebb85f3..52ff4baa668a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h
@@ -130,7 +130,7 @@ static const struct dpu_sspp_cfg x1e80100_sspp[] = {
static const struct dpu_lm_cfg x1e80100_lm[] = {
{
.name = "lm_0", .id = LM_0,
- .base = 0x44000, .len = 0x320,
+ .base = 0x44000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_1,
@@ -138,7 +138,7 @@ static const struct dpu_lm_cfg x1e80100_lm[] = {
.dspp = DSPP_0,
}, {
.name = "lm_1", .id = LM_1,
- .base = 0x45000, .len = 0x320,
+ .base = 0x45000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_0,
@@ -146,7 +146,7 @@ static const struct dpu_lm_cfg x1e80100_lm[] = {
.dspp = DSPP_1,
}, {
.name = "lm_2", .id = LM_2,
- .base = 0x46000, .len = 0x320,
+ .base = 0x46000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_3,
@@ -154,7 +154,7 @@ static const struct dpu_lm_cfg x1e80100_lm[] = {
.dspp = DSPP_2,
}, {
.name = "lm_3", .id = LM_3,
- .base = 0x47000, .len = 0x320,
+ .base = 0x47000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_2,
@@ -162,14 +162,14 @@ static const struct dpu_lm_cfg x1e80100_lm[] = {
.dspp = DSPP_3,
}, {
.name = "lm_4", .id = LM_4,
- .base = 0x48000, .len = 0x320,
+ .base = 0x48000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_5,
.pingpong = PINGPONG_4,
}, {
.name = "lm_5", .id = LM_5,
- .base = 0x49000, .len = 0x320,
+ .base = 0x49000, .len = 0x400,
.features = MIXER_MSM8998_MASK,
.sblk = &sdm845_lm_sblk,
.lm_pair = LM_4,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c
index 188ee0af2c90..23dcbe1ce1b8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c
@@ -89,7 +89,7 @@ static void dpu_setup_dspp_gc(struct dpu_hw_dspp *ctx,
base = ctx->cap->sblk->gc.base;
if (!base) {
- DRM_ERROR("invalid ctx %pK gc base\n", ctx);
+ DRM_ERROR("invalid ctx %p gc base\n", ctx);
return;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c
index e65f1fc026fd..f8f96ad971d7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c
@@ -156,11 +156,13 @@ static void dpu_hw_sspp_setup_pe_config_v13(struct dpu_hw_sspp *ctx,
u8 color;
u32 lr_pe[4], tb_pe[4];
const u32 bytemask = 0xff;
- u32 offset = ctx->cap->sblk->sspp_rec0_blk.base;
+ u32 offset;
if (!ctx || !pe_ext)
return;
+ offset = ctx->cap->sblk->sspp_rec0_blk.base;
+
c = &ctx->hw;
/* program SW pixel extension override for all pipes*/
for (color = 0; color < DPU_MAX_PLANES; color++) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 451a4fcf3e65..7e77d88f8959 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -350,26 +350,28 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm,
return true;
}
-static bool dpu_rm_find_lms(struct dpu_rm *rm,
- struct dpu_global_state *global_state,
- uint32_t crtc_id, bool skip_dspp,
- struct msm_display_topology *topology,
- int *lm_idx, int *pp_idx, int *dspp_idx)
+static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
+ struct dpu_global_state *global_state,
+ uint32_t crtc_id,
+ struct msm_display_topology *topology)
{
+ int lm_idx[MAX_BLOCKS];
+ int pp_idx[MAX_BLOCKS];
+ int dspp_idx[MAX_BLOCKS] = {0};
int i, lm_count = 0;
+ if (!topology->num_lm) {
+ DPU_ERROR("zero LMs in topology\n");
+ return -EINVAL;
+ }
+
/* Find a primary mixer */
for (i = 0; i < ARRAY_SIZE(rm->mixer_blks) &&
lm_count < topology->num_lm; i++) {
if (!rm->mixer_blks[i])
continue;
- if (skip_dspp && to_dpu_hw_mixer(rm->mixer_blks[i])->cap->dspp) {
- DPU_DEBUG("Skipping LM_%d, skipping LMs with DSPPs\n", i);
- continue;
- }
-
/*
* Reset lm_count to an even index. This will drop the previous
* primary mixer if failed to find its peer.
@@ -408,38 +410,12 @@ static bool dpu_rm_find_lms(struct dpu_rm *rm,
}
}
- return lm_count == topology->num_lm;
-}
-
-static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
- struct dpu_global_state *global_state,
- uint32_t crtc_id,
- struct msm_display_topology *topology)
-
-{
- int lm_idx[MAX_BLOCKS];
- int pp_idx[MAX_BLOCKS];
- int dspp_idx[MAX_BLOCKS] = {0};
- int i;
- bool found;
-
- if (!topology->num_lm) {
- DPU_ERROR("zero LMs in topology\n");
- return -EINVAL;
- }
-
- /* Try using non-DSPP LM blocks first */
- found = dpu_rm_find_lms(rm, global_state, crtc_id, !topology->num_dspp,
- topology, lm_idx, pp_idx, dspp_idx);
- if (!found && !topology->num_dspp)
- found = dpu_rm_find_lms(rm, global_state, crtc_id, false,
- topology, lm_idx, pp_idx, dspp_idx);
- if (!found) {
+ if (lm_count != topology->num_lm) {
DPU_DEBUG("unable to find appropriate mixers\n");
return -ENAVAIL;
}
- for (i = 0; i < topology->num_lm; i++) {
+ for (i = 0; i < lm_count; i++) {
global_state->mixer_to_crtc_id[lm_idx[i]] = crtc_id;
global_state->pingpong_to_crtc_id[pp_idx[i]] = crtc_id;
global_state->dspp_to_crtc_id[dspp_idx[i]] =
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index e0de545d4077..db6da99375a1 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -584,13 +584,30 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host)
* FIXME: Reconsider this if/when CMD mode handling is rewritten to use
* transfer time and data overhead as a starting point of the calculations.
*/
-static unsigned long dsi_adjust_pclk_for_compression(const struct drm_display_mode *mode,
- const struct drm_dsc_config *dsc)
+static unsigned long
+dsi_adjust_pclk_for_compression(const struct drm_display_mode *mode,
+ const struct drm_dsc_config *dsc,
+ bool is_bonded_dsi)
{
- int new_hdisplay = DIV_ROUND_UP(mode->hdisplay * drm_dsc_get_bpp_int(dsc),
- dsc->bits_per_component * 3);
+ int hdisplay, new_hdisplay, new_htotal;
- int new_htotal = mode->htotal - mode->hdisplay + new_hdisplay;
+ /*
+ * For bonded DSI, split hdisplay across two links and round up each
+ * half separately, passing the full hdisplay would only round up once.
+ * This also aligns with the hdisplay we program later in
+ * dsi_timing_setup()
+ */
+ hdisplay = mode->hdisplay;
+ if (is_bonded_dsi)
+ hdisplay /= 2;
+
+ new_hdisplay = DIV_ROUND_UP(hdisplay * drm_dsc_get_bpp_int(dsc),
+ dsc->bits_per_component * 3);
+
+ if (is_bonded_dsi)
+ new_hdisplay *= 2;
+
+ new_htotal = mode->htotal - mode->hdisplay + new_hdisplay;
return mult_frac(mode->clock * 1000u, new_htotal, mode->htotal);
}
@@ -603,7 +620,7 @@ static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode,
pclk_rate = mode->clock * 1000u;
if (dsc)
- pclk_rate = dsi_adjust_pclk_for_compression(mode, dsc);
+ pclk_rate = dsi_adjust_pclk_for_compression(mode, dsc, is_bonded_dsi);
/*
* For bonded DSI mode, the current DRM mode has the complete width of the
@@ -993,7 +1010,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
if (msm_host->dsc) {
struct drm_dsc_config *dsc = msm_host->dsc;
- u32 bytes_per_pclk;
+ u32 bits_per_pclk;
/* update dsc params with timing params */
if (!dsc || !mode->hdisplay || !mode->vdisplay) {
@@ -1015,7 +1032,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
/*
* DPU sends 3 bytes per pclk cycle to DSI. If widebus is
- * enabled, bus width is extended to 6 bytes.
+ * enabled, MDP always sends out 48-bit compressed data per
+ * pclk and on average, DSI consumes an amount of compressed
+ * data equivalent to the uncompressed pixel depth per pclk.
*
* Calculate the number of pclks needed to transmit one line of
* the compressed data.
@@ -1027,12 +1046,12 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
* unused anyway.
*/
h_total -= hdisplay;
- if (wide_bus_enabled && !(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO))
- bytes_per_pclk = 6;
+ if (wide_bus_enabled)
+ bits_per_pclk = mipi_dsi_pixel_format_to_bpp(msm_host->format);
else
- bytes_per_pclk = 3;
+ bits_per_pclk = 24;
- hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc), bytes_per_pclk);
+ hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc) * 8, bits_per_pclk);
h_total += hdisplay;
ha_end = ha_start + hdisplay;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
index 8cb0db3a9880..01182442dfd6 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
@@ -51,8 +51,8 @@
#define DSI_PHY_7NM_QUIRK_V4_3 BIT(3)
/* Hardware is V5.2 */
#define DSI_PHY_7NM_QUIRK_V5_2 BIT(4)
-/* Hardware is V7.0 */
-#define DSI_PHY_7NM_QUIRK_V7_0 BIT(5)
+/* Hardware is V7.2 */
+#define DSI_PHY_7NM_QUIRK_V7_2 BIT(5)
struct dsi_pll_config {
bool enable_ssc;
@@ -143,7 +143,7 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config
if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) {
config->pll_clock_inverters = 0x28;
- } else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
+ } else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) {
if (pll_freq < 163000000ULL)
config->pll_clock_inverters = 0xa0;
else if (pll_freq < 175000000ULL)
@@ -284,7 +284,7 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll)
}
if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
- (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
+ (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) {
if (pll->vco_current_rate < 1557000000ULL)
vco_config_1 = 0x08;
else
@@ -699,7 +699,7 @@ static int dsi_7nm_set_usecase(struct msm_dsi_phy *phy)
case MSM_DSI_PHY_MASTER:
pll_7nm->slave = pll_7nm_list[(pll_7nm->phy->id + 1) % DSI_MAX];
/* v7.0: Enable ATB_EN0 and alternate clock output to external phy */
- if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)
+ if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)
writel(0x07, base + REG_DSI_7nm_PHY_CMN_CTRL_5);
break;
case MSM_DSI_PHY_SLAVE:
@@ -987,7 +987,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
/* Request for REFGEN READY */
if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) ||
(phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
- (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
+ (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) {
writel(0x1, phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10);
udelay(500);
}
@@ -1021,7 +1021,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
lane_ctrl0 = 0x1f;
}
- if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
+ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) {
if (phy->cphy_mode) {
/* TODO: different for second phy */
vreg_ctrl_0 = 0x57;
@@ -1097,7 +1097,7 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
/* program CMN_CTRL_4 for minor_ver 2 chipsets*/
if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
- (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0) ||
+ (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2) ||
(readl(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0) & (0xf0)) == 0x20)
writel(0x04, base + REG_DSI_7nm_PHY_CMN_CTRL_4);
@@ -1213,7 +1213,7 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
/* Turn off REFGEN Vote */
if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) ||
(phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
- (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_0)) {
+ (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V7_2)) {
writel(0x0, base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10);
wmb();
/* Delay to ensure HW removes vote before PHY shut down */
@@ -1502,7 +1502,7 @@ const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs = {
#endif
.io_start = { 0xae95000, 0xae97000 },
.num_dsi_phy = 2,
- .quirks = DSI_PHY_7NM_QUIRK_V7_0,
+ .quirks = DSI_PHY_7NM_QUIRK_V7_2,
};
const struct msm_dsi_phy_cfg dsi_phy_3nm_kaanapali_cfgs = {
@@ -1525,5 +1525,5 @@ const struct msm_dsi_phy_cfg dsi_phy_3nm_kaanapali_cfgs = {
#endif
.io_start = { 0x9ac1000, 0x9ac4000 },
.num_dsi_phy = 2,
- .quirks = DSI_PHY_7NM_QUIRK_V7_0,
+ .quirks = DSI_PHY_7NM_QUIRK_V7_2,
};
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index b4aa49b1ac63..4b10715f951c 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -2915,9 +2915,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
if (rdev->family == CHIP_HAINAN) {
if ((rdev->pdev->revision == 0x81) ||
(rdev->pdev->revision == 0xC3) ||
+ (rdev->pdev->device == 0x6660) ||
(rdev->pdev->device == 0x6664) ||
(rdev->pdev->device == 0x6665) ||
- (rdev->pdev->device == 0x6667)) {
+ (rdev->pdev->device == 0x6667) ||
+ (rdev->pdev->device == 0x666F)) {
max_sclk = 75000;
}
if ((rdev->pdev->revision == 0xC3) ||
diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
index 68172b0248a6..dc5a4fafa70c 100644
--- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h
@@ -96,6 +96,12 @@
#define ENABLE_SEMAPHORE_POLL_BIT REG_BIT(13)
#define RING_CMD_CCTL(base) XE_REG((base) + 0xc4, XE_REG_OPTION_MASKED)
+
+#define CS_MMIO_GROUP_INSTANCE_SELECT(base) XE_REG((base) + 0xcc)
+#define SELECTIVE_READ_ADDRESSING REG_BIT(30)
+#define SELECTIVE_READ_GROUP REG_GENMASK(29, 23)
+#define SELECTIVE_READ_INSTANCE REG_GENMASK(22, 16)
+
/*
* CMD_CCTL read/write fields take a MOCS value and _not_ a table index.
* The lsb of each can be considered a separate enabling bit for encryption.
diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
index 24fc64fc832e..9d66f168ab8a 100644
--- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
@@ -553,6 +553,7 @@
#define ENABLE_SMP_LD_RENDER_SURFACE_CONTROL REG_BIT(44 - 32)
#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32)
#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32)
+#define L3_128B_256B_WRT_DIS REG_BIT(40 - 32)
#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32)
#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32)
diff --git a/drivers/gpu/drm/xe/xe_configfs.c b/drivers/gpu/drm/xe/xe_configfs.c
index c59b1414df22..7fd07d1280bb 100644
--- a/drivers/gpu/drm/xe/xe_configfs.c
+++ b/drivers/gpu/drm/xe/xe_configfs.c
@@ -830,6 +830,7 @@ static void xe_config_device_release(struct config_item *item)
mutex_destroy(&dev->lock);
+ kfree(dev->config.ctx_restore_mid_bb[0].cs);
kfree(dev->config.ctx_restore_post_bb[0].cs);
kfree(dev);
}
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 52ee24e9cd3a..3eb06b27db7e 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -837,6 +837,14 @@ static void detect_preproduction_hw(struct xe_device *xe)
}
}
+static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
+{
+ struct xe_device *xe = arg;
+
+ if (atomic_read(&xe->wedged.flag))
+ xe_pm_runtime_put(xe);
+}
+
int xe_device_probe(struct xe_device *xe)
{
struct xe_tile *tile;
@@ -1013,6 +1021,10 @@ int xe_device_probe(struct xe_device *xe)
detect_preproduction_hw(xe);
+ err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe);
+ if (err)
+ goto err_unregister_display;
+
return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
err_unregister_display:
@@ -1216,13 +1228,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address)
return address & GENMASK_ULL(xe->info.va_bits - 1, 0);
}
-static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
-{
- struct xe_device *xe = arg;
-
- xe_pm_runtime_put(xe);
-}
-
/**
* DOC: Xe Device Wedging
*
@@ -1300,15 +1305,9 @@ void xe_device_declare_wedged(struct xe_device *xe)
return;
}
- xe_pm_runtime_get_noresume(xe);
-
- if (drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe)) {
- drm_err(&xe->drm, "Failed to register xe_device_wedged_fini clean-up. Although device is wedged.\n");
- return;
- }
-
if (!atomic_xchg(&xe->wedged.flag, 1)) {
xe->needs_flr_on_fini = true;
+ xe_pm_runtime_get_noresume(xe);
drm_err(&xe->drm,
"CRITICAL: Xe has declared device %s as wedged.\n"
"IOCTLs and executions are blocked. Only a rebind may clear the failure\n"
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 0ddae7fcfc97..8ecdf949f9e4 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -266,6 +266,16 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
return q;
}
+static void __xe_exec_queue_fini(struct xe_exec_queue *q)
+{
+ int i;
+
+ q->ops->fini(q);
+
+ for (i = 0; i < q->width; ++i)
+ xe_lrc_put(q->lrc[i]);
+}
+
static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
{
int i, err;
@@ -320,21 +330,10 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
return 0;
err_lrc:
- for (i = i - 1; i >= 0; --i)
- xe_lrc_put(q->lrc[i]);
+ __xe_exec_queue_fini(q);
return err;
}
-static void __xe_exec_queue_fini(struct xe_exec_queue *q)
-{
- int i;
-
- q->ops->fini(q);
-
- for (i = 0; i < q->width; ++i)
- xe_lrc_put(q->lrc[i]);
-}
-
struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm,
u32 logical_mask, u16 width,
struct xe_hw_engine *hwe, u32 flags,
diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c
index 2bda426a6986..d1561ebe4e56 100644
--- a/drivers/gpu/drm/xe/xe_ggtt.c
+++ b/drivers/gpu/drm/xe/xe_ggtt.c
@@ -313,6 +313,8 @@ static void dev_fini_ggtt(void *arg)
{
struct xe_ggtt *ggtt = arg;
+ scoped_guard(mutex, &ggtt->lock)
+ ggtt->flags &= ~XE_GGTT_FLAGS_ONLINE;
drain_workqueue(ggtt->wq);
}
@@ -377,6 +379,7 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
if (err)
return err;
+ ggtt->flags |= XE_GGTT_FLAGS_ONLINE;
err = devm_add_action_or_reset(xe->drm.dev, dev_fini_ggtt, ggtt);
if (err)
return err;
@@ -410,13 +413,10 @@ static void xe_ggtt_initial_clear(struct xe_ggtt *ggtt)
static void ggtt_node_remove(struct xe_ggtt_node *node)
{
struct xe_ggtt *ggtt = node->ggtt;
- struct xe_device *xe = tile_to_xe(ggtt->tile);
bool bound;
- int idx;
-
- bound = drm_dev_enter(&xe->drm, &idx);
mutex_lock(&ggtt->lock);
+ bound = ggtt->flags & XE_GGTT_FLAGS_ONLINE;
if (bound)
xe_ggtt_clear(ggtt, node->base.start, node->base.size);
drm_mm_remove_node(&node->base);
@@ -429,8 +429,6 @@ static void ggtt_node_remove(struct xe_ggtt_node *node)
if (node->invalidate_on_remove)
xe_ggtt_invalidate(ggtt);
- drm_dev_exit(idx);
-
free_node:
xe_ggtt_node_fini(node);
}
diff --git a/drivers/gpu/drm/xe/xe_ggtt_types.h b/drivers/gpu/drm/xe/xe_ggtt_types.h
index d82b71a198bc..c002857bb761 100644
--- a/drivers/gpu/drm/xe/xe_ggtt_types.h
+++ b/drivers/gpu/drm/xe/xe_ggtt_types.h
@@ -28,11 +28,14 @@ struct xe_ggtt {
/** @size: Total usable size of this GGTT */
u64 size;
-#define XE_GGTT_FLAGS_64K BIT(0)
+#define XE_GGTT_FLAGS_64K BIT(0)
+#define XE_GGTT_FLAGS_ONLINE BIT(1)
/**
* @flags: Flags for this GGTT
* Acceptable flags:
* - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K.
+ * - %XE_GGTT_FLAGS_ONLINE - is GGTT online, protected by ggtt->lock
+ * after init
*/
unsigned int flags;
/** @scratch: Internal object allocation used as a scratch page */
diff --git a/drivers/gpu/drm/xe/xe_gsc_proxy.c b/drivers/gpu/drm/xe/xe_gsc_proxy.c
index 42438b21f235..707db650a2ae 100644
--- a/drivers/gpu/drm/xe/xe_gsc_proxy.c
+++ b/drivers/gpu/drm/xe/xe_gsc_proxy.c
@@ -435,15 +435,11 @@ static int proxy_channel_alloc(struct xe_gsc *gsc)
return 0;
}
-static void xe_gsc_proxy_remove(void *arg)
+static void xe_gsc_proxy_stop(struct xe_gsc *gsc)
{
- struct xe_gsc *gsc = arg;
struct xe_gt *gt = gsc_to_gt(gsc);
struct xe_device *xe = gt_to_xe(gt);
- if (!gsc->proxy.component_added)
- return;
-
/* disable HECI2 IRQs */
scoped_guard(xe_pm_runtime, xe) {
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC);
@@ -455,6 +451,30 @@ static void xe_gsc_proxy_remove(void *arg)
}
xe_gsc_wait_for_worker_completion(gsc);
+ gsc->proxy.started = false;
+}
+
+static void xe_gsc_proxy_remove(void *arg)
+{
+ struct xe_gsc *gsc = arg;
+ struct xe_gt *gt = gsc_to_gt(gsc);
+ struct xe_device *xe = gt_to_xe(gt);
+
+ if (!gsc->proxy.component_added)
+ return;
+
+ /*
+ * GSC proxy start is an async process that can be ongoing during
+ * Xe module load/unload. Using devm managed action to register
+ * xe_gsc_proxy_stop could cause issues if Xe module unload has
+ * already started when the action is registered, potentially leading
+ * to the cleanup being called at the wrong time. Therefore, instead
+ * of registering a separate devm action to undo what is done in
+ * proxy start, we call it from here, but only if the start has
+ * completed successfully (tracked with the 'started' flag).
+ */
+ if (gsc->proxy.started)
+ xe_gsc_proxy_stop(gsc);
component_del(xe->drm.dev, &xe_gsc_proxy_component_ops);
gsc->proxy.component_added = false;
@@ -510,6 +530,7 @@ int xe_gsc_proxy_init(struct xe_gsc *gsc)
*/
int xe_gsc_proxy_start(struct xe_gsc *gsc)
{
+ struct xe_gt *gt = gsc_to_gt(gsc);
int err;
/* enable the proxy interrupt in the GSC shim layer */
@@ -521,12 +542,18 @@ int xe_gsc_proxy_start(struct xe_gsc *gsc)
*/
err = xe_gsc_proxy_request_handler(gsc);
if (err)
- return err;
+ goto err_irq_disable;
if (!xe_gsc_proxy_init_done(gsc)) {
- xe_gt_err(gsc_to_gt(gsc), "GSC FW reports proxy init not completed\n");
- return -EIO;
+ xe_gt_err(gt, "GSC FW reports proxy init not completed\n");
+ err = -EIO;
+ goto err_irq_disable;
}
+ gsc->proxy.started = true;
return 0;
+
+err_irq_disable:
+ gsc_proxy_irq_toggle(gsc, false);
+ return err;
}
diff --git a/drivers/gpu/drm/xe/xe_gsc_types.h b/drivers/gpu/drm/xe/xe_gsc_types.h
index 97c056656df0..5aaa2a75861f 100644
--- a/drivers/gpu/drm/xe/xe_gsc_types.h
+++ b/drivers/gpu/drm/xe/xe_gsc_types.h
@@ -58,6 +58,8 @@ struct xe_gsc {
struct mutex mutex;
/** @proxy.component_added: whether the component has been added */
bool component_added;
+ /** @proxy.started: whether the proxy has been started */
+ bool started;
/** @proxy.bo: object to store message to and from the GSC */
struct xe_bo *bo;
/** @proxy.to_gsc: map of the memory used to send messages to the GSC */
diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c
index 9d090d0f2438..df6d04704823 100644
--- a/drivers/gpu/drm/xe/xe_gt.c
+++ b/drivers/gpu/drm/xe/xe_gt.c
@@ -210,11 +210,15 @@ static int emit_nop_job(struct xe_gt *gt, struct xe_exec_queue *q)
return ret;
}
+/* Dwords required to emit a RMW of a register */
+#define EMIT_RMW_DW 20
+
static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
{
- struct xe_reg_sr *sr = &q->hwe->reg_lrc;
+ struct xe_hw_engine *hwe = q->hwe;
+ struct xe_reg_sr *sr = &hwe->reg_lrc;
struct xe_reg_sr_entry *entry;
- int count_rmw = 0, count = 0, ret;
+ int count_rmw = 0, count_rmw_mcr = 0, count = 0, ret;
unsigned long idx;
struct xe_bb *bb;
size_t bb_len = 0;
@@ -224,6 +228,8 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
xa_for_each(&sr->xa, idx, entry) {
if (entry->reg.masked || entry->clr_bits == ~0)
++count;
+ else if (entry->reg.mcr)
+ ++count_rmw_mcr;
else
++count_rmw;
}
@@ -231,17 +237,35 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
if (count)
bb_len += count * 2 + 1;
- if (count_rmw)
- bb_len += count_rmw * 20 + 7;
+ /*
+ * RMW of MCR registers is the same as a normal RMW, except an
+ * additional LRI (3 dwords) is required per register to steer the read
+ * to a nom-terminated instance.
+ *
+ * We could probably shorten the batch slightly by eliding the
+ * steering for consecutive MCR registers that have the same
+ * group/instance target, but it's not worth the extra complexity to do
+ * so.
+ */
+ bb_len += count_rmw * EMIT_RMW_DW;
+ bb_len += count_rmw_mcr * (EMIT_RMW_DW + 3);
+
+ /*
+ * After doing all RMW, we need 7 trailing dwords to clean up,
+ * plus an additional 3 dwords to reset steering if any of the
+ * registers were MCR.
+ */
+ if (count_rmw || count_rmw_mcr)
+ bb_len += 7 + (count_rmw_mcr ? 3 : 0);
- if (q->hwe->class == XE_ENGINE_CLASS_RENDER)
+ if (hwe->class == XE_ENGINE_CLASS_RENDER)
/*
* Big enough to emit all of the context's 3DSTATE via
* xe_lrc_emit_hwe_state_instructions()
*/
- bb_len += xe_gt_lrc_size(gt, q->hwe->class) / sizeof(u32);
+ bb_len += xe_gt_lrc_size(gt, hwe->class) / sizeof(u32);
- xe_gt_dbg(gt, "LRC %s WA job: %zu dwords\n", q->hwe->name, bb_len);
+ xe_gt_dbg(gt, "LRC %s WA job: %zu dwords\n", hwe->name, bb_len);
bb = xe_bb_new(gt, bb_len, false);
if (IS_ERR(bb))
@@ -276,13 +300,23 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
}
}
- if (count_rmw) {
- /* Emit MI_MATH for each RMW reg: 20dw per reg + 7 trailing dw */
-
+ if (count_rmw || count_rmw_mcr) {
xa_for_each(&sr->xa, idx, entry) {
if (entry->reg.masked || entry->clr_bits == ~0)
continue;
+ if (entry->reg.mcr) {
+ struct xe_reg_mcr reg = { .__reg.raw = entry->reg.raw };
+ u8 group, instance;
+
+ xe_gt_mcr_get_nonterminated_steering(gt, reg, &group, &instance);
+ *cs++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1);
+ *cs++ = CS_MMIO_GROUP_INSTANCE_SELECT(hwe->mmio_base).addr;
+ *cs++ = SELECTIVE_READ_ADDRESSING |
+ REG_FIELD_PREP(SELECTIVE_READ_GROUP, group) |
+ REG_FIELD_PREP(SELECTIVE_READ_INSTANCE, instance);
+ }
+
*cs++ = MI_LOAD_REGISTER_REG | MI_LRR_DST_CS_MMIO;
*cs++ = entry->reg.addr;
*cs++ = CS_GPR_REG(0, 0).addr;
@@ -308,8 +342,9 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
*cs++ = CS_GPR_REG(0, 0).addr;
*cs++ = entry->reg.addr;
- xe_gt_dbg(gt, "REG[%#x] = ~%#x|%#x\n",
- entry->reg.addr, entry->clr_bits, entry->set_bits);
+ xe_gt_dbg(gt, "REG[%#x] = ~%#x|%#x%s\n",
+ entry->reg.addr, entry->clr_bits, entry->set_bits,
+ entry->reg.mcr ? " (MCR)" : "");
}
/* reset used GPR */
@@ -321,6 +356,13 @@ static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q)
*cs++ = 0;
*cs++ = CS_GPR_REG(0, 2).addr;
*cs++ = 0;
+
+ /* reset steering */
+ if (count_rmw_mcr) {
+ *cs++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1);
+ *cs++ = CS_MMIO_GROUP_INSTANCE_SELECT(q->hwe->mmio_base).addr;
+ *cs++ = 0;
+ }
}
cs = xe_lrc_emit_hwe_state_instructions(q, cs);
diff --git a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
index fe944687728c..03c1862ba497 100644
--- a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
+++ b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c
@@ -12,6 +12,7 @@
#include "xe_gt_printk.h"
#include "xe_gt_sysfs.h"
#include "xe_mmio.h"
+#include "xe_pm.h"
#include "xe_sriov.h"
static void __xe_gt_apply_ccs_mode(struct xe_gt *gt, u32 num_engines)
@@ -150,6 +151,7 @@ ccs_mode_store(struct device *kdev, struct device_attribute *attr,
xe_gt_info(gt, "Setting compute mode to %d\n", num_engines);
gt->ccs_mode = num_engines;
xe_gt_record_user_engines(gt);
+ guard(xe_pm_runtime)(xe);
xe_gt_reset(gt);
}
diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c
index 6df7c3f260e5..4ab65cae8743 100644
--- a/drivers/gpu/drm/xe/xe_guc.c
+++ b/drivers/gpu/drm/xe/xe_guc.c
@@ -1124,14 +1124,14 @@ static int guc_wait_ucode(struct xe_guc *guc)
struct xe_guc_pc *guc_pc = &gt->uc.guc.pc;
u32 before_freq, act_freq, cur_freq;
u32 status = 0, tries = 0;
+ int load_result, ret;
ktime_t before;
u64 delta_ms;
- int ret;
before_freq = xe_guc_pc_get_act_freq(guc_pc);
before = ktime_get();
- ret = poll_timeout_us(ret = guc_load_done(gt, &status, &tries), ret,
+ ret = poll_timeout_us(load_result = guc_load_done(gt, &status, &tries), load_result,
10 * USEC_PER_MSEC,
GUC_LOAD_TIMEOUT_SEC * USEC_PER_SEC, false);
@@ -1139,7 +1139,7 @@ static int guc_wait_ucode(struct xe_guc *guc)
act_freq = xe_guc_pc_get_act_freq(guc_pc);
cur_freq = xe_guc_pc_get_cur_freq_fw(guc_pc);
- if (ret) {
+ if (ret || load_result <= 0) {
xe_gt_err(gt, "load failed: status = 0x%08X, time = %lldms, freq = %dMHz (req %dMHz)\n",
status, delta_ms, xe_guc_pc_get_act_freq(guc_pc),
xe_guc_pc_get_cur_freq_fw(guc_pc));
@@ -1347,15 +1347,37 @@ int xe_guc_enable_communication(struct xe_guc *guc)
return 0;
}
-int xe_guc_suspend(struct xe_guc *guc)
+/**
+ * xe_guc_softreset() - Soft reset GuC
+ * @guc: The GuC object
+ *
+ * Send soft reset command to GuC through mmio send.
+ *
+ * Return: 0 if success, otherwise error code
+ */
+int xe_guc_softreset(struct xe_guc *guc)
{
- struct xe_gt *gt = guc_to_gt(guc);
u32 action[] = {
XE_GUC_ACTION_CLIENT_SOFT_RESET,
};
int ret;
+ if (!xe_uc_fw_is_running(&guc->fw))
+ return 0;
+
ret = xe_guc_mmio_send(guc, action, ARRAY_SIZE(action));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int xe_guc_suspend(struct xe_guc *guc)
+{
+ struct xe_gt *gt = guc_to_gt(guc);
+ int ret;
+
+ ret = xe_guc_softreset(guc);
if (ret) {
xe_gt_err(gt, "GuC suspend failed: %pe\n", ERR_PTR(ret));
return ret;
diff --git a/drivers/gpu/drm/xe/xe_guc.h b/drivers/gpu/drm/xe/xe_guc.h
index 66e7edc70ed9..02514914f404 100644
--- a/drivers/gpu/drm/xe/xe_guc.h
+++ b/drivers/gpu/drm/xe/xe_guc.h
@@ -44,6 +44,7 @@ int xe_guc_opt_in_features_enable(struct xe_guc *guc);
void xe_guc_runtime_suspend(struct xe_guc *guc);
void xe_guc_runtime_resume(struct xe_guc *guc);
int xe_guc_suspend(struct xe_guc *guc);
+int xe_guc_softreset(struct xe_guc *guc);
void xe_guc_notify(struct xe_guc *guc);
int xe_guc_auth_huc(struct xe_guc *guc, u32 rsa_addr);
int xe_guc_mmio_send(struct xe_guc *guc, const u32 *request, u32 len);
diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c
index d04589140b77..c80082b4c876 100644
--- a/drivers/gpu/drm/xe/xe_guc_ct.c
+++ b/drivers/gpu/drm/xe/xe_guc_ct.c
@@ -345,6 +345,7 @@ static void guc_action_disable_ct(void *arg)
{
struct xe_guc_ct *ct = arg;
+ xe_guc_ct_stop(ct);
guc_ct_change_state(ct, XE_GUC_CT_STATE_DISABLED);
}
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 799ef9f48003..fc4f99d46763 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -48,6 +48,8 @@
#define XE_GUC_EXEC_QUEUE_CGP_CONTEXT_ERROR_LEN 6
+static int guc_submit_reset_prepare(struct xe_guc *guc);
+
static struct xe_guc *
exec_queue_to_guc(struct xe_exec_queue *q)
{
@@ -239,7 +241,7 @@ static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q)
EXEC_QUEUE_STATE_BANNED));
}
-static void guc_submit_fini(struct drm_device *drm, void *arg)
+static void guc_submit_sw_fini(struct drm_device *drm, void *arg)
{
struct xe_guc *guc = arg;
struct xe_device *xe = guc_to_xe(guc);
@@ -257,6 +259,19 @@ static void guc_submit_fini(struct drm_device *drm, void *arg)
xa_destroy(&guc->submission_state.exec_queue_lookup);
}
+static void guc_submit_fini(void *arg)
+{
+ struct xe_guc *guc = arg;
+
+ /* Forcefully kill any remaining exec queues */
+ xe_guc_ct_stop(&guc->ct);
+ guc_submit_reset_prepare(guc);
+ xe_guc_softreset(guc);
+ xe_guc_submit_stop(guc);
+ xe_uc_fw_sanitize(&guc->fw);
+ xe_guc_submit_pause_abort(guc);
+}
+
static void guc_submit_wedged_fini(void *arg)
{
struct xe_guc *guc = arg;
@@ -326,7 +341,11 @@ int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids)
guc->submission_state.initialized = true;
- return drmm_add_action_or_reset(&xe->drm, guc_submit_fini, guc);
+ err = drmm_add_action_or_reset(&xe->drm, guc_submit_sw_fini, guc);
+ if (err)
+ return err;
+
+ return devm_add_action_or_reset(xe->drm.dev, guc_submit_fini, guc);
}
/*
@@ -1252,6 +1271,7 @@ static void disable_scheduling_deregister(struct xe_guc *guc,
*/
void xe_guc_submit_wedge(struct xe_guc *guc)
{
+ struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
struct xe_exec_queue *q;
unsigned long index;
@@ -1266,20 +1286,28 @@ void xe_guc_submit_wedge(struct xe_guc *guc)
if (!guc->submission_state.initialized)
return;
- err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev,
- guc_submit_wedged_fini, guc);
- if (err) {
- xe_gt_err(gt, "Failed to register clean-up in wedged.mode=%s; "
- "Although device is wedged.\n",
- xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET));
- return;
- }
+ if (xe->wedged.mode == 2) {
+ err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev,
+ guc_submit_wedged_fini, guc);
+ if (err) {
+ xe_gt_err(gt, "Failed to register clean-up on wedged.mode=2; "
+ "Although device is wedged.\n");
+ return;
+ }
- mutex_lock(&guc->submission_state.lock);
- xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
- if (xe_exec_queue_get_unless_zero(q))
- set_exec_queue_wedged(q);
- mutex_unlock(&guc->submission_state.lock);
+ mutex_lock(&guc->submission_state.lock);
+ xa_for_each(&guc->submission_state.exec_queue_lookup, index, q)
+ if (xe_exec_queue_get_unless_zero(q))
+ set_exec_queue_wedged(q);
+ mutex_unlock(&guc->submission_state.lock);
+ } else {
+ /* Forcefully kill any remaining exec queues, signal fences */
+ guc_submit_reset_prepare(guc);
+ xe_guc_submit_stop(guc);
+ xe_guc_softreset(guc);
+ xe_uc_fw_sanitize(&guc->fw);
+ xe_guc_submit_pause_abort(guc);
+ }
}
static bool guc_submit_hint_wedged(struct xe_guc *guc)
@@ -2230,6 +2258,7 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = {
static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
{
struct xe_gpu_scheduler *sched = &q->guc->sched;
+ bool do_destroy = false;
/* Stop scheduling + flush any DRM scheduler operations */
xe_sched_submission_stop(sched);
@@ -2237,7 +2266,7 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
/* Clean up lost G2H + reset engine state */
if (exec_queue_registered(q)) {
if (exec_queue_destroyed(q))
- __guc_exec_queue_destroy(guc, q);
+ do_destroy = true;
}
if (q->guc->suspend_pending) {
set_exec_queue_suspended(q);
@@ -2273,18 +2302,15 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
xe_guc_exec_queue_trigger_cleanup(q);
}
}
+
+ if (do_destroy)
+ __guc_exec_queue_destroy(guc, q);
}
-int xe_guc_submit_reset_prepare(struct xe_guc *guc)
+static int guc_submit_reset_prepare(struct xe_guc *guc)
{
int ret;
- if (xe_gt_WARN_ON(guc_to_gt(guc), vf_recovery(guc)))
- return 0;
-
- if (!guc->submission_state.initialized)
- return 0;
-
/*
* Using an atomic here rather than submission_state.lock as this
* function can be called while holding the CT lock (engine reset
@@ -2299,6 +2325,17 @@ int xe_guc_submit_reset_prepare(struct xe_guc *guc)
return ret;
}
+int xe_guc_submit_reset_prepare(struct xe_guc *guc)
+{
+ if (xe_gt_WARN_ON(guc_to_gt(guc), vf_recovery(guc)))
+ return 0;
+
+ if (!guc->submission_state.initialized)
+ return 0;
+
+ return guc_submit_reset_prepare(guc);
+}
+
void xe_guc_submit_reset_wait(struct xe_guc *guc)
{
wait_event(guc->ct.wq, xe_device_wedged(guc_to_xe(guc)) ||
@@ -2695,8 +2732,7 @@ void xe_guc_submit_pause_abort(struct xe_guc *guc)
continue;
xe_sched_submission_start(sched);
- if (exec_queue_killed_or_banned_or_wedged(q))
- xe_guc_exec_queue_trigger_cleanup(q);
+ guc_exec_queue_kill(q);
}
mutex_unlock(&guc->submission_state.lock);
}
diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 688d645e0e73..aa0b7a427f0b 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -595,9 +595,8 @@ static void adjust_idledly(struct xe_hw_engine *hwe)
maxcnt *= maxcnt_units_ns;
if (xe_gt_WARN_ON(gt, idledly >= maxcnt || inhibit_switch)) {
- idledly = DIV_ROUND_CLOSEST(((maxcnt - 1) * maxcnt_units_ns),
+ idledly = DIV_ROUND_CLOSEST(((maxcnt - 1) * 1000),
idledly_units_ps);
- idledly = DIV_ROUND_CLOSEST(idledly, 1000);
xe_mmio_write32(&gt->mmio, RING_IDLEDLY(hwe->mmio_base), idledly);
}
}
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index b0f037bc227f..7b70cc01fdb3 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -2413,14 +2413,14 @@ static int get_ctx_timestamp(struct xe_lrc *lrc, u32 engine_id, u64 *reg_ctx_ts)
* @lrc: Pointer to the lrc.
*
* Return latest ctx timestamp. With support for active contexts, the
- * calculation may bb slightly racy, so follow a read-again logic to ensure that
+ * calculation may be slightly racy, so follow a read-again logic to ensure that
* the context is still active before returning the right timestamp.
*
* Returns: New ctx timestamp value
*/
u64 xe_lrc_timestamp(struct xe_lrc *lrc)
{
- u64 lrc_ts, reg_ts, new_ts;
+ u64 lrc_ts, reg_ts, new_ts = lrc->ctx_timestamp;
u32 engine_id;
lrc_ts = xe_lrc_ctx_timestamp(lrc);
diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
index c307a3fd9ea2..c1c615447c85 100644
--- a/drivers/gpu/drm/xe/xe_lrc.h
+++ b/drivers/gpu/drm/xe/xe_lrc.h
@@ -75,7 +75,8 @@ static inline struct xe_lrc *xe_lrc_get(struct xe_lrc *lrc)
*/
static inline void xe_lrc_put(struct xe_lrc *lrc)
{
- kref_put(&lrc->refcount, xe_lrc_destroy);
+ if (lrc)
+ kref_put(&lrc->refcount, xe_lrc_destroy);
}
/**
diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
index 4dd3f29933cf..fa90441d3052 100644
--- a/drivers/gpu/drm/xe/xe_oa.c
+++ b/drivers/gpu/drm/xe/xe_oa.c
@@ -543,8 +543,7 @@ static ssize_t xe_oa_read(struct file *file, char __user *buf,
size_t offset = 0;
int ret;
- /* Can't read from disabled streams */
- if (!stream->enabled || !stream->sample)
+ if (!stream->sample)
return -EINVAL;
if (!(file->f_flags & O_NONBLOCK)) {
@@ -1460,6 +1459,10 @@ static void xe_oa_stream_disable(struct xe_oa_stream *stream)
if (stream->sample)
hrtimer_cancel(&stream->poll_check_timer);
+
+ /* Update stream->oa_buffer.tail to allow any final reports to be read */
+ if (xe_oa_buffer_check_unlocked(stream))
+ wake_up(&stream->poll_wq);
}
static int xe_oa_enable_preempt_timeslice(struct xe_oa_stream *stream)
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c
index 6bee53d6ffc3..922a4f3344b1 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -187,6 +187,12 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
goto unlock_vm;
}
+ if (xe_vma_read_only(vma) &&
+ pf->consumer.access_type != XE_PAGEFAULT_ACCESS_TYPE_READ) {
+ err = -EPERM;
+ goto unlock_vm;
+ }
+
atomic = xe_pagefault_access_is_atomic(pf->consumer.access_type);
if (xe_vma_is_cpu_addr_mirror(vma))
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 13b355fadd58..713a303c9053 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -1442,9 +1442,9 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op,
err = vma_check_userptr(vm, op->map.vma, pt_update);
break;
case DRM_GPUVA_OP_REMAP:
- if (op->remap.prev)
+ if (op->remap.prev && !op->remap.skip_prev)
err = vma_check_userptr(vm, op->remap.prev, pt_update);
- if (!err && op->remap.next)
+ if (!err && op->remap.next && !op->remap.skip_next)
err = vma_check_userptr(vm, op->remap.next, pt_update);
break;
case DRM_GPUVA_OP_UNMAP:
@@ -1655,15 +1655,36 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
XE_WARN_ON(!level);
/* Check for leaf node */
if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) &&
- (!xe_child->base.children || !xe_child->base.children[first])) {
+ xe_child->level <= MAX_HUGEPTE_LEVEL) {
struct iosys_map *leaf_map = &xe_child->bo->vmap;
pgoff_t count = xe_pt_num_entries(addr, next, xe_child->level, walk);
for (pgoff_t i = 0; i < count; i++) {
- u64 pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64);
+ u64 pte;
int ret;
/*
+ * If not a leaf pt, skip unless non-leaf pt is interleaved between
+ * leaf ptes which causes the page walk to skip over the child leaves
+ */
+ if (xe_child->base.children && xe_child->base.children[first + i]) {
+ u64 pt_size = 1ULL << walk->shifts[xe_child->level];
+ bool edge_pt = (i == 0 && !IS_ALIGNED(addr, pt_size)) ||
+ (i == count - 1 && !IS_ALIGNED(next, pt_size));
+
+ if (!edge_pt) {
+ xe_page_reclaim_list_abort(xe_walk->tile->primary_gt,
+ xe_walk->prl,
+ "PT is skipped by walk at level=%u offset=%lu",
+ xe_child->level, first + i);
+ break;
+ }
+ continue;
+ }
+
+ pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64);
+
+ /*
* In rare scenarios, pte may not be written yet due to racy conditions.
* In such cases, invalidate the PRL and fallback to full PPC invalidation.
*/
@@ -1674,9 +1695,8 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
}
/* Ensure it is a defined page */
- xe_tile_assert(xe_walk->tile,
- xe_child->level == 0 ||
- (pte & (XE_PTE_PS64 | XE_PDE_PS_2M | XE_PDPE_PS_1G)));
+ xe_tile_assert(xe_walk->tile, xe_child->level == 0 ||
+ (pte & (XE_PDE_PS_2M | XE_PDPE_PS_1G)));
/* An entry should be added for 64KB but contigious 4K have XE_PTE_PS64 */
if (pte & XE_PTE_PS64)
@@ -1701,11 +1721,11 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
killed = xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk);
/*
- * Verify PRL is active and if entry is not a leaf pte (base.children conditions),
- * there is a potential need to invalidate the PRL if any PTE (num_live) are dropped.
+ * Verify if any PTE are potentially dropped at non-leaf levels, either from being
+ * killed or the page walk covers the region.
*/
- if (xe_walk->prl && level > 1 && xe_child->num_live &&
- xe_child->base.children && xe_child->base.children[first]) {
+ if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) &&
+ xe_child->level > MAX_HUGEPTE_LEVEL && xe_child->num_live) {
bool covered = xe_pt_covers(addr, next, xe_child->level, &xe_walk->base);
/*
@@ -2178,12 +2198,12 @@ static int op_prepare(struct xe_vm *vm,
err = unbind_op_prepare(tile, pt_update_ops, old);
- if (!err && op->remap.prev) {
+ if (!err && op->remap.prev && !op->remap.skip_prev) {
err = bind_op_prepare(vm, tile, pt_update_ops,
op->remap.prev, false);
pt_update_ops->wait_vm_bookkeep = true;
}
- if (!err && op->remap.next) {
+ if (!err && op->remap.next && !op->remap.skip_next) {
err = bind_op_prepare(vm, tile, pt_update_ops,
op->remap.next, false);
pt_update_ops->wait_vm_bookkeep = true;
@@ -2408,10 +2428,10 @@ static void op_commit(struct xe_vm *vm,
unbind_op_commit(vm, tile, pt_update_ops, old, fence, fence2);
- if (op->remap.prev)
+ if (op->remap.prev && !op->remap.skip_prev)
bind_op_commit(vm, tile, pt_update_ops, op->remap.prev,
fence, fence2, false);
- if (op->remap.next)
+ if (op->remap.next && !op->remap.skip_next)
bind_op_commit(vm, tile, pt_update_ops, op->remap.next,
fence, fence2, false);
break;
diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c
index d61446bf9c19..872217f30375 100644
--- a/drivers/gpu/drm/xe/xe_pxp.c
+++ b/drivers/gpu/drm/xe/xe_pxp.c
@@ -380,6 +380,18 @@ int xe_pxp_init(struct xe_device *xe)
return 0;
}
+ /*
+ * On PTL, older GSC FWs have a bug that can cause them to crash during
+ * PXP invalidation events, which leads to a complete loss of power
+ * management on the media GT. Therefore, we can't use PXP on FWs that
+ * have this bug, which was fixed in PTL GSC build 1396.
+ */
+ if (xe->info.platform == XE_PANTHERLAKE &&
+ gt->uc.gsc.fw.versions.found[XE_UC_FW_VER_RELEASE].build < 1396) {
+ drm_info(&xe->drm, "PXP requires PTL GSC build 1396 or newer\n");
+ return 0;
+ }
+
pxp = drmm_kzalloc(&xe->drm, sizeof(struct xe_pxp), GFP_KERNEL);
if (!pxp) {
err = -ENOMEM;
@@ -512,7 +524,7 @@ static int __exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q)
static int pxp_start(struct xe_pxp *pxp, u8 type)
{
int ret = 0;
- bool restart = false;
+ bool restart;
if (!xe_pxp_is_enabled(pxp))
return -ENODEV;
@@ -541,6 +553,8 @@ wait_for_idle:
msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS)))
return -ETIMEDOUT;
+ restart = false;
+
mutex_lock(&pxp->mutex);
/* If PXP is not already active, turn it on */
@@ -583,6 +597,7 @@ wait_for_idle:
drm_err(&pxp->xe->drm, "PXP termination failed before start\n");
mutex_lock(&pxp->mutex);
pxp->status = XE_PXP_ERROR;
+ complete_all(&pxp->termination);
goto out_unlock;
}
@@ -870,11 +885,6 @@ wait_for_activation:
pxp->key_instance++;
needs_queue_inval = true;
break;
- default:
- drm_err(&pxp->xe->drm, "unexpected state during PXP suspend: %u",
- pxp->status);
- ret = -EIO;
- goto out;
}
/*
@@ -899,7 +909,6 @@ wait_for_activation:
pxp->last_suspend_key_instance = pxp->key_instance;
-out:
return ret;
}
diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
index 2e5c78940b41..a07be161cfa2 100644
--- a/drivers/gpu/drm/xe/xe_reg_sr.c
+++ b/drivers/gpu/drm/xe/xe_reg_sr.c
@@ -98,10 +98,12 @@ int xe_reg_sr_add(struct xe_reg_sr *sr,
*pentry = *e;
ret = xa_err(xa_store(&sr->xa, idx, pentry, GFP_KERNEL));
if (ret)
- goto fail;
+ goto fail_free;
return 0;
+fail_free:
+ kfree(pentry);
fail:
xe_gt_err(gt,
"discarding save-restore reg %04lx (clear: %08x, set: %08x, masked: %s, mcr: %s): ret=%d\n",
diff --git a/drivers/gpu/drm/xe/xe_ring_ops.c b/drivers/gpu/drm/xe/xe_ring_ops.c
index 248620b0901d..53d420d72164 100644
--- a/drivers/gpu/drm/xe/xe_ring_ops.c
+++ b/drivers/gpu/drm/xe/xe_ring_ops.c
@@ -280,6 +280,9 @@ static void __emit_job_gen12_simple(struct xe_sched_job *job, struct xe_lrc *lrc
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
+ /* Don't preempt fence signaling */
+ dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
+
if (job->user_fence.used) {
i = emit_flush_dw(dw, i);
i = emit_store_imm_ppgtt_posted(job->user_fence.addr,
@@ -345,6 +348,9 @@ static void __emit_job_gen12_video(struct xe_sched_job *job, struct xe_lrc *lrc,
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
+ /* Don't preempt fence signaling */
+ dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
+
if (job->user_fence.used) {
i = emit_flush_dw(dw, i);
i = emit_store_imm_ppgtt_posted(job->user_fence.addr,
@@ -397,6 +403,9 @@ static void __emit_job_gen12_render_compute(struct xe_sched_job *job,
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
+ /* Don't preempt fence signaling */
+ dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
+
i = emit_render_cache_flush(job, dw, i);
if (job->user_fence.used)
diff --git a/drivers/gpu/drm/xe/xe_sriov_packet.c b/drivers/gpu/drm/xe/xe_sriov_packet.c
index 968f32496282..2ae9eff2a7c0 100644
--- a/drivers/gpu/drm/xe/xe_sriov_packet.c
+++ b/drivers/gpu/drm/xe/xe_sriov_packet.c
@@ -341,6 +341,8 @@ ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid,
ret = xe_sriov_pf_migration_restore_produce(xe, vfid, *data);
if (ret) {
xe_sriov_packet_free(*data);
+ *data = NULL;
+
return ret;
}
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index ca67d0bdbfac..c6b92d4ea6f4 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -903,7 +903,7 @@ int xe_svm_init(struct xe_vm *vm)
void xe_svm_close(struct xe_vm *vm)
{
xe_assert(vm->xe, xe_vm_is_closed(vm));
- flush_work(&vm->svm.garbage_collector.work);
+ disable_work_sync(&vm->svm.garbage_collector.work);
xe_svm_put_pagemaps(vm);
drm_pagemap_release_owner(&vm->svm.peer);
}
diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c
index eb136390dafd..24d6d9af20d6 100644
--- a/drivers/gpu/drm/xe/xe_sync.c
+++ b/drivers/gpu/drm/xe/xe_sync.c
@@ -146,8 +146,10 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
if (!signal) {
sync->fence = drm_syncobj_fence_get(sync->syncobj);
- if (XE_IOCTL_DBG(xe, !sync->fence))
- return -EINVAL;
+ if (XE_IOCTL_DBG(xe, !sync->fence)) {
+ err = -EINVAL;
+ goto free_sync;
+ }
}
break;
@@ -167,17 +169,21 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
if (signal) {
sync->chain_fence = dma_fence_chain_alloc();
- if (!sync->chain_fence)
- return -ENOMEM;
+ if (!sync->chain_fence) {
+ err = -ENOMEM;
+ goto free_sync;
+ }
} else {
sync->fence = drm_syncobj_fence_get(sync->syncobj);
- if (XE_IOCTL_DBG(xe, !sync->fence))
- return -EINVAL;
+ if (XE_IOCTL_DBG(xe, !sync->fence)) {
+ err = -EINVAL;
+ goto free_sync;
+ }
err = dma_fence_chain_find_seqno(&sync->fence,
sync_in.timeline_value);
if (err)
- return err;
+ goto free_sync;
}
break;
@@ -200,8 +206,10 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence)))
return PTR_ERR(sync->ufence);
sync->ufence_chain_fence = dma_fence_chain_alloc();
- if (!sync->ufence_chain_fence)
- return -ENOMEM;
+ if (!sync->ufence_chain_fence) {
+ err = -ENOMEM;
+ goto free_sync;
+ }
sync->ufence_syncobj = ufence_syncobj;
}
@@ -216,6 +224,10 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef,
sync->timeline_value = sync_in.timeline_value;
return 0;
+
+free_sync:
+ xe_sync_entry_cleanup(sync);
+ return err;
}
ALLOW_ERROR_INJECTION(xe_sync_entry_parse, ERRNO);
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index a82e3a4fb389..ffdbab106a58 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -2554,7 +2554,6 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
if (!err && op->remap.skip_prev) {
op->remap.prev->tile_present =
tile_present;
- op->remap.prev = NULL;
}
}
if (op->remap.next) {
@@ -2564,11 +2563,13 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op)
if (!err && op->remap.skip_next) {
op->remap.next->tile_present =
tile_present;
- op->remap.next = NULL;
}
}
- /* Adjust for partial unbind after removing VMA from VM */
+ /*
+ * Adjust for partial unbind after removing VMA from VM. In case
+ * of unwind we might need to undo this later.
+ */
if (!err) {
op->base.remap.unmap->va->va.addr = op->remap.start;
op->base.remap.unmap->va->va.range = op->remap.range;
@@ -2687,6 +2688,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops,
op->remap.start = xe_vma_start(old);
op->remap.range = xe_vma_size(old);
+ op->remap.old_start = op->remap.start;
+ op->remap.old_range = op->remap.range;
flags |= op->base.remap.unmap->va->flags & XE_VMA_CREATE_MASK;
if (op->base.remap.prev) {
@@ -2835,8 +2838,19 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
xe_svm_notifier_lock(vm);
vma->gpuva.flags &= ~XE_VMA_DESTROYED;
xe_svm_notifier_unlock(vm);
- if (post_commit)
+ if (post_commit) {
+ /*
+ * Restore the old va range, in case of the
+ * prev/next skip optimisation. Otherwise what
+ * we re-insert here could be smaller than the
+ * original range.
+ */
+ op->base.remap.unmap->va->va.addr =
+ op->remap.old_start;
+ op->base.remap.unmap->va->va.range =
+ op->remap.old_range;
xe_vm_insert_vma(vm, vma);
+ }
}
break;
}
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c
index 95bf53cc29e3..b4086129a364 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.c
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
@@ -408,8 +408,15 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
struct xe_device *xe = to_xe_device(dev);
struct xe_file *xef = to_xe_file(file);
struct drm_xe_madvise *args = data;
- struct xe_vmas_in_madvise_range madvise_range = {.addr = args->start,
- .range = args->range, };
+ struct xe_vmas_in_madvise_range madvise_range = {
+ /*
+ * Userspace may pass canonical (sign-extended) addresses.
+ * Strip the sign extension to get the internal non-canonical
+ * form used by the GPUVM, matching xe_vm_bind_ioctl() behavior.
+ */
+ .addr = xe_device_uncanonicalize_addr(xe, args->start),
+ .range = args->range,
+ };
struct xe_madvise_details details;
struct xe_vm *vm;
struct drm_exec exec;
@@ -439,7 +446,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
if (err)
goto unlock_vm;
- err = xe_vm_alloc_madvise_vma(vm, args->start, args->range);
+ err = xe_vm_alloc_madvise_vma(vm, madvise_range.addr, args->range);
if (err)
goto madv_fini;
@@ -453,7 +460,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
madvise_range.num_vmas,
args->atomic.val)) {
err = -EINVAL;
- goto madv_fini;
+ goto free_vmas;
}
}
@@ -482,7 +489,8 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args,
&details);
- err = xe_vm_invalidate_madvise_range(vm, args->start, args->start + args->range);
+ err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr,
+ madvise_range.addr + args->range);
if (madvise_range.has_svm_userptr_vmas)
xe_svm_notifier_unlock(vm);
@@ -490,6 +498,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
err_fini:
if (madvise_range.has_bo_vmas)
drm_exec_fini(&exec);
+free_vmas:
kfree(madvise_range.vmas);
madvise_range.vmas = NULL;
madv_fini:
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 437f64202f3b..e2946e311d7a 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -373,6 +373,10 @@ struct xe_vma_op_remap {
u64 start;
/** @range: range of the VMA unmap */
u64 range;
+ /** @old_start: Original start of the VMA we unmap */
+ u64 old_start;
+ /** @old_range: Original range of the VMA we unmap */
+ u64 old_range;
/** @skip_prev: skip prev rebind */
bool skip_prev;
/** @skip_next: skip next rebind */
diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c
index c7b1bd79ab17..d7e309ad9aba 100644
--- a/drivers/gpu/drm/xe/xe_wa.c
+++ b/drivers/gpu/drm/xe/xe_wa.c
@@ -241,12 +241,14 @@ static const struct xe_rtp_entry_sr gt_was[] = {
{ XE_RTP_NAME("16025250150"),
XE_RTP_RULES(GRAPHICS_VERSION(2001)),
- XE_RTP_ACTIONS(SET(LSN_VC_REG2,
- LSN_LNI_WGT(1) |
- LSN_LNE_WGT(1) |
- LSN_DIM_X_WGT(1) |
- LSN_DIM_Y_WGT(1) |
- LSN_DIM_Z_WGT(1)))
+ XE_RTP_ACTIONS(FIELD_SET(LSN_VC_REG2,
+ LSN_LNI_WGT_MASK | LSN_LNE_WGT_MASK |
+ LSN_DIM_X_WGT_MASK | LSN_DIM_Y_WGT_MASK |
+ LSN_DIM_Z_WGT_MASK,
+ LSN_LNI_WGT(1) | LSN_LNE_WGT(1) |
+ LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) |
+ LSN_DIM_Z_WGT(1)),
+ SET(LSC_CHICKEN_BIT_0_UDW, L3_128B_256B_WRT_DIS))
},
/* Xe2_HPM */
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 174feaca0a6b..c69adaa92bbe 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -47,16 +47,12 @@ struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]);
unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {}
impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> {
- /// Creates a new page table array mapping `NUM_PAGES` GSP pages starting at address `start`.
- fn new(start: DmaAddress) -> Result<Self> {
- let mut ptes = [0u64; NUM_PAGES];
- for (i, pte) in ptes.iter_mut().enumerate() {
- *pte = start
- .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT)
- .ok_or(EOVERFLOW)?;
- }
-
- Ok(Self(ptes))
+ /// Returns the page table entry for `index`, for a mapping starting at `start`.
+ // TODO: Replace with `IoView` projection once available.
+ fn entry(start: DmaAddress, index: usize) -> Result<u64> {
+ start
+ .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT)
+ .ok_or(EOVERFLOW)
}
}
@@ -86,16 +82,22 @@ impl LogBuffer {
NUM_PAGES * GSP_PAGE_SIZE,
GFP_KERNEL | __GFP_ZERO,
)?);
- let ptes = PteArray::<NUM_PAGES>::new(obj.0.dma_handle())?;
+
+ let start_addr = obj.0.dma_handle();
// SAFETY: `obj` has just been created and we are its sole user.
- unsafe {
- // Copy the self-mapping PTE at the expected location.
+ let pte_region = unsafe {
obj.0
- .as_slice_mut(size_of::<u64>(), size_of_val(&ptes))?
- .copy_from_slice(ptes.as_bytes())
+ .as_slice_mut(size_of::<u64>(), NUM_PAGES * size_of::<u64>())?
};
+ // Write values one by one to avoid an on-stack instance of `PteArray`.
+ for (i, chunk) in pte_region.chunks_exact_mut(size_of::<u64>()).enumerate() {
+ let pte_value = PteArray::<0>::entry(start_addr, i)?;
+
+ chunk.copy_from_slice(&pte_value.to_ne_bytes());
+ }
+
Ok(obj)
}
}
@@ -143,14 +145,14 @@ impl Gsp {
// _kgspInitLibosLoggingStructures (allocates memory for buffers)
// kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
dma_write!(
- libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)
- )?;
+ libos, [0]?, LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)
+ );
dma_write!(
- libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
- )?;
- dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
- dma_write!(rmargs[0].inner = fw::GspArgumentsCached::new(cmdq))?;
- dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?;
+ libos, [1]?, LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
+ );
+ dma_write!(libos, [2]?, LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0));
+ dma_write!(rmargs, [0]?.inner, fw::GspArgumentsCached::new(cmdq));
+ dma_write!(libos, [3]?, LibosMemoryRegionInitArgument::new("RMARGS", rmargs));
},
}))
})
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index be427fe26a58..94833f7996e8 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -157,7 +157,7 @@ impl super::Gsp {
let wpr_meta =
CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
- dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?;
+ dma_write!(wpr_meta, [0]?, GspFwWprMeta::new(&gsp_fw, &fb_layout));
self.cmdq
.send_command(bar, commands::SetSystemInfo::new(pdev))?;
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 46819a82a51a..03a4f3599849 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -2,11 +2,7 @@
use core::{
cmp,
- mem,
- sync::atomic::{
- fence,
- Ordering, //
- }, //
+ mem, //
};
use kernel::{
@@ -146,30 +142,36 @@ static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE);
#[repr(C)]
// There is no struct defined for this in the open-gpu-kernel-source headers.
// Instead it is defined by code in `GspMsgQueuesInit()`.
-struct Msgq {
+// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
+pub(super) struct Msgq {
/// Header for sending messages, including the write pointer.
- tx: MsgqTxHeader,
+ pub(super) tx: MsgqTxHeader,
/// Header for receiving messages, including the read pointer.
- rx: MsgqRxHeader,
+ pub(super) rx: MsgqRxHeader,
/// The message queue proper.
msgq: MsgqData,
}
/// Structure shared between the driver and the GSP and containing the command and message queues.
#[repr(C)]
-struct GspMem {
+// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
+pub(super) struct GspMem {
/// Self-mapping page table entries.
- ptes: PteArray<{ GSP_PAGE_SIZE / size_of::<u64>() }>,
+ ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>,
/// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the
/// write and read pointers that the CPU updates.
///
/// This member is read-only for the GSP.
- cpuq: Msgq,
+ pub(super) cpuq: Msgq,
/// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the
/// write and read pointers that the GSP updates.
///
/// This member is read-only for the driver.
- gspq: Msgq,
+ pub(super) gspq: Msgq,
+}
+
+impl GspMem {
+ const PTE_ARRAY_SIZE: usize = GSP_PAGE_SIZE / size_of::<u64>();
}
// SAFETY: These structs don't meet the no-padding requirements of AsBytes but
@@ -201,9 +203,19 @@ impl DmaGspMem {
let gsp_mem =
CoherentAllocation::<GspMem>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
- dma_write!(gsp_mem[0].ptes = PteArray::new(gsp_mem.dma_handle())?)?;
- dma_write!(gsp_mem[0].cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES))?;
- dma_write!(gsp_mem[0].cpuq.rx = MsgqRxHeader::new())?;
+
+ let start = gsp_mem.dma_handle();
+ // Write values one by one to avoid an on-stack instance of `PteArray`.
+ for i in 0..GspMem::PTE_ARRAY_SIZE {
+ dma_write!(gsp_mem, [0]?.ptes.0[i], PteArray::<0>::entry(start, i)?);
+ }
+
+ dma_write!(
+ gsp_mem,
+ [0]?.cpuq.tx,
+ MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES)
+ );
+ dma_write!(gsp_mem, [0]?.cpuq.rx, MsgqRxHeader::new());
Ok(Self(gsp_mem))
}
@@ -317,12 +329,7 @@ impl DmaGspMem {
//
// - The returned value is between `0` and `MSGQ_NUM_PAGES`.
fn gsp_write_ptr(&self) -> u32 {
- let gsp_mem = self.0.start_ptr();
-
- // SAFETY:
- // - The 'CoherentAllocation' contains at least one object.
- // - By the invariants of `CoherentAllocation` the pointer is valid.
- (unsafe { (*gsp_mem).gspq.tx.write_ptr() } % MSGQ_NUM_PAGES)
+ super::fw::gsp_mem::gsp_write_ptr(&self.0)
}
// Returns the index of the memory page the GSP will read the next command from.
@@ -331,12 +338,7 @@ impl DmaGspMem {
//
// - The returned value is between `0` and `MSGQ_NUM_PAGES`.
fn gsp_read_ptr(&self) -> u32 {
- let gsp_mem = self.0.start_ptr();
-
- // SAFETY:
- // - The 'CoherentAllocation' contains at least one object.
- // - By the invariants of `CoherentAllocation` the pointer is valid.
- (unsafe { (*gsp_mem).gspq.rx.read_ptr() } % MSGQ_NUM_PAGES)
+ super::fw::gsp_mem::gsp_read_ptr(&self.0)
}
// Returns the index of the memory page the CPU can read the next message from.
@@ -345,27 +347,12 @@ impl DmaGspMem {
//
// - The returned value is between `0` and `MSGQ_NUM_PAGES`.
fn cpu_read_ptr(&self) -> u32 {
- let gsp_mem = self.0.start_ptr();
-
- // SAFETY:
- // - The ['CoherentAllocation'] contains at least one object.
- // - By the invariants of CoherentAllocation the pointer is valid.
- (unsafe { (*gsp_mem).cpuq.rx.read_ptr() } % MSGQ_NUM_PAGES)
+ super::fw::gsp_mem::cpu_read_ptr(&self.0)
}
// Informs the GSP that it can send `elem_count` new pages into the message queue.
fn advance_cpu_read_ptr(&mut self, elem_count: u32) {
- let rptr = self.cpu_read_ptr().wrapping_add(elem_count) % MSGQ_NUM_PAGES;
-
- // Ensure read pointer is properly ordered.
- fence(Ordering::SeqCst);
-
- let gsp_mem = self.0.start_ptr_mut();
-
- // SAFETY:
- // - The 'CoherentAllocation' contains at least one object.
- // - By the invariants of `CoherentAllocation` the pointer is valid.
- unsafe { (*gsp_mem).cpuq.rx.set_read_ptr(rptr) };
+ super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count)
}
// Returns the index of the memory page the CPU can write the next command to.
@@ -374,26 +361,12 @@ impl DmaGspMem {
//
// - The returned value is between `0` and `MSGQ_NUM_PAGES`.
fn cpu_write_ptr(&self) -> u32 {
- let gsp_mem = self.0.start_ptr();
-
- // SAFETY:
- // - The 'CoherentAllocation' contains at least one object.
- // - By the invariants of `CoherentAllocation` the pointer is valid.
- (unsafe { (*gsp_mem).cpuq.tx.write_ptr() } % MSGQ_NUM_PAGES)
+ super::fw::gsp_mem::cpu_write_ptr(&self.0)
}
// Informs the GSP that it can process `elem_count` new pages from the command queue.
fn advance_cpu_write_ptr(&mut self, elem_count: u32) {
- let wptr = self.cpu_write_ptr().wrapping_add(elem_count) & MSGQ_NUM_PAGES;
- let gsp_mem = self.0.start_ptr_mut();
-
- // SAFETY:
- // - The 'CoherentAllocation' contains at least one object.
- // - By the invariants of `CoherentAllocation` the pointer is valid.
- unsafe { (*gsp_mem).cpuq.tx.set_write_ptr(wptr) };
-
- // Ensure all command data is visible before triggering the GSP read.
- fence(Ordering::SeqCst);
+ super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count)
}
}
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 83ff91614e36..040b30ec3089 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -40,6 +40,75 @@ use crate::{
},
};
+// TODO: Replace with `IoView` projections once available; the `unwrap()` calls go away once we
+// switch to the new `dma::Coherent` API.
+pub(super) mod gsp_mem {
+ use core::sync::atomic::{
+ fence,
+ Ordering, //
+ };
+
+ use kernel::{
+ dma::CoherentAllocation,
+ dma_read,
+ dma_write,
+ prelude::*, //
+ };
+
+ use crate::gsp::cmdq::{
+ GspMem,
+ MSGQ_NUM_PAGES, //
+ };
+
+ pub(in crate::gsp) fn gsp_write_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
+ // PANIC: A `dma::CoherentAllocation` always contains at least one element.
+ || -> Result<u32> { Ok(dma_read!(qs, [0]?.gspq.tx.0.writePtr) % MSGQ_NUM_PAGES) }().unwrap()
+ }
+
+ pub(in crate::gsp) fn gsp_read_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
+ // PANIC: A `dma::CoherentAllocation` always contains at least one element.
+ || -> Result<u32> { Ok(dma_read!(qs, [0]?.gspq.rx.0.readPtr) % MSGQ_NUM_PAGES) }().unwrap()
+ }
+
+ pub(in crate::gsp) fn cpu_read_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
+ // PANIC: A `dma::CoherentAllocation` always contains at least one element.
+ || -> Result<u32> { Ok(dma_read!(qs, [0]?.cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES) }().unwrap()
+ }
+
+ pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &CoherentAllocation<GspMem>, count: u32) {
+ let rptr = cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES;
+
+ // Ensure read pointer is properly ordered.
+ fence(Ordering::SeqCst);
+
+ // PANIC: A `dma::CoherentAllocation` always contains at least one element.
+ || -> Result {
+ dma_write!(qs, [0]?.cpuq.rx.0.readPtr, rptr);
+ Ok(())
+ }()
+ .unwrap()
+ }
+
+ pub(in crate::gsp) fn cpu_write_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
+ // PANIC: A `dma::CoherentAllocation` always contains at least one element.
+ || -> Result<u32> { Ok(dma_read!(qs, [0]?.cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES) }().unwrap()
+ }
+
+ pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &CoherentAllocation<GspMem>, count: u32) {
+ let wptr = cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES;
+
+ // PANIC: A `dma::CoherentAllocation` always contains at least one element.
+ || -> Result {
+ dma_write!(qs, [0]?.cpuq.tx.0.writePtr, wptr);
+ Ok(())
+ }()
+ .unwrap();
+
+ // Ensure all command data is visible before triggering the GSP read.
+ fence(Ordering::SeqCst);
+ }
+}
+
/// Empty type to group methods related to heap parameters for running the GSP firmware.
enum GspFwHeapParams {}
@@ -708,22 +777,6 @@ impl MsgqTxHeader {
entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(),
})
}
-
- /// Returns the value of the write pointer for this queue.
- pub(crate) fn write_ptr(&self) -> u32 {
- let ptr = core::ptr::from_ref(&self.0.writePtr);
-
- // SAFETY: `ptr` is a valid pointer to a `u32`.
- unsafe { ptr.read_volatile() }
- }
-
- /// Sets the value of the write pointer for this queue.
- pub(crate) fn set_write_ptr(&mut self, val: u32) {
- let ptr = core::ptr::from_mut(&mut self.0.writePtr);
-
- // SAFETY: `ptr` is a valid pointer to a `u32`.
- unsafe { ptr.write_volatile(val) }
- }
}
// SAFETY: Padding is explicit and does not contain uninitialized data.
@@ -739,22 +792,6 @@ impl MsgqRxHeader {
pub(crate) fn new() -> Self {
Self(Default::default())
}
-
- /// Returns the value of the read pointer for this queue.
- pub(crate) fn read_ptr(&self) -> u32 {
- let ptr = core::ptr::from_ref(&self.0.readPtr);
-
- // SAFETY: `ptr` is a valid pointer to a `u32`.
- unsafe { ptr.read_volatile() }
- }
-
- /// Sets the value of the read pointer for this queue.
- pub(crate) fn set_read_ptr(&mut self, val: u32) {
- let ptr = core::ptr::from_mut(&mut self.0.readPtr);
-
- // SAFETY: `ptr` is a valid pointer to a `u32`.
- unsafe { ptr.write_volatile(val) }
- }
}
// SAFETY: Padding is explicit and does not contain uninitialized data.
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index 1d9f955573aa..4b81cebdc335 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -413,7 +413,8 @@ static void sfh_init_work(struct work_struct *work)
rc = amd_sfh_hid_client_init(mp2);
if (rc) {
amd_sfh_clear_intr(mp2);
- dev_err(&pdev->dev, "amd_sfh_hid_client_init failed err %d\n", rc);
+ if (rc != -EOPNOTSUPP)
+ dev_err(&pdev->dev, "amd_sfh_hid_client_init failed err %d\n", rc);
return;
}
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
index f3d15994ca1e..50c7b45c59e3 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -444,6 +444,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
(u64)(long)ctx,
true); /* prevent infinite recursions */
+ if (ret > size)
+ ret = size;
if (ret > 0)
memcpy(buf, dma_data, ret);
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index b949b767cf08..fc5897a6bb53 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -365,6 +365,9 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
{ "A3R" },
{ "hfd.cn" },
{ "WKB603" },
+ { "TH87" }, /* EPOMAKER TH87 BT mode */
+ { "HFD Epomaker TH87" }, /* EPOMAKER TH87 USB mode */
+ { "2.4G Wireless Receiver" }, /* EPOMAKER TH87 dongle */
};
static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
@@ -686,9 +689,7 @@ static const __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev,
"fixing up Magic Keyboard battery report descriptor\n");
*rsize = *rsize - 1;
- rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ rdesc = rdesc + 1;
rdesc[0] = 0x05;
rdesc[1] = 0x01;
diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
index a1db3b3d0667..0fdc0968b9ef 100644
--- a/drivers/hid/hid-appletb-kbd.c
+++ b/drivers/hid/hid-appletb-kbd.c
@@ -476,7 +476,7 @@ static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
return 0;
}
-static int appletb_kbd_reset_resume(struct hid_device *hdev)
+static int appletb_kbd_resume(struct hid_device *hdev)
{
struct appletb_kbd *kbd = hid_get_drvdata(hdev);
@@ -500,7 +500,8 @@ static struct hid_driver appletb_kbd_hid_driver = {
.event = appletb_kbd_hid_event,
.input_configured = appletb_kbd_input_configured,
.suspend = pm_ptr(appletb_kbd_suspend),
- .reset_resume = pm_ptr(appletb_kbd_reset_resume),
+ .resume = pm_ptr(appletb_kbd_resume),
+ .reset_resume = pm_ptr(appletb_kbd_resume),
.driver.dev_groups = appletb_kbd_groups,
};
module_hid_driver(appletb_kbd_hid_driver);
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 8ffcd12038e8..bc93b27f9b13 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1399,14 +1399,21 @@ static const __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*/
if (*rsize == rsize_orig &&
rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
- *rsize = rsize_orig + 1;
- rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ __u8 *new_rdesc;
+
+ new_rdesc = devm_kzalloc(&hdev->dev, rsize_orig + 1,
+ GFP_KERNEL);
+ if (!new_rdesc)
+ return rdesc;
hid_info(hdev, "Fixing up %s keyb report descriptor\n",
drvdata->quirks & QUIRK_T100CHI ?
"T100CHI" : "T90CHI");
+
+ memcpy(new_rdesc, rdesc, rsize_orig);
+ *rsize = rsize_orig + 1;
+ rdesc = new_rdesc;
+
memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
rdesc[offs] = 0x19;
rdesc[offs + 1] = 0x00;
@@ -1491,6 +1498,12 @@ static const struct hid_device_id asus_devices[] = {
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_XGM_2022),
+ },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_XGM_2023),
+ },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
QUIRK_ROG_CLAYMORE_II_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
diff --git a/drivers/hid/hid-cmedia.c b/drivers/hid/hid-cmedia.c
index 6bc50df9b3e1..7b3dd4197875 100644
--- a/drivers/hid/hid-cmedia.c
+++ b/drivers/hid/hid-cmedia.c
@@ -99,7 +99,7 @@ static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
{
struct cmhid *cm = hid_get_drvdata(hid);
- if (len != CM6533_JD_RAWEV_LEN)
+ if (len != CM6533_JD_RAWEV_LEN || !(hid->claimed & HID_CLAIMED_INPUT))
goto out;
if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
goto out;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 840a60113868..833df14ef68f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2057,9 +2057,10 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
rsize = max_buffer_size;
if (csize < rsize) {
- dbg_hid("report %d is too short, (%d < %d)\n", report->id,
- csize, rsize);
- memset(cdata + csize, 0, rsize - csize);
+ hid_warn_ratelimited(hid, "Event data for report %d was too short (%d vs %d)\n",
+ report->id, rsize, csize);
+ ret = -EINVAL;
+ goto out;
}
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
diff --git a/drivers/hid/hid-creative-sb0540.c b/drivers/hid/hid-creative-sb0540.c
index b4c8e7a5d3e0..dfd6add353d1 100644
--- a/drivers/hid/hid-creative-sb0540.c
+++ b/drivers/hid/hid-creative-sb0540.c
@@ -153,7 +153,7 @@ static int creative_sb0540_raw_event(struct hid_device *hid,
u64 code, main_code;
int key;
- if (len != 6)
+ if (len != 6 || !(hid->claimed & HID_CLAIMED_INPUT))
return 0;
/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index f20dc46fd8eb..f44e6e708404 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -990,6 +990,9 @@ static const struct hid_usage_entry hid_usage_table[] = {
{ 0x0c, 0x01c9, "ALContactSync" },
{ 0x0c, 0x01ca, "ALNavigation" },
{ 0x0c, 0x01cb, "ALContextawareDesktopAssistant" },
+ { 0x0c, 0x01cc, "ALActionOnSelection" },
+ { 0x0c, 0x01cd, "ALContextualInsertion" },
+ { 0x0c, 0x01ce, "ALContextualQuery" },
{ 0x0c, 0x0200, "GenericGUIApplicationControls" },
{ 0x0c, 0x0201, "ACNew" },
{ 0x0c, 0x0202, "ACOpen" },
@@ -3375,6 +3378,9 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
[KEY_BRIGHTNESS_MAX] = "BrightnessMax",
[KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
+ [KEY_ACTION_ON_SELECTION] = "ActionOnSelection",
+ [KEY_CONTEXTUAL_INSERT] = "ContextualInsert",
+ [KEY_CONTEXTUAL_QUERY] = "ContextualQuery",
[KEY_KBDINPUTASSIST_PREV] = "KbdInputAssistPrev",
[KEY_KBDINPUTASSIST_NEXT] = "KbdInputAssistNext",
[KEY_KBDINPUTASSIST_PREVGROUP] = "KbdInputAssistPrevGroup",
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3e299a30dcde..c1e4a6ce9631 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -22,6 +22,9 @@
#define USB_DEVICE_ID_3M2256 0x0502
#define USB_DEVICE_ID_3M3266 0x0506
+#define USB_VENDOR_ID_8BITDO 0x2dc8
+#define USB_DEVICE_ID_8BITDO_PRO_3 0x6009
+
#define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a
@@ -229,6 +232,8 @@
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c
#define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
+#define USB_DEVICE_ID_ASUSTEK_XGM_2022 0x1970
+#define USB_DEVICE_ID_ASUSTEK_XGM_2023 0x1a9a
#define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
@@ -453,8 +458,6 @@
#define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401
#define USB_DEVICE_ID_HP_X2 0x074d
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
-#define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544
-#define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
#define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM 0x2F81
#define USB_VENDOR_ID_ELECOM 0x056e
@@ -1471,6 +1474,10 @@
#define USB_VENDOR_ID_VTL 0x0306
#define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f
+#define USB_VENDOR_ID_VXE 0x3554
+#define USB_DEVICE_ID_VXE_DRAGONFLY_R1_PRO_DONGLE 0xf58a
+#define USB_DEVICE_ID_VXE_DRAGONFLY_R1_PRO_WIRED 0xf58c
+
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0x00BD
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d5308adb2894..e824c793f669 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -354,6 +354,7 @@ static enum power_supply_property hidinput_battery_props[] = {
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */
#define HID_BATTERY_QUIRK_AVOID_QUERY (1 << 3) /* do not query the battery */
+#define HID_BATTERY_QUIRK_DYNAMIC (1 << 4) /* report present only after life signs */
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -386,10 +387,6 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
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_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
@@ -402,8 +399,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
* Elan HID touchscreens seem to all report a non present battery,
* set HID_BATTERY_QUIRK_IGNORE for all Elan I2C and USB HID devices.
*/
- { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC },
{}
};
@@ -460,11 +457,14 @@ static int hidinput_get_battery_property(struct power_supply *psy,
int ret = 0;
switch (prop) {
- case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 1;
break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = dev->battery_present;
+ break;
+
case POWER_SUPPLY_PROP_CAPACITY:
if (dev->battery_status != HID_BATTERY_REPORTED &&
!dev->battery_avoid_query) {
@@ -577,6 +577,8 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY)
dev->battery_avoid_query = true;
+ dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
+
dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
if (IS_ERR(dev->battery)) {
error = PTR_ERR(dev->battery);
@@ -632,6 +634,7 @@ static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
return;
if (hidinput_update_battery_charge_status(dev, usage, value)) {
+ dev->battery_present = true;
power_supply_changed(dev->battery);
return;
}
@@ -647,6 +650,7 @@ static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
if (dev->battery_status != HID_BATTERY_REPORTED ||
capacity != dev->battery_capacity ||
ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) {
+ dev->battery_present = true;
dev->battery_capacity = capacity;
dev->battery_status = HID_BATTERY_REPORTED;
dev->battery_ratelimit_time =
@@ -1223,6 +1227,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1bc: map_key_clear(KEY_MESSENGER); break;
case 0x1bd: map_key_clear(KEY_INFO); break;
case 0x1cb: map_key_clear(KEY_ASSISTANT); break;
+ case 0x1cc: map_key_clear(KEY_ACTION_ON_SELECTION); break;
+ case 0x1cd: map_key_clear(KEY_CONTEXTUAL_INSERT); break;
+ case 0x1ce: map_key_clear(KEY_CONTEXTUAL_QUERY); break;
case 0x201: map_key_clear(KEY_NEW); break;
case 0x202: map_key_clear(KEY_OPEN); break;
case 0x203: map_key_clear(KEY_CLOSE); break;
diff --git a/drivers/hid/hid-kysona.c b/drivers/hid/hid-kysona.c
index 09bfe30d02cb..ccbd8380064e 100644
--- a/drivers/hid/hid-kysona.c
+++ b/drivers/hid/hid-kysona.c
@@ -272,6 +272,8 @@ static void kysona_remove(struct hid_device *hdev)
static const struct hid_device_id kysona_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_WIRED) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VXE, USB_DEVICE_ID_VXE_DRAGONFLY_R1_PRO_DONGLE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VXE, USB_DEVICE_ID_VXE_DRAGONFLY_R1_PRO_WIRED) },
{ }
};
MODULE_DEVICE_TABLE(hid, kysona_devices);
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index d40932809ce1..d1dea7297712 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4487,10 +4487,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!ret)
ret = hidpp_ff_init(hidpp, &data);
- if (ret)
+ if (ret) {
hid_warn(hidpp->hid_dev,
"Unable to initialize force feedback support, errno %d\n",
ret);
+ ret = 0;
+ }
}
/*
@@ -4668,6 +4670,8 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
{ /* Slim Solar+ K980 Keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
+ { /* MX Master 4 mouse over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb042) },
{}
};
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 91f621ceb924..9eadf3252d0d 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -990,13 +990,11 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*/
if ((is_usb_magicmouse2(hdev->vendor, hdev->product) ||
is_usb_magictrackpad2(hdev->vendor, hdev->product)) &&
- *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
+ *rsize >= 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
hid_info(hdev,
"fixing up magicmouse battery report descriptor\n");
*rsize = *rsize - 1;
- rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ rdesc = rdesc + 1;
rdesc[0] = 0x05;
rdesc[1] = 0x01;
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 33603b019f97..ef3b5c77c38e 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -353,6 +353,8 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
usleep_range(90, 100);
retries++;
} else {
+ usleep_range(980, 1000);
+ mcp_cancel_last_cmd(mcp);
return ret;
}
} else {
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 7daa8f6d8187..e82a3c4e5b44 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
#define MT_QUIRK_YOGABOOK9I BIT(24)
+#define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -214,6 +215,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016
#define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017
#define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU 0x0018
+#define MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE 0x0019
/* vendor specific classes */
#define MT_CLS_3M 0x0101
@@ -233,6 +235,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_SMART_TECH 0x0113
#define MT_CLS_APPLE_TOUCHBAR 0x0114
#define MT_CLS_YOGABOOK9I 0x0115
+#define MT_CLS_EGALAX_P80H84 0x0116
#define MT_CLS_SIS 0x0457
#define MT_DEFAULT_MAXCONTACT 10
@@ -334,6 +337,15 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_WIN8_PTP_BUTTONS,
.export_all_inputs = true },
+ { .name = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_HOVERING |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_STICKY_FINGERS |
+ MT_QUIRK_WIN8_PTP_BUTTONS |
+ MT_QUIRK_KEEP_LATENCY_ON_CLOSE,
+ .export_all_inputs = true },
/*
* vendor specific classes
@@ -438,6 +450,11 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_YOGABOOK9I,
.export_all_inputs = true
},
+ { .name = MT_CLS_EGALAX_P80H84,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_CONTACT_CNT_ACCURATE,
+ },
{ }
};
@@ -509,12 +526,19 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
dev_warn(&hdev->dev, "failed to fetch feature %d\n",
report->id);
} else {
+ /* The report ID in the request and the response should match */
+ if (report->id != buf[0]) {
+ hid_err(hdev, "Returned feature report did not match the request\n");
+ goto free;
+ }
+
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
size, 0);
if (ret)
dev_warn(&hdev->dev, "failed to report feature\n");
}
+free:
kfree(buf);
}
@@ -849,7 +873,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if ((cls->name == MT_CLS_WIN_8 ||
cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT ||
cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU ||
- cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP) &&
+ cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP ||
+ cls->name == MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE) &&
(field->application == HID_DG_TOUCHPAD ||
field->application == HID_DG_TOUCHSCREEN))
app->quirks |= MT_QUIRK_CONFIDENCE;
@@ -1762,7 +1787,8 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
int ret;
if (td->is_haptic_touchpad && (td->mtclass.name == MT_CLS_WIN_8 ||
- td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT)) {
+ td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT ||
+ td->mtclass.name == MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE)) {
if (hid_haptic_input_configured(hdev, td->haptic, hi) == 0)
td->is_haptic_touchpad = false;
} else {
@@ -2075,7 +2101,12 @@ static void mt_on_hid_hw_open(struct hid_device *hdev)
static void mt_on_hid_hw_close(struct hid_device *hdev)
{
- mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE);
+ struct mt_device *td = hid_get_drvdata(hdev);
+
+ if (td->mtclass.quirks & MT_QUIRK_KEEP_LATENCY_ON_CLOSE)
+ mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE);
+ else
+ mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE);
}
/*
@@ -2215,8 +2246,9 @@ static const struct hid_device_id mt_devices[] = {
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000) },
- { .driver_data = MT_CLS_EGALAX,
- MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ { .driver_data = MT_CLS_EGALAX_P80H84,
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
/* Elan devices */
@@ -2461,6 +2493,14 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
+ /* Uniwill touchpads */
+ { .driver_data = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_PIXART, 0x0255) },
+ { .driver_data = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_PIXART, 0x0274) },
+
/* VTL panels */
{ .driver_data = MT_CLS_VTL,
MT_USB_DEVICE(USB_VENDOR_ID_VTL,
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index edc4339adb50..02f7db5c1056 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -25,6 +25,7 @@
*/
static const struct hid_device_id hid_quirks[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_8BITDO, USB_DEVICE_ID_8BITDO_PRO_3), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ADATA_XPG, USB_VENDOR_ID_ADATA_XPG_WL_GAMING_MOUSE), HID_QUIRK_ALWAYS_POLL },
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index fd0ea52f7cba..d6fff53d4ee7 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -257,6 +257,7 @@ int roccat_report_event(int minor, u8 const *data)
if (!new_value)
return -ENOMEM;
+ mutex_lock(&device->readers_lock);
mutex_lock(&device->cbuf_lock);
report = &device->cbuf[device->cbuf_end];
@@ -279,6 +280,7 @@ int roccat_report_event(int minor, u8 const *data)
}
mutex_unlock(&device->cbuf_lock);
+ mutex_unlock(&device->readers_lock);
wake_up_interruptible(&device->wait);
return 0;
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 3bdb26f45592..1aae80f848f5 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -114,7 +114,7 @@ static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
unsigned key;
unsigned short index;
- if (report->id == data[0]) {
+ if (report->id == data[0] && (hdev->claimed & HID_CLAIMED_INPUT)) {
/* break keys */
for (index = 0; index < 4; index++) {
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
index fa5d68c36313..27389971b96c 100644
--- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -39,6 +39,8 @@
#define PCI_DEVICE_ID_INTEL_ISH_PTL_H 0xE345
#define PCI_DEVICE_ID_INTEL_ISH_PTL_P 0xE445
#define PCI_DEVICE_ID_INTEL_ISH_WCL 0x4D45
+#define PCI_DEVICE_ID_INTEL_ISH_NVL_H 0xD354
+#define PCI_DEVICE_ID_INTEL_ISH_NVL_S 0x6E78
#define REVISION_ID_CHT_A0 0x6
#define REVISION_ID_CHT_Ax_SI 0x0
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 1612e8cb23f0..ed3405c05e73 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -28,11 +28,15 @@ enum ishtp_driver_data_index {
ISHTP_DRIVER_DATA_LNL_M,
ISHTP_DRIVER_DATA_PTL,
ISHTP_DRIVER_DATA_WCL,
+ ISHTP_DRIVER_DATA_NVL_H,
+ ISHTP_DRIVER_DATA_NVL_S,
};
#define ISH_FW_GEN_LNL_M "lnlm"
#define ISH_FW_GEN_PTL "ptl"
#define ISH_FW_GEN_WCL "wcl"
+#define ISH_FW_GEN_NVL_H "nvlh"
+#define ISH_FW_GEN_NVL_S "nvls"
#define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
#define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
@@ -47,6 +51,12 @@ static struct ishtp_driver_data ishtp_driver_data[] = {
[ISHTP_DRIVER_DATA_WCL] = {
.fw_generation = ISH_FW_GEN_WCL,
},
+ [ISHTP_DRIVER_DATA_NVL_H] = {
+ .fw_generation = ISH_FW_GEN_NVL_H,
+ },
+ [ISHTP_DRIVER_DATA_NVL_S] = {
+ .fw_generation = ISH_FW_GEN_NVL_S,
+ },
};
static const struct pci_device_id ish_pci_tbl[] = {
@@ -76,6 +86,8 @@ static const struct pci_device_id ish_pci_tbl[] = {
{PCI_DEVICE_DATA(INTEL, ISH_PTL_H, ISHTP_DRIVER_DATA_PTL)},
{PCI_DEVICE_DATA(INTEL, ISH_PTL_P, ISHTP_DRIVER_DATA_PTL)},
{PCI_DEVICE_DATA(INTEL, ISH_WCL, ISHTP_DRIVER_DATA_WCL)},
+ {PCI_DEVICE_DATA(INTEL, ISH_NVL_H, ISHTP_DRIVER_DATA_NVL_H)},
+ {PCI_DEVICE_DATA(INTEL, ISH_NVL_S, ISHTP_DRIVER_DATA_NVL_S)},
{}
};
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
index f178017352ba..46d3e9a01999 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
@@ -26,6 +26,11 @@ static struct quicki2c_ddata ptl_ddata = {
.max_interrupt_delay = MAX_RX_INTERRUPT_DELAY,
};
+static struct quicki2c_ddata nvl_ddata = {
+ .max_detect_size = MAX_RX_DETECT_SIZE_NVL,
+ .max_interrupt_delay = MAX_RX_INTERRUPT_DELAY,
+};
+
/* THC QuickI2C ACPI method to get device properties */
/* HIDI2C device method */
static guid_t i2c_hid_guid =
@@ -1032,6 +1037,8 @@ static const struct pci_device_id quicki2c_pci_tbl[] = {
{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
{ PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
{ PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
+ { PCI_DEVICE_DATA(INTEL, THC_NVL_H_DEVICE_ID_I2C_PORT1, &nvl_ddata) },
+ { PCI_DEVICE_DATA(INTEL, THC_NVL_H_DEVICE_ID_I2C_PORT2, &nvl_ddata) },
{ }
};
MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl);
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
index 33a1e3db1cb2..61dbdece59a1 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
@@ -15,6 +15,8 @@
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT2 0xE44A
#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_I2C_PORT1 0x4D48
#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_I2C_PORT2 0x4D4A
+#define PCI_DEVICE_ID_INTEL_THC_NVL_H_DEVICE_ID_I2C_PORT1 0xD348
+#define PCI_DEVICE_ID_INTEL_THC_NVL_H_DEVICE_ID_I2C_PORT2 0xD34A
/* Packet size value, the unit is 16 bytes */
#define MAX_PACKET_SIZE_VALUE_LNL 256
@@ -40,6 +42,8 @@
/* PTL Max packet size detection capability is 255 Bytes */
#define MAX_RX_DETECT_SIZE_PTL 255
+/* NVL Max packet size detection capability is 64K Bytes */
+#define MAX_RX_DETECT_SIZE_NVL 65535
/* Max interrupt delay capability is 2.56ms */
#define MAX_RX_INTERRUPT_DELAY 256
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
index f9fcb398673b..8075992e8732 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
@@ -127,6 +127,7 @@ int quicki2c_hid_probe(struct quicki2c_device *qcdev)
hid->product = le16_to_cpu(qcdev->dev_desc.product_id);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quicki2c-hid",
hid->vendor, hid->product);
+ strscpy(hid->phys, dev_name(qcdev->dev), sizeof(hid->phys));
ret = hid_add_device(hid);
if (ret) {
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
index ad6bd59963b2..b6a69995692c 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
@@ -37,6 +37,10 @@ struct quickspi_driver_data arl = {
.max_packet_size_value = MAX_PACKET_SIZE_VALUE_MTL,
};
+struct quickspi_driver_data nvl = {
+ .max_packet_size_value = MAX_PACKET_SIZE_VALUE_LNL,
+};
+
/* THC QuickSPI ACPI method to get device properties */
/* HIDSPI Method: {6e2ac436-0fcf-41af-a265-b32a220dcfab} */
static guid_t hidspi_guid =
@@ -982,6 +986,8 @@ static const struct pci_device_id quickspi_pci_tbl[] = {
{PCI_DEVICE_DATA(INTEL, THC_WCL_DEVICE_ID_SPI_PORT2, &ptl), },
{PCI_DEVICE_DATA(INTEL, THC_ARL_DEVICE_ID_SPI_PORT1, &arl), },
{PCI_DEVICE_DATA(INTEL, THC_ARL_DEVICE_ID_SPI_PORT2, &arl), },
+ {PCI_DEVICE_DATA(INTEL, THC_NVL_H_DEVICE_ID_SPI_PORT1, &nvl), },
+ {PCI_DEVICE_DATA(INTEL, THC_NVL_H_DEVICE_ID_SPI_PORT2, &nvl), },
{}
};
MODULE_DEVICE_TABLE(pci, quickspi_pci_tbl);
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
index c30e1a42eb09..bf5e18f5a5f4 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-dev.h
@@ -23,6 +23,8 @@
#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_SPI_PORT2 0x4D4B
#define PCI_DEVICE_ID_INTEL_THC_ARL_DEVICE_ID_SPI_PORT1 0x7749
#define PCI_DEVICE_ID_INTEL_THC_ARL_DEVICE_ID_SPI_PORT2 0x774B
+#define PCI_DEVICE_ID_INTEL_THC_NVL_H_DEVICE_ID_SPI_PORT1 0xD349
+#define PCI_DEVICE_ID_INTEL_THC_NVL_H_DEVICE_ID_SPI_PORT2 0xD34B
/* HIDSPI special ACPI parameters DSM methods */
#define ACPI_QUICKSPI_REVISION_NUM 2
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
index 82c72bfa2795..91d5807b4a83 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
@@ -118,6 +118,7 @@ int quickspi_hid_probe(struct quickspi_device *qsdev)
hid->product = le16_to_cpu(qsdev->dev_desc.product_id);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quickspi-hid",
hid->vendor, hid->product);
+ strscpy(hid->phys, dev_name(qsdev->dev), sizeof(hid->phys));
ret = hid_add_device(hid);
if (ret) {
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index fdcf03408f47..fbf3dbc92e66 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -1452,10 +1452,13 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
hid_warn(pidff->hid, "unknown ramp effect layout\n");
if (PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
- if (test_and_clear_bit(FF_SPRING, dev->ffbit) ||
- test_and_clear_bit(FF_DAMPER, dev->ffbit) ||
- test_and_clear_bit(FF_FRICTION, dev->ffbit) ||
- test_and_clear_bit(FF_INERTIA, dev->ffbit))
+ bool test = false;
+
+ test |= test_and_clear_bit(FF_SPRING, dev->ffbit);
+ test |= test_and_clear_bit(FF_DAMPER, dev->ffbit);
+ test |= test_and_clear_bit(FF_FRICTION, dev->ffbit);
+ test |= test_and_clear_bit(FF_INERTIA, dev->ffbit);
+ if (test)
hid_warn(pidff->hid, "unknown condition effect layout\n");
}
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 9b2c710f8da1..da1f0ea85625 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1208,10 +1208,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
switch (data[0]) {
case 0x04:
+ if (len < 32) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Report 0x04 too short: %zu bytes\n", len);
+ break;
+ }
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
fallthrough;
case 0x03:
+ if (i == 1 && len < 22) {
+ dev_warn(wacom->pen_input->dev.parent,
+ "Report 0x03 too short: %zu bytes\n", len);
+ break;
+ }
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
wacom_intuos_bt_process_data(wacom, data + i);
diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index c28aac0726de..fdffd4f002f6 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -314,15 +314,17 @@ int mshv_region_pin(struct mshv_mem_region *region)
ret = pin_user_pages_fast(userspace_addr, nr_pages,
FOLL_WRITE | FOLL_LONGTERM,
pages);
- if (ret < 0)
+ if (ret != nr_pages)
goto release_pages;
}
return 0;
release_pages:
+ if (ret > 0)
+ done_count += ret;
mshv_region_invalidate_pages(region, 0, done_count);
- return ret;
+ return ret < 0 ? ret : -ENOMEM;
}
static int mshv_region_chunk_unmap(struct mshv_mem_region *region,
diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
index 04c2a1910a8a..826798f1a8ec 100644
--- a/drivers/hv/mshv_root.h
+++ b/drivers/hv/mshv_root.h
@@ -190,7 +190,6 @@ struct hv_synic_pages {
};
struct mshv_root {
- struct hv_synic_pages __percpu *synic_pages;
spinlock_t pt_ht_lock;
DECLARE_HASHTABLE(pt_htable, MSHV_PARTITIONS_HASH_BITS);
struct hv_partition_property_vmm_capabilities vmm_caps;
@@ -249,8 +248,8 @@ int mshv_register_doorbell(u64 partition_id, doorbell_cb_t doorbell_cb,
void mshv_unregister_doorbell(u64 partition_id, int doorbell_portid);
void mshv_isr(void);
-int mshv_synic_init(unsigned int cpu);
-int mshv_synic_cleanup(unsigned int cpu);
+int mshv_synic_init(struct device *dev);
+void mshv_synic_exit(void);
static inline bool mshv_partition_encrypted(struct mshv_partition *partition)
{
diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 82ff823ef0ca..c8e5523a52b6 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -120,7 +120,6 @@ static u16 mshv_passthru_hvcalls[] = {
HVCALL_SET_VP_REGISTERS,
HVCALL_TRANSLATE_VIRTUAL_ADDRESS,
HVCALL_CLEAR_VIRTUAL_INTERRUPT,
- HVCALL_SCRUB_PARTITION,
HVCALL_REGISTER_INTERCEPT_RESULT,
HVCALL_ASSERT_VIRTUAL_INTERRUPT,
HVCALL_GET_GPA_PAGES_ACCESS_STATES,
@@ -631,7 +630,7 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
{
struct mshv_partition *p = vp->vp_partition;
struct mshv_mem_region *region;
- bool ret;
+ bool ret = false;
u64 gfn;
#if defined(CONFIG_X86_64)
struct hv_x64_memory_intercept_message *msg =
@@ -642,6 +641,8 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
(struct hv_arm64_memory_intercept_message *)
vp->vp_intercept_msg_page->u.payload;
#endif
+ enum hv_intercept_access_type access_type =
+ msg->header.intercept_access_type;
gfn = HVPFN_DOWN(msg->guest_physical_address);
@@ -649,12 +650,19 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
if (!region)
return false;
+ if (access_type == HV_INTERCEPT_ACCESS_WRITE &&
+ !(region->hv_map_flags & HV_MAP_GPA_WRITABLE))
+ goto put_region;
+
+ if (access_type == HV_INTERCEPT_ACCESS_EXECUTE &&
+ !(region->hv_map_flags & HV_MAP_GPA_EXECUTABLE))
+ goto put_region;
+
/* Only movable memory ranges are supported for GPA intercepts */
if (region->mreg_type == MSHV_REGION_TYPE_MEM_MOVABLE)
ret = mshv_region_handle_gfn_fault(region, gfn);
- else
- ret = false;
+put_region:
mshv_region_put(region);
return ret;
@@ -1289,7 +1297,7 @@ err_out:
*/
static long
mshv_map_user_memory(struct mshv_partition *partition,
- struct mshv_user_mem_region mem)
+ struct mshv_user_mem_region *mem)
{
struct mshv_mem_region *region;
struct vm_area_struct *vma;
@@ -1297,12 +1305,12 @@ mshv_map_user_memory(struct mshv_partition *partition,
ulong mmio_pfn;
long ret;
- if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
- !access_ok((const void __user *)mem.userspace_addr, mem.size))
+ if (mem->flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
+ !access_ok((const void __user *)mem->userspace_addr, mem->size))
return -EINVAL;
mmap_read_lock(current->mm);
- vma = vma_lookup(current->mm, mem.userspace_addr);
+ vma = vma_lookup(current->mm, mem->userspace_addr);
is_mmio = vma ? !!(vma->vm_flags & (VM_IO | VM_PFNMAP)) : 0;
mmio_pfn = is_mmio ? vma->vm_pgoff : 0;
mmap_read_unlock(current->mm);
@@ -1310,7 +1318,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
if (!vma)
return -EINVAL;
- ret = mshv_partition_create_region(partition, &mem, &region,
+ ret = mshv_partition_create_region(partition, mem, &region,
is_mmio);
if (ret)
return ret;
@@ -1348,32 +1356,32 @@ mshv_map_user_memory(struct mshv_partition *partition,
return 0;
errout:
- vfree(region);
+ mshv_region_put(region);
return ret;
}
/* Called for unmapping both the guest ram and the mmio space */
static long
mshv_unmap_user_memory(struct mshv_partition *partition,
- struct mshv_user_mem_region mem)
+ struct mshv_user_mem_region *mem)
{
struct mshv_mem_region *region;
- if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
+ if (!(mem->flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
return -EINVAL;
spin_lock(&partition->pt_mem_regions_lock);
- region = mshv_partition_region_by_gfn(partition, mem.guest_pfn);
+ region = mshv_partition_region_by_gfn(partition, mem->guest_pfn);
if (!region) {
spin_unlock(&partition->pt_mem_regions_lock);
return -ENOENT;
}
/* Paranoia check */
- if (region->start_uaddr != mem.userspace_addr ||
- region->start_gfn != mem.guest_pfn ||
- region->nr_pages != HVPFN_DOWN(mem.size)) {
+ if (region->start_uaddr != mem->userspace_addr ||
+ region->start_gfn != mem->guest_pfn ||
+ region->nr_pages != HVPFN_DOWN(mem->size)) {
spin_unlock(&partition->pt_mem_regions_lock);
return -EINVAL;
}
@@ -1404,9 +1412,9 @@ mshv_partition_ioctl_set_memory(struct mshv_partition *partition,
return -EINVAL;
if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP))
- return mshv_unmap_user_memory(partition, mem);
+ return mshv_unmap_user_memory(partition, &mem);
- return mshv_map_user_memory(partition, mem);
+ return mshv_map_user_memory(partition, &mem);
}
static long
@@ -2064,7 +2072,6 @@ mshv_dev_release(struct inode *inode, struct file *filp)
return 0;
}
-static int mshv_cpuhp_online;
static int mshv_root_sched_online;
static const char *scheduler_type_to_string(enum hv_scheduler_type type)
@@ -2249,27 +2256,6 @@ root_scheduler_deinit(void)
free_percpu(root_scheduler_output);
}
-static int mshv_reboot_notify(struct notifier_block *nb,
- unsigned long code, void *unused)
-{
- cpuhp_remove_state(mshv_cpuhp_online);
- return 0;
-}
-
-struct notifier_block mshv_reboot_nb = {
- .notifier_call = mshv_reboot_notify,
-};
-
-static void mshv_root_partition_exit(void)
-{
- unregister_reboot_notifier(&mshv_reboot_nb);
-}
-
-static int __init mshv_root_partition_init(struct device *dev)
-{
- return register_reboot_notifier(&mshv_reboot_nb);
-}
-
static int __init mshv_init_vmm_caps(struct device *dev)
{
int ret;
@@ -2314,39 +2300,21 @@ static int __init mshv_parent_partition_init(void)
MSHV_HV_MAX_VERSION);
}
- mshv_root.synic_pages = alloc_percpu(struct hv_synic_pages);
- if (!mshv_root.synic_pages) {
- dev_err(dev, "Failed to allocate percpu synic page\n");
- ret = -ENOMEM;
+ ret = mshv_synic_init(dev);
+ if (ret)
goto device_deregister;
- }
-
- ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
- mshv_synic_init,
- mshv_synic_cleanup);
- if (ret < 0) {
- dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
- goto free_synic_pages;
- }
-
- mshv_cpuhp_online = ret;
ret = mshv_init_vmm_caps(dev);
if (ret)
- goto remove_cpu_state;
+ goto synic_cleanup;
ret = mshv_retrieve_scheduler_type(dev);
if (ret)
- goto remove_cpu_state;
-
- if (hv_root_partition())
- ret = mshv_root_partition_init(dev);
- if (ret)
- goto remove_cpu_state;
+ goto synic_cleanup;
ret = root_scheduler_init(dev);
if (ret)
- goto exit_partition;
+ goto synic_cleanup;
ret = mshv_debugfs_init();
if (ret)
@@ -2367,13 +2335,8 @@ exit_debugfs:
mshv_debugfs_exit();
deinit_root_scheduler:
root_scheduler_deinit();
-exit_partition:
- if (hv_root_partition())
- mshv_root_partition_exit();
-remove_cpu_state:
- cpuhp_remove_state(mshv_cpuhp_online);
-free_synic_pages:
- free_percpu(mshv_root.synic_pages);
+synic_cleanup:
+ mshv_synic_exit();
device_deregister:
misc_deregister(&mshv_dev);
return ret;
@@ -2387,10 +2350,7 @@ static void __exit mshv_parent_partition_exit(void)
misc_deregister(&mshv_dev);
mshv_irqfd_wq_cleanup();
root_scheduler_deinit();
- if (hv_root_partition())
- mshv_root_partition_exit();
- cpuhp_remove_state(mshv_cpuhp_online);
- free_percpu(mshv_root.synic_pages);
+ mshv_synic_exit();
}
module_init(mshv_parent_partition_init);
diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c
index 216065e21d28..43f1bcbbf2d3 100644
--- a/drivers/hv/mshv_synic.c
+++ b/drivers/hv/mshv_synic.c
@@ -10,13 +10,22 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/random.h>
+#include <linux/cpuhotplug.h>
+#include <linux/reboot.h>
#include <asm/mshyperv.h>
+#include <linux/acpi.h>
#include "mshv_eventfd.h"
#include "mshv.h"
+static int synic_cpuhp_online;
+static struct hv_synic_pages __percpu *synic_pages;
+static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */
+static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */
+
static u32 synic_event_ring_get_queued_port(u32 sint_index)
{
struct hv_synic_event_ring_page **event_ring_page;
@@ -26,7 +35,7 @@ static u32 synic_event_ring_get_queued_port(u32 sint_index)
u32 message;
u8 tail;
- spages = this_cpu_ptr(mshv_root.synic_pages);
+ spages = this_cpu_ptr(synic_pages);
event_ring_page = &spages->synic_event_ring_page;
synic_eventring_tail = (u8 **)this_cpu_ptr(hv_synic_eventring_tail);
@@ -393,7 +402,7 @@ unlock_out:
void mshv_isr(void)
{
- struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
+ struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
struct hv_message *msg;
bool handled;
@@ -437,25 +446,21 @@ void mshv_isr(void)
if (msg->header.message_flags.msg_pending)
hv_set_non_nested_msr(HV_MSR_EOM, 0);
-#ifdef HYPERVISOR_CALLBACK_VECTOR
- add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR);
-#endif
+ add_interrupt_randomness(mshv_sint_vector);
} else {
pr_warn_once("%s: unknown message type 0x%x\n", __func__,
msg->header.message_type);
}
}
-int mshv_synic_init(unsigned int cpu)
+static int mshv_synic_cpu_init(unsigned int cpu)
{
union hv_synic_simp simp;
union hv_synic_siefp siefp;
union hv_synic_sirbp sirbp;
-#ifdef HYPERVISOR_CALLBACK_VECTOR
union hv_synic_sint sint;
-#endif
union hv_synic_scontrol sctrl;
- struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
+ struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
struct hv_synic_event_flags_page **event_flags_page =
&spages->synic_event_flags_page;
@@ -496,10 +501,12 @@ int mshv_synic_init(unsigned int cpu)
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
-#ifdef HYPERVISOR_CALLBACK_VECTOR
+ if (mshv_sint_irq != -1)
+ enable_percpu_irq(mshv_sint_irq, 0);
+
/* Enable intercepts */
sint.as_uint64 = 0;
- sint.vector = HYPERVISOR_CALLBACK_VECTOR;
+ sint.vector = mshv_sint_vector;
sint.masked = false;
sint.auto_eoi = hv_recommend_using_aeoi();
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX,
@@ -507,13 +514,12 @@ int mshv_synic_init(unsigned int cpu)
/* Doorbell SINT */
sint.as_uint64 = 0;
- sint.vector = HYPERVISOR_CALLBACK_VECTOR;
+ sint.vector = mshv_sint_vector;
sint.masked = false;
sint.as_intercept = 1;
sint.auto_eoi = hv_recommend_using_aeoi();
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
sint.as_uint64);
-#endif
/* Enable global synic bit */
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
@@ -542,14 +548,14 @@ cleanup:
return -EFAULT;
}
-int mshv_synic_cleanup(unsigned int cpu)
+static int mshv_synic_cpu_exit(unsigned int cpu)
{
union hv_synic_sint sint;
union hv_synic_simp simp;
union hv_synic_siefp siefp;
union hv_synic_sirbp sirbp;
union hv_synic_scontrol sctrl;
- struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
+ struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
struct hv_synic_event_flags_page **event_flags_page =
&spages->synic_event_flags_page;
@@ -568,6 +574,9 @@ int mshv_synic_cleanup(unsigned int cpu)
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
sint.as_uint64);
+ if (mshv_sint_irq != -1)
+ disable_percpu_irq(mshv_sint_irq);
+
/* Disable Synic's event ring page */
sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
sirbp.sirbp_enabled = false;
@@ -663,3 +672,152 @@ mshv_unregister_doorbell(u64 partition_id, int doorbell_portid)
mshv_portid_free(doorbell_portid);
}
+
+static int mshv_synic_reboot_notify(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+ if (!hv_root_partition())
+ return 0;
+
+ cpuhp_remove_state(synic_cpuhp_online);
+ return 0;
+}
+
+static struct notifier_block mshv_synic_reboot_nb = {
+ .notifier_call = mshv_synic_reboot_notify,
+};
+
+#ifndef HYPERVISOR_CALLBACK_VECTOR
+static DEFINE_PER_CPU(long, mshv_evt);
+
+static irqreturn_t mshv_percpu_isr(int irq, void *dev_id)
+{
+ mshv_isr();
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_ACPI
+static int __init mshv_acpi_setup_sint_irq(void)
+{
+ return acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE,
+ ACPI_ACTIVE_HIGH);
+}
+
+static void mshv_acpi_cleanup_sint_irq(void)
+{
+ acpi_unregister_gsi(mshv_sint_vector);
+}
+#else
+static int __init mshv_acpi_setup_sint_irq(void)
+{
+ return -ENODEV;
+}
+
+static void mshv_acpi_cleanup_sint_irq(void)
+{
+}
+#endif
+
+static int __init mshv_sint_vector_setup(void)
+{
+ int ret;
+ struct hv_register_assoc reg = {
+ .name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID,
+ };
+ union hv_input_vtl input_vtl = { 0 };
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
+ 1, input_vtl, &reg);
+ if (ret || !reg.value.reg64)
+ return -ENODEV;
+
+ mshv_sint_vector = reg.value.reg64;
+ ret = mshv_acpi_setup_sint_irq();
+ if (ret < 0) {
+ pr_err("Failed to setup IRQ for MSHV SINT vector %d: %d\n",
+ mshv_sint_vector, ret);
+ goto out_fail;
+ }
+
+ mshv_sint_irq = ret;
+
+ ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV",
+ &mshv_evt);
+ if (ret)
+ goto out_unregister;
+
+ return 0;
+
+out_unregister:
+ mshv_acpi_cleanup_sint_irq();
+out_fail:
+ return ret;
+}
+
+static void mshv_sint_vector_cleanup(void)
+{
+ free_percpu_irq(mshv_sint_irq, &mshv_evt);
+ mshv_acpi_cleanup_sint_irq();
+}
+#else /* !HYPERVISOR_CALLBACK_VECTOR */
+static int __init mshv_sint_vector_setup(void)
+{
+ mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR;
+ return 0;
+}
+
+static void mshv_sint_vector_cleanup(void)
+{
+}
+#endif /* HYPERVISOR_CALLBACK_VECTOR */
+
+int __init mshv_synic_init(struct device *dev)
+{
+ int ret = 0;
+
+ ret = mshv_sint_vector_setup();
+ if (ret)
+ return ret;
+
+ synic_pages = alloc_percpu(struct hv_synic_pages);
+ if (!synic_pages) {
+ dev_err(dev, "Failed to allocate percpu synic page\n");
+ ret = -ENOMEM;
+ goto sint_vector_cleanup;
+ }
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
+ mshv_synic_cpu_init,
+ mshv_synic_cpu_exit);
+ if (ret < 0) {
+ dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
+ goto free_synic_pages;
+ }
+
+ synic_cpuhp_online = ret;
+
+ ret = register_reboot_notifier(&mshv_synic_reboot_nb);
+ if (ret)
+ goto remove_cpuhp_state;
+
+ return 0;
+
+remove_cpuhp_state:
+ cpuhp_remove_state(synic_cpuhp_online);
+free_synic_pages:
+ free_percpu(synic_pages);
+sint_vector_cleanup:
+ mshv_sint_vector_cleanup();
+ return ret;
+}
+
+void mshv_synic_exit(void)
+{
+ unregister_reboot_notifier(&mshv_synic_reboot_nb);
+ cpuhp_remove_state(synic_cpuhp_online);
+ free_percpu(synic_pages);
+ mshv_sint_vector_cleanup();
+}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 41c381764c2b..328867242cb3 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1493,8 +1493,7 @@ config SENSORS_LM73
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
- depends on I2C
- depends on I3C || !I3C
+ depends on I3C_OR_I2C
select REGMAP_I2C
select REGMAP_I3C if I3C
help
@@ -1927,16 +1926,6 @@ config SENSORS_RASPBERRYPI_HWMON
This driver can also be built as a module. If so, the module
will be called raspberrypi-hwmon.
-config SENSORS_SA67MCU
- tristate "Kontron sa67mcu hardware monitoring driver"
- depends on MFD_SL28CPLD || COMPILE_TEST
- help
- If you say yes here you get support for the voltage and temperature
- monitor of the sa67 board management controller.
-
- This driver can also be built as a module. If so, the module
- will be called sa67mcu-hwmon.
-
config SENSORS_SL28CPLD
tristate "Kontron sl28cpld hardware monitoring driver"
depends on MFD_SL28CPLD || COMPILE_TEST
@@ -2392,8 +2381,7 @@ config SENSORS_TMP103
config SENSORS_TMP108
tristate "Texas Instruments TMP108"
- depends on I2C
- depends on I3C || !I3C
+ depends on I3C_OR_I2C
select REGMAP_I2C
select REGMAP_I3C if I3C
help
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eade8e3b1bde..5833c807c688 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -199,7 +199,6 @@ obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
-obj-$(CONFIG_SENSORS_SA67MCU) += sa67mcu-hwmon.o
obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c
index 8b2c965480e3..7888afe8dafd 100644
--- a/drivers/hwmon/adm1177.c
+++ b/drivers/hwmon/adm1177.c
@@ -10,6 +10,8 @@
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
@@ -33,7 +35,7 @@
struct adm1177_state {
struct i2c_client *client;
u32 r_sense_uohm;
- u32 alert_threshold_ua;
+ u64 alert_threshold_ua;
bool vrange_high;
};
@@ -48,7 +50,7 @@ static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd)
}
static int adm1177_write_alert_thr(struct adm1177_state *st,
- u32 alert_threshold_ua)
+ u64 alert_threshold_ua)
{
u64 val;
int ret;
@@ -91,8 +93,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
*val = div_u64((105840000ull * dummy),
4096 * st->r_sense_uohm);
return 0;
- case hwmon_curr_max_alarm:
- *val = st->alert_threshold_ua;
+ case hwmon_curr_max:
+ *val = div_u64(st->alert_threshold_ua, 1000);
return 0;
default:
return -EOPNOTSUPP;
@@ -126,9 +128,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
switch (type) {
case hwmon_curr:
switch (attr) {
- case hwmon_curr_max_alarm:
- adm1177_write_alert_thr(st, val);
- return 0;
+ case hwmon_curr_max:
+ val = clamp_val(val, 0,
+ div_u64(105840000ULL, st->r_sense_uohm));
+ return adm1177_write_alert_thr(st, (u64)val * 1000);
default:
return -EOPNOTSUPP;
}
@@ -156,7 +159,7 @@ static umode_t adm1177_is_visible(const void *data,
if (st->r_sense_uohm)
return 0444;
return 0;
- case hwmon_curr_max_alarm:
+ case hwmon_curr_max:
if (st->r_sense_uohm)
return 0644;
return 0;
@@ -170,7 +173,7 @@ static umode_t adm1177_is_visible(const void *data,
static const struct hwmon_channel_info * const adm1177_info[] = {
HWMON_CHANNEL_INFO(curr,
- HWMON_C_INPUT | HWMON_C_MAX_ALARM),
+ HWMON_C_INPUT | HWMON_C_MAX),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT),
NULL
@@ -192,7 +195,8 @@ static int adm1177_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct adm1177_state *st;
- u32 alert_threshold_ua;
+ u64 alert_threshold_ua;
+ u32 prop;
int ret;
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
@@ -208,22 +212,26 @@ static int adm1177_probe(struct i2c_client *client)
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&st->r_sense_uohm))
st->r_sense_uohm = 0;
- if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
- &alert_threshold_ua)) {
- if (st->r_sense_uohm)
- /*
- * set maximum default value from datasheet based on
- * shunt-resistor
- */
- alert_threshold_ua = div_u64(105840000000,
- st->r_sense_uohm);
- else
- alert_threshold_ua = 0;
+ if (!device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
+ &prop)) {
+ alert_threshold_ua = prop;
+ } else if (st->r_sense_uohm) {
+ /*
+ * set maximum default value from datasheet based on
+ * shunt-resistor
+ */
+ alert_threshold_ua = div_u64(105840000000ULL,
+ st->r_sense_uohm);
+ } else {
+ alert_threshold_ua = 0;
}
st->vrange_high = device_property_read_bool(dev,
"adi,vrange-high-enable");
- if (alert_threshold_ua && st->r_sense_uohm)
- adm1177_write_alert_thr(st, alert_threshold_ua);
+ if (alert_threshold_ua && st->r_sense_uohm) {
+ ret = adm1177_write_alert_thr(st, alert_threshold_ua);
+ if (ret)
+ return ret;
+ }
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
ADM1177_CMD_I_CONT |
diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c
index 007befdba977..4ce019d2cc80 100644
--- a/drivers/hwmon/aht10.c
+++ b/drivers/hwmon/aht10.c
@@ -37,7 +37,9 @@
#define AHT10_CMD_MEAS 0b10101100
#define AHT10_CMD_RST 0b10111010
-#define DHT20_CMD_INIT 0x71
+#define AHT20_CMD_INIT 0b10111110
+
+#define DHT20_CMD_INIT 0b01110001
/*
* Flags in the answer byte/command
@@ -341,7 +343,7 @@ static int aht10_probe(struct i2c_client *client)
data->meas_size = AHT20_MEAS_SIZE;
data->crc8 = true;
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY);
- data->init_cmd = AHT10_CMD_INIT;
+ data->init_cmd = AHT20_CMD_INIT;
break;
case dht20:
data->meas_size = AHT20_MEAS_SIZE;
diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 86f444498650..adedaf0db10e 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -111,6 +111,8 @@ enum ec_sensors {
ec_sensor_temp_mb,
/* "T_Sensor" temperature sensor reading [℃] */
ec_sensor_temp_t_sensor,
+ /* like ec_sensor_temp_t_sensor, but at an alternate address [℃] */
+ ec_sensor_temp_t_sensor_alt1,
/* VRM temperature [℃] */
ec_sensor_temp_vrm,
/* VRM east (right) temperature [℃] */
@@ -160,6 +162,7 @@ enum ec_sensors {
#define SENSOR_TEMP_CPU_PACKAGE BIT(ec_sensor_temp_cpu_package)
#define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb)
#define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor)
+#define SENSOR_TEMP_T_SENSOR_ALT1 BIT(ec_sensor_temp_t_sensor_alt1)
#define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm)
#define SENSOR_TEMP_VRME BIT(ec_sensor_temp_vrme)
#define SENSOR_TEMP_VRMW BIT(ec_sensor_temp_vrmw)
@@ -279,6 +282,8 @@ static const struct ec_sensor_info sensors_family_amd_600[] = {
EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33),
[ec_sensor_temp_t_sensor] =
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36),
+ [ec_sensor_temp_t_sensor_alt1] =
+ EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x37),
[ec_sensor_fan_cpu_opt] =
EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
[ec_sensor_temp_water_in] =
@@ -519,7 +524,7 @@ static const struct ec_board_info board_info_prime_x570_pro = {
static const struct ec_board_info board_info_prime_x670e_pro_wifi = {
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
- SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT,
+ SENSOR_TEMP_T_SENSOR_ALT1 | SENSOR_FAN_CPU_OPT,
.mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
.family = family_amd_600_series,
};
diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c
index b7bb325c3ad9..01590dfa55e6 100644
--- a/drivers/hwmon/axi-fan-control.c
+++ b/drivers/hwmon/axi-fan-control.c
@@ -507,7 +507,7 @@ static int axi_fan_control_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, ctl->irq, NULL,
axi_fan_control_irq_handler,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
- pdev->driver_override, ctl);
+ NULL, ctl);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"failed to request an irq\n");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e233aafa8856..5cfb98a0512f 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -3590,10 +3590,13 @@ static int it87_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct it87_data *data = dev_get_drvdata(dev);
+ int err;
it87_resume_sio(pdev);
- it87_lock(data);
+ err = it87_lock(data);
+ if (err)
+ return err;
it87_check_pwm(dev);
it87_check_limit_regs(data);
diff --git a/drivers/hwmon/macsmc-hwmon.c b/drivers/hwmon/macsmc-hwmon.c
index 1c0bbec7e8eb..1500ec2cc9f8 100644
--- a/drivers/hwmon/macsmc-hwmon.c
+++ b/drivers/hwmon/macsmc-hwmon.c
@@ -22,6 +22,7 @@
#include <linux/bitfield.h>
#include <linux/hwmon.h>
+#include <linux/math64.h>
#include <linux/mfd/macsmc.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -130,7 +131,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
if (ret < 0)
return ret;
- *p = mult_frac(val, scale, 65536);
+ *p = mul_u64_u32_div(val, scale, 65536);
return 0;
}
@@ -140,7 +141,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
* them.
*/
static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
- int *p, int scale)
+ long *p, int scale)
{
u32 fval;
u64 val;
@@ -162,21 +163,21 @@ static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
val = 0;
else if (exp < 0)
val >>= -exp;
- else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
+ else if (exp != 0 && (val & ~((1ULL << (64 - exp)) - 1))) /* overflow */
val = U64_MAX;
else
val <<= exp;
if (fval & FLT_SIGN_MASK) {
- if (val > (-(s64)INT_MIN))
- *p = INT_MIN;
+ if (val > (u64)LONG_MAX + 1)
+ *p = LONG_MIN;
else
- *p = -val;
+ *p = -(long)val;
} else {
- if (val > INT_MAX)
- *p = INT_MAX;
+ if (val > (u64)LONG_MAX)
+ *p = LONG_MAX;
else
- *p = val;
+ *p = (long)val;
}
return 0;
@@ -195,7 +196,7 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
switch (sensor->info.type_code) {
/* 32-bit IEEE 754 float */
case __SMC_KEY('f', 'l', 't', ' '): {
- u32 flt_ = 0;
+ long flt_ = 0;
ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
&flt_, scale);
@@ -214,7 +215,10 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
if (ret)
return ret;
- *val = (long)ioft;
+ if (ioft > LONG_MAX)
+ *val = LONG_MAX;
+ else
+ *val = (long)ioft;
break;
}
default:
@@ -224,29 +228,26 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
return 0;
}
-static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value)
+static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, long value)
{
u64 val;
u32 fval = 0;
- int exp = 0, neg;
+ int exp, neg;
+ neg = value < 0;
val = abs(value);
- neg = val != value;
if (val) {
- int msb = __fls(val) - exp;
-
- if (msb > 23) {
- val >>= msb - FLT_MANT_BIAS;
- exp -= msb - FLT_MANT_BIAS;
- } else if (msb < 23) {
- val <<= FLT_MANT_BIAS - msb;
- exp += msb;
- }
+ exp = __fls(val);
+
+ if (exp > 23)
+ val >>= exp - 23;
+ else
+ val <<= 23 - exp;
fval = FIELD_PREP(FLT_SIGN_MASK, neg) |
FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) |
- FIELD_PREP(FLT_MANT_MASK, val);
+ FIELD_PREP(FLT_MANT_MASK, val & FLT_MANT_MASK);
}
return apple_smc_write_u32(smc, key, fval);
@@ -663,8 +664,8 @@ static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
if (!hwmon->volt.sensors)
return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") {
- sensor = &hwmon->temp.sensors[hwmon->temp.count];
+ for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
+ sensor = &hwmon->volt.sensors[hwmon->volt.count];
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
sensor->attrs = HWMON_I_INPUT;
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index a0a1dbbda887..163d31f17bd4 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -232,7 +232,7 @@ static int max6639_read_fan(struct device *dev, u32 attr, int channel,
static int max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr)
{
/* Decrement the PPR value and shift left by 6 to match the register format */
- return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6);
+ return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), --ppr << 6);
}
static int max6639_write_fan(struct device *dev, u32 attr, int channel,
@@ -524,8 +524,8 @@ static int max6639_probe_child_from_dt(struct i2c_client *client,
{
struct device *dev = &client->dev;
- u32 i;
- int err, val;
+ u32 i, val;
+ int err;
err = of_property_read_u32(child, "reg", &i);
if (err) {
@@ -540,8 +540,8 @@ static int max6639_probe_child_from_dt(struct i2c_client *client,
err = of_property_read_u32(child, "pulses-per-revolution", &val);
if (!err) {
- if (val < 1 || val > 5) {
- dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child);
+ if (val < 1 || val > 4) {
+ dev_err(dev, "invalid pulses-per-revolution %u of %pOFn\n", val, child);
return -EINVAL;
}
data->ppr[i] = val;
@@ -607,7 +607,7 @@ static int max6639_init_client(struct i2c_client *client,
return err;
/* Fans PWM polarity high by default */
- err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
+ err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
if (err)
return err;
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 89928d38831b..42cc6068bb08 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -420,6 +420,12 @@ static ssize_t occ_show_freq_2(struct device *dev,
return sysfs_emit(buf, "%u\n", val);
}
+static u64 occ_get_powr_avg(u64 accum, u32 samples)
+{
+ return (samples == 0) ? 0 :
+ mul_u64_u32_div(accum, 1000000UL, samples);
+}
+
static ssize_t occ_show_power_1(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -441,9 +447,8 @@ static ssize_t occ_show_power_1(struct device *dev,
val = get_unaligned_be16(&power->sensor_id);
break;
case 1:
- val = get_unaligned_be32(&power->accumulator) /
- get_unaligned_be32(&power->update_tag);
- val *= 1000000ULL;
+ val = occ_get_powr_avg(get_unaligned_be32(&power->accumulator),
+ get_unaligned_be32(&power->update_tag));
break;
case 2:
val = (u64)get_unaligned_be32(&power->update_tag) *
@@ -459,12 +464,6 @@ static ssize_t occ_show_power_1(struct device *dev,
return sysfs_emit(buf, "%llu\n", val);
}
-static u64 occ_get_powr_avg(u64 accum, u32 samples)
-{
- return (samples == 0) ? 0 :
- mul_u64_u32_div(accum, 1000000UL, samples);
-}
-
static ssize_t occ_show_power_2(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -725,7 +724,7 @@ static ssize_t occ_show_extended(struct device *dev,
switch (sattr->nr) {
case 0:
if (extn->flags & EXTN_FLAG_SENSOR_ID) {
- rc = sysfs_emit(buf, "%u",
+ rc = sysfs_emit(buf, "%u\n",
get_unaligned_be32(&extn->sensor_id));
} else {
rc = sysfs_emit(buf, "%4phN\n", extn->name);
diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c
index b2fc936851e1..457089c561b4 100644
--- a/drivers/hwmon/peci/cputemp.c
+++ b/drivers/hwmon/peci/cputemp.c
@@ -131,7 +131,7 @@ static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type
*val = priv->temp.target.tjmax;
break;
case crit_hyst_type:
- *val = priv->temp.target.tjmax - priv->temp.target.tcontrol;
+ *val = priv->temp.target.tcontrol;
break;
default:
ret = -EOPNOTSUPP;
@@ -319,7 +319,7 @@ static umode_t cputemp_is_visible(const void *data, enum hwmon_sensor_types type
{
const struct peci_cputemp *priv = data;
- if (channel > CPUTEMP_CHANNEL_NUMS)
+ if (channel >= CPUTEMP_CHANNEL_NUMS)
return 0;
if (channel < channel_core)
diff --git a/drivers/hwmon/pmbus/hac300s.c b/drivers/hwmon/pmbus/hac300s.c
index 0a1d52cae91e..a073db1cfe2e 100644
--- a/drivers/hwmon/pmbus/hac300s.c
+++ b/drivers/hwmon/pmbus/hac300s.c
@@ -58,6 +58,8 @@ static int hac300s_read_word_data(struct i2c_client *client, int page,
case PMBUS_MFR_VOUT_MIN:
case PMBUS_READ_VOUT:
rv = pmbus_read_word_data(client, page, phase, reg);
+ if (rv < 0)
+ return rv;
return FIELD_GET(LINEAR11_MANTISSA_MASK, rv);
default:
return -ENODATA;
diff --git a/drivers/hwmon/pmbus/ina233.c b/drivers/hwmon/pmbus/ina233.c
index dde1e1678394..7aebd854763a 100644
--- a/drivers/hwmon/pmbus/ina233.c
+++ b/drivers/hwmon/pmbus/ina233.c
@@ -67,10 +67,13 @@ static int ina233_read_word_data(struct i2c_client *client, int page,
switch (reg) {
case PMBUS_VIRT_READ_VMON:
ret = pmbus_read_word_data(client, 0, 0xff, MFR_READ_VSHUNT);
+ if (ret < 0)
+ return ret;
/* Adjust returned value to match VIN coefficients */
/* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
- ret = DIV_ROUND_CLOSEST(ret * 25, 12500);
+ ret = clamp_val(DIV_ROUND_CLOSEST((s16)ret * 25, 12500),
+ S16_MIN, S16_MAX) & 0xffff;
break;
default:
ret = -ENODATA;
diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c
index 97b61836f53a..3e3a887aad05 100644
--- a/drivers/hwmon/pmbus/isl68137.c
+++ b/drivers/hwmon/pmbus/isl68137.c
@@ -96,10 +96,21 @@ static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,
int page,
char *buf)
{
- int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+ int val;
- return sprintf(buf, "%d\n",
- (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0);
+ val = pmbus_lock_interruptible(client);
+ if (val)
+ return val;
+
+ val = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+
+ pmbus_unlock(client);
+
+ if (val < 0)
+ return val;
+
+ return sysfs_emit(buf, "%d\n",
+ (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS);
}
static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
@@ -115,6 +126,10 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
op_val = result ? ISL68137_VOUT_AVS : 0;
+ rc = pmbus_lock_interruptible(client);
+ if (rc)
+ return rc;
+
/*
* Writes to VOUT setpoint over AVSBus will persist after the VRM is
* switched to PMBus control. Switching back to AVSBus control
@@ -126,17 +141,20 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
rc = pmbus_read_word_data(client, page, 0xff,
PMBUS_VOUT_COMMAND);
if (rc < 0)
- return rc;
+ goto unlock;
rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND,
rc);
if (rc < 0)
- return rc;
+ goto unlock;
}
rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION,
ISL68137_VOUT_AVS, op_val);
+unlock:
+ pmbus_unlock(client);
+
return (rc < 0) ? rc : count;
}
diff --git a/drivers/hwmon/pmbus/ltc4286.c b/drivers/hwmon/pmbus/ltc4286.c
index aabd0bcdfeee..8715d380784a 100644
--- a/drivers/hwmon/pmbus/ltc4286.c
+++ b/drivers/hwmon/pmbus/ltc4286.c
@@ -173,3 +173,4 @@ module_i2c_driver(ltc4286_driver);
MODULE_AUTHOR("Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>");
MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("PMBUS");
diff --git a/drivers/hwmon/pmbus/mp2869.c b/drivers/hwmon/pmbus/mp2869.c
index cc69a1e91dfe..4647892e5112 100644
--- a/drivers/hwmon/pmbus/mp2869.c
+++ b/drivers/hwmon/pmbus/mp2869.c
@@ -165,7 +165,7 @@ static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct mp2869_data *data = to_mp2869_data(info);
- int ret;
+ int ret, mfr;
switch (reg) {
case PMBUS_VOUT_MODE:
@@ -188,11 +188,14 @@ static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg)
if (ret < 0)
return ret;
+ mfr = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr < 0)
+ return mfr;
+
ret = (ret & ~GENMASK(2, 2)) |
FIELD_PREP(GENMASK(2, 2),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC)));
+ FIELD_GET(GENMASK(1, 1), mfr));
break;
case PMBUS_STATUS_TEMPERATURE:
/*
@@ -207,15 +210,16 @@ static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg)
if (ret < 0)
return ret;
+ mfr = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr < 0)
+ return mfr;
+
ret = (ret & ~GENMASK(7, 6)) |
FIELD_PREP(GENMASK(6, 6),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC))) |
+ FIELD_GET(GENMASK(1, 1), mfr)) |
FIELD_PREP(GENMASK(7, 7),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC)));
+ FIELD_GET(GENMASK(1, 1), mfr));
break;
default:
ret = -ENODATA;
@@ -230,7 +234,7 @@ static int mp2869_read_word_data(struct i2c_client *client, int page, int phase,
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct mp2869_data *data = to_mp2869_data(info);
- int ret;
+ int ret, mfr;
switch (reg) {
case PMBUS_STATUS_WORD:
@@ -246,11 +250,14 @@ static int mp2869_read_word_data(struct i2c_client *client, int page, int phase,
if (ret < 0)
return ret;
+ mfr = pmbus_read_byte_data(client, page,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfr < 0)
+ return mfr;
+
ret = (ret & ~GENMASK(2, 2)) |
FIELD_PREP(GENMASK(2, 2),
- FIELD_GET(GENMASK(1, 1),
- pmbus_read_byte_data(client, page,
- PMBUS_STATUS_MFR_SPECIFIC)));
+ FIELD_GET(GENMASK(1, 1), mfr));
break;
case PMBUS_READ_VIN:
/*
diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index c31982d85196..d0bc47b12cb0 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -313,6 +313,8 @@ static int mp2973_read_word_data(struct i2c_client *client, int page,
case PMBUS_STATUS_WORD:
/* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */
ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
ret ^= PB_STATUS_POWER_GOOD_N;
break;
case PMBUS_OT_FAULT_LIMIT:
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index be6d05def115..572be3ebc03d 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -6,6 +6,7 @@
* Copyright (c) 2012 Guenter Roeck
*/
+#include <linux/atomic.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dcache.h>
@@ -21,8 +22,8 @@
#include <linux/pmbus.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/of.h>
#include <linux/thermal.h>
+#include <linux/workqueue.h>
#include "pmbus.h"
/*
@@ -112,6 +113,11 @@ struct pmbus_data {
struct mutex update_lock;
+#if IS_ENABLED(CONFIG_REGULATOR)
+ atomic_t regulator_events[PMBUS_PAGES];
+ struct work_struct regulator_notify_work;
+#endif
+
bool has_status_word; /* device uses STATUS_WORD register */
int (*read_status)(struct i2c_client *client, int page);
@@ -1209,6 +1215,12 @@ static ssize_t pmbus_show_boolean(struct device *dev,
return sysfs_emit(buf, "%d\n", val);
}
+static ssize_t pmbus_show_zero(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sysfs_emit(buf, "0\n");
+}
+
static ssize_t pmbus_show_sensor(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -1407,7 +1419,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
int reg,
enum pmbus_sensor_classes class,
bool update, bool readonly,
- bool convert)
+ bool writeonly, bool convert)
{
struct pmbus_sensor *sensor;
struct device_attribute *a;
@@ -1436,7 +1448,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
sensor->data = -ENODATA;
pmbus_dev_attr_init(a, sensor->name,
readonly ? 0444 : 0644,
- pmbus_show_sensor, pmbus_set_sensor);
+ writeonly ? pmbus_show_zero : pmbus_show_sensor,
+ pmbus_set_sensor);
if (pmbus_add_attribute(data, &a->attr))
return NULL;
@@ -1495,8 +1508,10 @@ static int pmbus_add_label(struct pmbus_data *data,
struct pmbus_limit_attr {
u16 reg; /* Limit register */
u16 sbit; /* Alarm attribute status bit */
- bool update; /* True if register needs updates */
- bool low; /* True if low limit; for limits with compare functions only */
+ bool readonly:1; /* True if the attribute is read-only */
+ bool writeonly:1; /* True if the attribute is write-only */
+ bool update:1; /* True if register needs updates */
+ bool low:1; /* True if low limit; for limits with compare functions only */
const char *attr; /* Attribute name */
const char *alarm; /* Alarm attribute name */
};
@@ -1511,9 +1526,9 @@ struct pmbus_sensor_attr {
u8 nlimit; /* # of limit registers */
enum pmbus_sensor_classes class;/* sensor class */
const char *label; /* sensor label */
- bool paged; /* true if paged sensor */
- bool update; /* true if update needed */
- bool compare; /* true if compare function needed */
+ bool paged:1; /* true if paged sensor */
+ bool update:1; /* true if update needed */
+ bool compare:1; /* true if compare function needed */
u32 func; /* sensor mask */
u32 sfunc; /* sensor status mask */
int sreg; /* status register */
@@ -1544,7 +1559,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
curr = pmbus_add_sensor(data, name, l->attr, index,
page, 0xff, l->reg, attr->class,
attr->update || l->update,
- false, true);
+ l->readonly, l->writeonly, true);
if (!curr)
return -ENOMEM;
if (l->sbit && (info->func[page] & attr->sfunc)) {
@@ -1584,7 +1599,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
return ret;
}
base = pmbus_add_sensor(data, name, "input", index, page, phase,
- attr->reg, attr->class, true, true, true);
+ attr->reg, attr->class, true, true, false, true);
if (!base)
return -ENOMEM;
/* No limit and alarm attributes for phase specific sensors */
@@ -1707,23 +1722,29 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_VIN_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_VIN_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_VIN_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_VIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_VIN_MIN,
+ .readonly = true,
.attr = "rated_min",
}, {
.reg = PMBUS_MFR_VIN_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1776,23 +1797,29 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_VOUT_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_VOUT_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_VOUT_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_VOUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_VOUT_MIN,
+ .readonly = true,
.attr = "rated_min",
}, {
.reg = PMBUS_MFR_VOUT_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1852,20 +1879,25 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_IIN_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_IIN_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_IIN_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_IIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_IIN_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1889,20 +1921,25 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_IOUT_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_IOUT_MIN,
.update = true,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_IOUT_MAX,
.update = true,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_IOUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_IOUT_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1943,20 +1980,25 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_PIN_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_PIN_MIN,
.update = true,
+ .readonly = true,
.attr = "input_lowest",
}, {
.reg = PMBUS_VIRT_READ_PIN_MAX,
.update = true,
+ .readonly = true,
.attr = "input_highest",
}, {
.reg = PMBUS_VIRT_RESET_PIN_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_PIN_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -1980,20 +2022,25 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = {
}, {
.reg = PMBUS_VIRT_READ_POUT_AVG,
.update = true,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_POUT_MIN,
.update = true,
+ .readonly = true,
.attr = "input_lowest",
}, {
.reg = PMBUS_VIRT_READ_POUT_MAX,
.update = true,
+ .readonly = true,
.attr = "input_highest",
}, {
.reg = PMBUS_VIRT_RESET_POUT_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_POUT_MAX,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2049,18 +2096,23 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = {
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_VIRT_READ_TEMP_MIN,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_TEMP_AVG,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_TEMP_MAX,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_MAX_TEMP_1,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2090,18 +2142,23 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = {
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_VIRT_READ_TEMP2_MIN,
+ .readonly = true,
.attr = "lowest",
}, {
.reg = PMBUS_VIRT_READ_TEMP2_AVG,
+ .readonly = true,
.attr = "average",
}, {
.reg = PMBUS_VIRT_READ_TEMP2_MAX,
+ .readonly = true,
.attr = "highest",
}, {
.reg = PMBUS_VIRT_RESET_TEMP2_HISTORY,
+ .writeonly = true,
.attr = "reset_history",
}, {
.reg = PMBUS_MFR_MAX_TEMP_2,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2131,6 +2188,7 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = {
.sbit = PB_TEMP_OT_FAULT,
}, {
.reg = PMBUS_MFR_MAX_TEMP_3,
+ .readonly = true,
.attr = "rated_max",
},
};
@@ -2214,7 +2272,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
sensor = pmbus_add_sensor(data, "fan", "target", index, page,
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
- false, false, true);
+ false, false, false, true);
if (!sensor)
return -ENOMEM;
@@ -2225,14 +2283,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
sensor = pmbus_add_sensor(data, "pwm", NULL, index, page,
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
- false, false, true);
+ false, false, false, true);
if (!sensor)
return -ENOMEM;
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
- true, false, false);
+ true, false, false, false);
if (!sensor)
return -ENOMEM;
@@ -2274,7 +2332,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
if (pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
- PSC_FAN, true, true, true) == NULL)
+ PSC_FAN, true, true, false, true) == NULL)
return -ENOMEM;
/* Fan control */
@@ -3176,12 +3234,19 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev)
.class = PSC_VOLTAGE_OUT,
.convert = true,
};
+ int ret;
+ mutex_lock(&data->update_lock);
s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT);
- if (s.data < 0)
- return s.data;
+ if (s.data < 0) {
+ ret = s.data;
+ goto unlock;
+ }
- return (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
+ ret = (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */
+unlock:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
@@ -3198,16 +3263,22 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
};
int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
int low, high;
+ int ret;
*selector = 0;
+ mutex_lock(&data->update_lock);
low = pmbus_regulator_get_low_margin(client, s.page);
- if (low < 0)
- return low;
+ if (low < 0) {
+ ret = low;
+ goto unlock;
+ }
high = pmbus_regulator_get_high_margin(client, s.page);
- if (high < 0)
- return high;
+ if (high < 0) {
+ ret = high;
+ goto unlock;
+ }
/* Make sure we are within margins */
if (low > val)
@@ -3217,7 +3288,10 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
val = pmbus_data2reg(data, &s, val);
- return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+ ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+unlock:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
@@ -3227,6 +3301,7 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
struct i2c_client *client = to_i2c_client(dev->parent);
struct pmbus_data *data = i2c_get_clientdata(client);
int val, low, high;
+ int ret;
if (data->flags & PMBUS_VOUT_PROTECTED)
return 0;
@@ -3239,18 +3314,29 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
val = DIV_ROUND_CLOSEST(rdev->desc->min_uV +
(rdev->desc->uV_step * selector), 1000); /* convert to mV */
+ mutex_lock(&data->update_lock);
+
low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
- if (low < 0)
- return low;
+ if (low < 0) {
+ ret = low;
+ goto unlock;
+ }
high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
- if (high < 0)
- return high;
+ if (high < 0) {
+ ret = high;
+ goto unlock;
+ }
- if (val >= low && val <= high)
- return val * 1000; /* unit is uV */
+ if (val >= low && val <= high) {
+ ret = val * 1000; /* unit is uV */
+ goto unlock;
+ }
- return 0;
+ ret = 0;
+unlock:
+ mutex_unlock(&data->update_lock);
+ return ret;
}
const struct regulator_ops pmbus_regulator_ops = {
@@ -3281,12 +3367,42 @@ int pmbus_regulator_init_cb(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_NS_GPL(pmbus_regulator_init_cb, "PMBUS");
+static void pmbus_regulator_notify_work_cancel(void *data)
+{
+ struct pmbus_data *pdata = data;
+
+ cancel_work_sync(&pdata->regulator_notify_work);
+}
+
+static void pmbus_regulator_notify_worker(struct work_struct *work)
+{
+ struct pmbus_data *data =
+ container_of(work, struct pmbus_data, regulator_notify_work);
+ int i, j;
+
+ for (i = 0; i < data->info->pages; i++) {
+ int event;
+
+ event = atomic_xchg(&data->regulator_events[i], 0);
+ if (!event)
+ continue;
+
+ for (j = 0; j < data->info->num_regulators; j++) {
+ if (i == rdev_get_id(data->rdevs[j])) {
+ regulator_notifier_call_chain(data->rdevs[j],
+ event, NULL);
+ break;
+ }
+ }
+ }
+}
+
static int pmbus_regulator_register(struct pmbus_data *data)
{
struct device *dev = data->dev;
const struct pmbus_driver_info *info = data->info;
const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
- int i;
+ int i, ret;
data->rdevs = devm_kzalloc(dev, sizeof(struct regulator_dev *) * info->num_regulators,
GFP_KERNEL);
@@ -3310,19 +3426,19 @@ static int pmbus_regulator_register(struct pmbus_data *data)
info->reg_desc[i].name);
}
+ INIT_WORK(&data->regulator_notify_work, pmbus_regulator_notify_worker);
+
+ ret = devm_add_action_or_reset(dev, pmbus_regulator_notify_work_cancel, data);
+ if (ret)
+ return ret;
+
return 0;
}
static void pmbus_regulator_notify(struct pmbus_data *data, int page, int event)
{
- int j;
-
- for (j = 0; j < data->info->num_regulators; j++) {
- if (page == rdev_get_id(data->rdevs[j])) {
- regulator_notifier_call_chain(data->rdevs[j], event, NULL);
- break;
- }
- }
+ atomic_or(event, &data->regulator_events[page]);
+ schedule_work(&data->regulator_notify_work);
}
#else
static int pmbus_regulator_register(struct pmbus_data *data)
diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c
index 6a4a978eca7e..24c1f961c766 100644
--- a/drivers/hwmon/pmbus/pxe1610.c
+++ b/drivers/hwmon/pmbus/pxe1610.c
@@ -104,7 +104,10 @@ static int pxe1610_probe(struct i2c_client *client)
* By default this device doesn't boot to page 0, so set page 0
* to access all pmbus registers.
*/
- i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to set page 0\n");
/* Read Manufacturer id */
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c
index fc030ca34480..d5d60a9af8c5 100644
--- a/drivers/hwmon/pmbus/q54sj108a2.c
+++ b/drivers/hwmon/pmbus/q54sj108a2.c
@@ -79,7 +79,8 @@ static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
int idx = *idxp;
struct q54sj108a2_data *psu = to_psu(idxp, idx);
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
- char data_char[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
+ char data_char[I2C_SMBUS_BLOCK_MAX * 2 + 2] = { 0 };
+ char *out = data;
char *res;
switch (idx) {
@@ -150,27 +151,27 @@ static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
if (rc < 0)
return rc;
- res = bin2hex(data, data_char, 32);
- rc = res - data;
-
+ res = bin2hex(data_char, data, rc);
+ rc = res - data_char;
+ out = data_char;
break;
case Q54SJ108A2_DEBUGFS_FLASH_KEY:
rc = i2c_smbus_read_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, data);
if (rc < 0)
return rc;
- res = bin2hex(data, data_char, 4);
- rc = res - data;
-
+ res = bin2hex(data_char, data, rc);
+ rc = res - data_char;
+ out = data_char;
break;
default:
return -EINVAL;
}
- data[rc] = '\n';
+ out[rc] = '\n';
rc += 2;
- return simple_read_from_buffer(buf, count, ppos, data, rc);
+ return simple_read_from_buffer(buf, count, ppos, out, rc);
}
static ssize_t q54sj108a2_debugfs_write(struct file *file, const char __user *buf,
diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c
index ca2bfa25eb04..249974c13aa3 100644
--- a/drivers/hwmon/pmbus/tps53679.c
+++ b/drivers/hwmon/pmbus/tps53679.c
@@ -103,10 +103,10 @@ static int tps53679_identify_chip(struct i2c_client *client,
}
ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
- if (ret < 0)
- return ret;
+ if (ret <= 0)
+ return ret < 0 ? ret : -EIO;
- /* Adjust length if null terminator if present */
+ /* Adjust length if null terminator is present */
buf_len = (buf[ret - 1] != '\x00' ? ret : ret - 1);
id_len = strlen(id);
@@ -175,8 +175,8 @@ static int tps53676_identify(struct i2c_client *client,
ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
if (ret < 0)
return ret;
- if (strncmp("TI\x53\x67\x60", buf, 5)) {
- dev_err(&client->dev, "Unexpected device ID: %s\n", buf);
+ if (ret != 6 || memcmp(buf, "TI\x53\x67\x60\x00", 6)) {
+ dev_err(&client->dev, "Unexpected device ID: %*ph\n", ret, buf);
return -ENODEV;
}
diff --git a/drivers/hwmon/sa67mcu-hwmon.c b/drivers/hwmon/sa67mcu-hwmon.c
deleted file mode 100644
index 22f703b7b256..000000000000
--- a/drivers/hwmon/sa67mcu-hwmon.c
+++ /dev/null
@@ -1,161 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * sl67mcu hardware monitoring driver
- *
- * Copyright 2025 Kontron Europe GmbH
- */
-
-#include <linux/bitfield.h>
-#include <linux/hwmon.h>
-#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/property.h>
-#include <linux/regmap.h>
-
-#define SA67MCU_VOLTAGE(n) (0x00 + ((n) * 2))
-#define SA67MCU_TEMP(n) (0x04 + ((n) * 2))
-
-struct sa67mcu_hwmon {
- struct regmap *regmap;
- u32 offset;
-};
-
-static int sa67mcu_hwmon_read(struct device *dev,
- enum hwmon_sensor_types type, u32 attr,
- int channel, long *input)
-{
- struct sa67mcu_hwmon *hwmon = dev_get_drvdata(dev);
- unsigned int offset;
- u8 reg[2];
- int ret;
-
- switch (type) {
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- offset = hwmon->offset + SA67MCU_VOLTAGE(channel);
- break;
- default:
- return -EOPNOTSUPP;
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- offset = hwmon->offset + SA67MCU_TEMP(channel);
- break;
- default:
- return -EOPNOTSUPP;
- }
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- /* Reading the low byte will capture the value */
- ret = regmap_bulk_read(hwmon->regmap, offset, reg, ARRAY_SIZE(reg));
- if (ret)
- return ret;
-
- *input = reg[1] << 8 | reg[0];
-
- /* Temperatures are s16 and in 0.1degC steps. */
- if (type == hwmon_temp)
- *input = sign_extend32(*input, 15) * 100;
-
- return 0;
-}
-
-static const struct hwmon_channel_info * const sa67mcu_hwmon_info[] = {
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL),
- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
- NULL
-};
-
-static const char *const sa67mcu_hwmon_in_labels[] = {
- "VDDIN",
- "VDD_RTC",
-};
-
-static int sa67mcu_hwmon_read_string(struct device *dev,
- enum hwmon_sensor_types type, u32 attr,
- int channel, const char **str)
-{
- switch (type) {
- case hwmon_in:
- switch (attr) {
- case hwmon_in_label:
- *str = sa67mcu_hwmon_in_labels[channel];
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static const struct hwmon_ops sa67mcu_hwmon_ops = {
- .visible = 0444,
- .read = sa67mcu_hwmon_read,
- .read_string = sa67mcu_hwmon_read_string,
-};
-
-static const struct hwmon_chip_info sa67mcu_hwmon_chip_info = {
- .ops = &sa67mcu_hwmon_ops,
- .info = sa67mcu_hwmon_info,
-};
-
-static int sa67mcu_hwmon_probe(struct platform_device *pdev)
-{
- struct sa67mcu_hwmon *hwmon;
- struct device *hwmon_dev;
- int ret;
-
- if (!pdev->dev.parent)
- return -ENODEV;
-
- hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
- if (!hwmon)
- return -ENOMEM;
-
- hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!hwmon->regmap)
- return -ENODEV;
-
- ret = device_property_read_u32(&pdev->dev, "reg", &hwmon->offset);
- if (ret)
- return -EINVAL;
-
- hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
- "sa67mcu_hwmon", hwmon,
- &sa67mcu_hwmon_chip_info,
- NULL);
- if (IS_ERR(hwmon_dev))
- dev_err(&pdev->dev, "failed to register as hwmon device");
-
- return PTR_ERR_OR_ZERO(hwmon_dev);
-}
-
-static const struct of_device_id sa67mcu_hwmon_of_match[] = {
- { .compatible = "kontron,sa67mcu-hwmon", },
- {}
-};
-MODULE_DEVICE_TABLE(of, sa67mcu_hwmon_of_match);
-
-static struct platform_driver sa67mcu_hwmon_driver = {
- .probe = sa67mcu_hwmon_probe,
- .driver = {
- .name = "sa67mcu-hwmon",
- .of_match_table = sa67mcu_hwmon_of_match,
- },
-};
-module_platform_driver(sa67mcu_hwmon_driver);
-
-MODULE_DESCRIPTION("sa67mcu Hardware Monitoring Driver");
-MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index e11d50750e63..7cb6b9b864a7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1213,6 +1213,8 @@ config I2C_TEGRA
tristate "NVIDIA Tegra internal I2C controller"
depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
# COMPILE_TEST needs architectures with readsX()/writesX() primitives
+ depends on PINCTRL
+ # ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
help
If you say yes to this option, support will be included for the
I2C controller embedded in NVIDIA Tegra SOCs
diff --git a/drivers/i2c/busses/i2c-cp2615.c b/drivers/i2c/busses/i2c-cp2615.c
index e2d7cd2390fc..8212875700e1 100644
--- a/drivers/i2c/busses/i2c-cp2615.c
+++ b/drivers/i2c/busses/i2c-cp2615.c
@@ -298,6 +298,9 @@ cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
if (!adap)
return -ENOMEM;
+ if (!usbdev->serial)
+ return -EINVAL;
+
strscpy(adap->name, usbdev->serial, sizeof(adap->name));
adap->owner = THIS_MODULE;
adap->dev.parent = &usbif->dev;
diff --git a/drivers/i2c/busses/i2c-designware-amdisp.c b/drivers/i2c/busses/i2c-designware-amdisp.c
index c48728ad9f6f..9f0ec0fae6f2 100644
--- a/drivers/i2c/busses/i2c-designware-amdisp.c
+++ b/drivers/i2c/busses/i2c-designware-amdisp.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/soc/amd/isp4_misc.h>
@@ -76,22 +77,20 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev)
device_enable_async_suspend(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
-
+ dev_pm_genpd_resume(&pdev->dev);
ret = i2c_dw_probe(isp_i2c_dev);
if (ret) {
dev_err_probe(&pdev->dev, ret, "i2c_dw_probe failed\n");
goto error_release_rpm;
}
-
- pm_runtime_put_sync(&pdev->dev);
+ dev_pm_genpd_suspend(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
return 0;
error_release_rpm:
amd_isp_dw_i2c_plat_pm_cleanup(isp_i2c_dev);
- pm_runtime_put_sync(&pdev->dev);
return ret;
}
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 82c87e04ac6f..b2dc5ae1d0e4 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -729,6 +729,7 @@ static int fsi_i2c_probe(struct fsi_device *fsi_dev)
rc = i2c_add_adapter(&port->adapter);
if (rc < 0) {
dev_err(dev, "Failed to register adapter: %d\n", rc);
+ of_node_put(np);
kfree(port);
continue;
}
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 9e1789725edf..32a3cef02c7b 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -310,9 +310,10 @@ struct i801_priv {
/*
* If set to true the host controller registers are reserved for
- * ACPI AML use.
+ * ACPI AML use. Needs extra protection by acpi_lock.
*/
bool acpi_reserved;
+ struct mutex acpi_lock;
};
#define FEATURE_SMBUS_PEC BIT(0)
@@ -894,8 +895,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
int hwpec, ret;
struct i801_priv *priv = i2c_get_adapdata(adap);
- if (priv->acpi_reserved)
+ mutex_lock(&priv->acpi_lock);
+ if (priv->acpi_reserved) {
+ mutex_unlock(&priv->acpi_lock);
return -EBUSY;
+ }
pm_runtime_get_sync(&priv->pci_dev->dev);
@@ -935,6 +939,7 @@ out:
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
+ mutex_unlock(&priv->acpi_lock);
return ret;
}
@@ -1465,7 +1470,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
* further access from the driver itself. This device is now owned
* by the system firmware.
*/
- i2c_lock_bus(&priv->adapter, I2C_LOCK_SEGMENT);
+ mutex_lock(&priv->acpi_lock);
if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
priv->acpi_reserved = true;
@@ -1485,7 +1490,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
else
status = acpi_os_write_port(address, (u32)*value, bits);
- i2c_unlock_bus(&priv->adapter, I2C_LOCK_SEGMENT);
+ mutex_unlock(&priv->acpi_lock);
return status;
}
@@ -1545,6 +1550,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->adapter.dev.parent = &dev->dev;
acpi_use_parent_companion(&priv->adapter.dev);
priv->adapter.retries = 3;
+ mutex_init(&priv->acpi_lock);
priv->pci_dev = dev;
priv->features = id->driver_data;
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 85f554044cf1..a208fefd3c3b 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -401,7 +401,7 @@ static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_addr_t phy_addr)
{
struct imx_i2c_dma *dma;
- struct dma_slave_config dma_sconfig;
+ struct dma_slave_config dma_sconfig = {};
struct device *dev = i2c_imx->adapter.dev.parent;
int ret;
@@ -1018,8 +1018,9 @@ static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx)
return 0;
}
-static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
+static inline enum imx_i2c_state i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
{
+ enum imx_i2c_state next_state = IMX_I2C_STATE_READ_CONTINUE;
unsigned int temp;
if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) {
@@ -1033,18 +1034,20 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
i2c_imx->stopped = 1;
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- } else {
- /*
- * For i2c master receiver repeat restart operation like:
- * read -> repeat MSTA -> read/write
- * The controller must set MTX before read the last byte in
- * the first read operation, otherwise the first read cost
- * one extra clock cycle.
- */
- temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
- temp |= I2CR_MTX;
- imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+
+ return IMX_I2C_STATE_DONE;
}
+ /*
+ * For i2c master receiver repeat restart operation like:
+ * read -> repeat MSTA -> read/write
+ * The controller must set MTX before read the last byte in
+ * the first read operation, otherwise the first read cost
+ * one extra clock cycle.
+ */
+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+ temp |= I2CR_MTX;
+ imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+ next_state = IMX_I2C_STATE_DONE;
} else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) {
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_TXAK;
@@ -1052,6 +1055,7 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx)
}
i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+ return next_state;
}
static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx)
@@ -1088,11 +1092,9 @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned i
break;
case IMX_I2C_STATE_READ_CONTINUE:
- i2c_imx_isr_read_continue(i2c_imx);
- if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) {
- i2c_imx->state = IMX_I2C_STATE_DONE;
+ i2c_imx->state = i2c_imx_isr_read_continue(i2c_imx);
+ if (i2c_imx->state == IMX_I2C_STATE_DONE)
wake_up(&i2c_imx->queue);
- }
break;
case IMX_I2C_STATE_READ_BLOCK_DATA:
@@ -1490,6 +1492,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
bool is_lastmsg)
{
int block_data = msgs->flags & I2C_M_RECV_LEN;
+ int ret = 0;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
@@ -1522,10 +1525,20 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__);
return -ETIMEDOUT;
}
- if (!i2c_imx->stopped)
- return i2c_imx_bus_busy(i2c_imx, 0, false);
+ if (i2c_imx->is_lastmsg) {
+ if (!i2c_imx->stopped)
+ ret = i2c_imx_bus_busy(i2c_imx, 0, false);
+ /*
+ * Only read the last byte of the last message after the bus is
+ * not busy. Else the controller generates another clock which
+ * might confuse devices.
+ */
+ if (!ret)
+ i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx,
+ IMX_I2C_I2DR);
+ }
- return 0;
+ return ret;
}
static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 09af3b3625f1..f55840b2eb9a 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -268,6 +268,7 @@ struct pxa_i2c {
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_default;
struct pinctrl_state *pinctrl_recovery;
+ bool reset_before_xfer;
};
#define _IBMR(i2c) ((i2c)->reg_ibmr)
@@ -1144,6 +1145,11 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap,
{
struct pxa_i2c *i2c = adap->algo_data;
+ if (i2c->reset_before_xfer) {
+ i2c_pxa_reset(i2c);
+ i2c->reset_before_xfer = false;
+ }
+
return i2c_pxa_internal_xfer(i2c, msgs, num, i2c_pxa_do_xfer);
}
@@ -1521,7 +1527,16 @@ static int i2c_pxa_probe(struct platform_device *dev)
}
}
- i2c_pxa_reset(i2c);
+ /*
+ * Skip reset on Armada 3700 when recovery is used to avoid
+ * controller hang due to the pinctrl state changes done by
+ * the generic recovery initialization code. The reset will
+ * be performed later, prior to the first transfer.
+ */
+ if (i2c_type == REGS_A3700 && i2c->adap.bus_recovery_info)
+ i2c->reset_before_xfer = true;
+ else
+ i2c_pxa_reset(i2c);
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index bec619b9af4e..4eaeb395d5db 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -2047,8 +2047,11 @@ static int tegra_i2c_probe(struct platform_device *pdev)
*
* VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't
* be used for atomic transfers. ACPI device is not IRQ safe also.
+ *
+ * Devices with pinctrl states cannot be marked IRQ-safe as the pinctrl
+ * state transitions during runtime PM require mutexes.
*/
- if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev))
+ if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev) && !i2c_dev->dev->pins)
pm_runtime_irq_safe(i2c_dev->dev);
pm_runtime_enable(i2c_dev->dev);
diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig
index 30a441506f61..626c54b386d5 100644
--- a/drivers/i3c/Kconfig
+++ b/drivers/i3c/Kconfig
@@ -22,3 +22,15 @@ menuconfig I3C
if I3C
source "drivers/i3c/master/Kconfig"
endif # I3C
+
+config I3C_OR_I2C
+ tristate
+ default m if I3C=m
+ default I2C
+ help
+ Device drivers using module_i3c_i2c_driver() can use either
+ i2c or i3c hosts, but cannot be built-in for the kernel when
+ CONFIG_I3C=m.
+
+ Add 'depends on I2C_OR_I3C' in Kconfig for those drivers to
+ get the correct dependencies.
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index d87bde3f7700..d6bdb32397fb 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -1024,7 +1024,7 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
master->free_pos &= ~BIT(pos);
}
- writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr),
+ writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr) | DEV_ADDR_TABLE_SIR_REJECT,
master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
@@ -1053,7 +1053,7 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
master->free_pos &= ~BIT(pos);
i3c_dev_set_master_data(dev, data);
- writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr),
+ writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr) | DEV_ADDR_TABLE_SIR_REJECT,
master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
@@ -1659,6 +1659,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
pm_runtime_get_noresume(&pdev->dev);
INIT_WORK(&master->hj_work, dw_i3c_hj_work);
+
+ device_set_of_node_from_dev(&master->base.i2c.dev, &pdev->dev);
ret = i3c_master_register(&master->base, &pdev->dev,
&dw_mipi_i3c_ops, false);
if (ret)
diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd.h b/drivers/i3c/master/mipi-i3c-hci/cmd.h
index 1d6dd2c5d01a..b1bf87daa651 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd.h
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd.h
@@ -17,6 +17,7 @@
#define CMD_0_TOC W0_BIT_(31)
#define CMD_0_ROC W0_BIT_(30)
#define CMD_0_ATTR W0_MASK(2, 0)
+#define CMD_0_TID W0_MASK(6, 3)
/*
* Response Descriptor Structure
diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
index fe260461e7e6..75d452d7f6af 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
@@ -331,12 +331,10 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
CMD_A0_ROC | CMD_A0_TOC;
xfer->cmd_desc[1] = 0;
xfer->completion = &done;
- hci->io->queue_xfer(hci, xfer, 1);
- if (!wait_for_completion_timeout(&done, HZ) &&
- hci->io->dequeue_xfer(hci, xfer, 1)) {
- ret = -ETIME;
+ xfer->timeout = HZ;
+ ret = i3c_hci_process_xfer(hci, xfer, 1);
+ if (ret)
break;
- }
if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
RESP_DATA_LENGTH(xfer->response) == 1) {
diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
index 3729e6419581..39eec26a363c 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
@@ -253,6 +253,7 @@ static int hci_cmd_v2_daa(struct i3c_hci *hci)
xfer[0].rnw = true;
xfer[0].cmd_desc[1] = CMD_A1_DATA_LENGTH(8);
xfer[1].completion = &done;
+ xfer[1].timeout = HZ;
for (;;) {
ret = i3c_master_get_free_addr(&hci->master, next_addr);
@@ -272,12 +273,9 @@ static int hci_cmd_v2_daa(struct i3c_hci *hci)
CMD_A0_ASSIGN_ADDRESS(next_addr) |
CMD_A0_ROC |
CMD_A0_TOC;
- hci->io->queue_xfer(hci, xfer, 2);
- if (!wait_for_completion_timeout(&done, HZ) &&
- hci->io->dequeue_xfer(hci, xfer, 2)) {
- ret = -ETIME;
+ ret = i3c_hci_process_xfer(hci, xfer, 2);
+ if (ret)
break;
- }
if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
ret = 0; /* no more devices to be assigned */
break;
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 5879bba78164..284f3ed7af8c 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -152,7 +152,11 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m)
if (hci->quirks & HCI_QUIRK_RESP_BUF_THLD)
amd_set_resp_buf_thld(hci);
- reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE);
+ scoped_guard(spinlock_irqsave, &hci->lock)
+ hci->irq_inactive = false;
+
+ /* Enable bus with Hot-Join disabled */
+ reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL);
dev_dbg(&hci->master.dev, "HC_CONTROL = %#x", reg_read(HC_CONTROL));
return 0;
@@ -177,21 +181,51 @@ static int i3c_hci_bus_disable(struct i3c_hci *hci)
return ret;
}
+static int i3c_hci_software_reset(struct i3c_hci *hci)
+{
+ u32 regval;
+ int ret;
+
+ /*
+ * SOFT_RST must be clear before we write to it.
+ * Then we must wait until it clears again.
+ */
+ ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
+ !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
+ if (ret) {
+ dev_err(&hci->master.dev, "%s: Software reset stuck\n", __func__);
+ return ret;
+ }
+
+ reg_write(RESET_CONTROL, SOFT_RST);
+
+ ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
+ !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
+ if (ret) {
+ dev_err(&hci->master.dev, "%s: Software reset failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
void i3c_hci_sync_irq_inactive(struct i3c_hci *hci)
{
struct platform_device *pdev = to_platform_device(hci->master.dev.parent);
int irq = platform_get_irq(pdev, 0);
reg_write(INTR_SIGNAL_ENABLE, 0x0);
- hci->irq_inactive = true;
synchronize_irq(irq);
+ scoped_guard(spinlock_irqsave, &hci->lock)
+ hci->irq_inactive = true;
}
static void i3c_hci_bus_cleanup(struct i3c_master_controller *m)
{
struct i3c_hci *hci = to_i3c_hci(m);
- i3c_hci_bus_disable(hci);
+ if (i3c_hci_bus_disable(hci))
+ i3c_hci_software_reset(hci);
hci->io->cleanup(hci);
}
@@ -212,6 +246,36 @@ void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci)
reg_write(DCT_SECTION, FIELD_PREP(DCT_TABLE_INDEX, 0));
}
+int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
+{
+ struct completion *done = xfer[n - 1].completion;
+ unsigned long timeout = xfer[n - 1].timeout;
+ int ret;
+
+ ret = hci->io->queue_xfer(hci, xfer, n);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_timeout(done, timeout)) {
+ if (hci->io->dequeue_xfer(hci, xfer, n)) {
+ dev_err(&hci->master.dev, "%s: timeout error\n", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+ }
+
+ if (hci->io->handle_error) {
+ bool error = false;
+
+ for (int i = 0; i < n && !error; i++)
+ error = RESP_STATUS(xfer[i].response);
+ if (error)
+ return hci->io->handle_error(hci, xfer, n);
+ }
+
+ return 0;
+}
+
static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
struct i3c_ccc_cmd *ccc)
{
@@ -252,18 +316,14 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
xfer[last].completion = &done;
+ xfer[last].timeout = HZ;
if (prefixed)
xfer--;
- ret = hci->io->queue_xfer(hci, xfer, nxfers);
+ ret = i3c_hci_process_xfer(hci, xfer, nxfers);
if (ret)
goto out;
- if (!wait_for_completion_timeout(&done, HZ) &&
- hci->io->dequeue_xfer(hci, xfer, nxfers)) {
- ret = -ETIME;
- goto out;
- }
for (i = prefixed; i < nxfers; i++) {
if (ccc->rnw)
ccc->dests[i - prefixed].payload.len =
@@ -334,15 +394,11 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
xfer[last].completion = &done;
+ xfer[last].timeout = HZ;
- ret = hci->io->queue_xfer(hci, xfer, nxfers);
+ ret = i3c_hci_process_xfer(hci, xfer, nxfers);
if (ret)
goto out;
- if (!wait_for_completion_timeout(&done, HZ) &&
- hci->io->dequeue_xfer(hci, xfer, nxfers)) {
- ret = -ETIME;
- goto out;
- }
for (i = 0; i < nxfers; i++) {
if (i3c_xfers[i].rnw)
i3c_xfers[i].len = RESP_DATA_LENGTH(xfer[i].response);
@@ -382,15 +438,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
xfer[last].completion = &done;
+ xfer[last].timeout = m->i2c.timeout;
- ret = hci->io->queue_xfer(hci, xfer, nxfers);
+ ret = i3c_hci_process_xfer(hci, xfer, nxfers);
if (ret)
goto out;
- if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
- hci->io->dequeue_xfer(hci, xfer, nxfers)) {
- ret = -ETIME;
- goto out;
- }
for (i = 0; i < nxfers; i++) {
if (RESP_STATUS(xfer[i].response) != RESP_SUCCESS) {
ret = -EIO;
@@ -566,6 +618,8 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
irqreturn_t result = IRQ_NONE;
u32 val;
+ guard(spinlock)(&hci->lock);
+
/*
* The IRQ can be shared, so the handler may be called when the IRQ is
* due to a different device. That could happen when runtime suspended,
@@ -601,34 +655,6 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
return result;
}
-static int i3c_hci_software_reset(struct i3c_hci *hci)
-{
- u32 regval;
- int ret;
-
- /*
- * SOFT_RST must be clear before we write to it.
- * Then we must wait until it clears again.
- */
- ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
- !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
- if (ret) {
- dev_err(&hci->master.dev, "%s: Software reset stuck\n", __func__);
- return ret;
- }
-
- reg_write(RESET_CONTROL, SOFT_RST);
-
- ret = readx_poll_timeout(reg_read, RESET_CONTROL, regval,
- !(regval & SOFT_RST), 0, 10 * USEC_PER_MSEC);
- if (ret) {
- dev_err(&hci->master.dev, "%s: Software reset failed\n", __func__);
- return ret;
- }
-
- return 0;
-}
-
static inline bool is_version_1_1_or_newer(struct i3c_hci *hci)
{
return hci->version_major > 1 || (hci->version_major == 1 && hci->version_minor > 0);
@@ -739,8 +765,12 @@ static int i3c_hci_runtime_suspend(struct device *dev)
int ret;
ret = i3c_hci_bus_disable(hci);
- if (ret)
+ if (ret) {
+ /* Fall back to software reset to disable the bus */
+ ret = i3c_hci_software_reset(hci);
+ i3c_hci_sync_irq_inactive(hci);
return ret;
+ }
hci->io->suspend(hci);
@@ -760,11 +790,13 @@ static int i3c_hci_runtime_resume(struct device *dev)
mipi_i3c_hci_dat_v1.restore(hci);
- hci->irq_inactive = false;
-
hci->io->resume(hci);
- reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE);
+ scoped_guard(spinlock_irqsave, &hci->lock)
+ hci->irq_inactive = false;
+
+ /* Enable bus with Hot-Join disabled */
+ reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL);
return 0;
}
@@ -924,6 +956,9 @@ static int i3c_hci_probe(struct platform_device *pdev)
if (!hci)
return -ENOMEM;
+ spin_lock_init(&hci->lock);
+ mutex_init(&hci->control_mutex);
+
/*
* Multi-bus instances share the same MMIO address range, but not
* necessarily in separate contiguous sub-ranges. To avoid overlapping
@@ -950,6 +985,8 @@ static int i3c_hci_probe(struct platform_device *pdev)
if (ret)
return ret;
+ hci->irq_inactive = true;
+
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, irq, i3c_hci_irq_handler,
IRQF_SHARED, NULL, hci);
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index b903a2da1fd1..e487ef52f6b4 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -129,9 +129,8 @@ struct hci_rh_data {
dma_addr_t xfer_dma, resp_dma, ibi_status_dma, ibi_data_dma;
unsigned int xfer_entries, ibi_status_entries, ibi_chunks_total;
unsigned int xfer_struct_sz, resp_struct_sz, ibi_status_sz, ibi_chunk_sz;
- unsigned int done_ptr, ibi_chunk_ptr;
+ unsigned int done_ptr, ibi_chunk_ptr, xfer_space;
struct hci_xfer **src_xfers;
- spinlock_t lock;
struct completion op_done;
};
@@ -261,6 +260,7 @@ ring_ready:
rh->done_ptr = 0;
rh->ibi_chunk_ptr = 0;
+ rh->xfer_space = rh->xfer_entries;
}
static void hci_dma_init_rings(struct i3c_hci *hci)
@@ -344,7 +344,6 @@ static int hci_dma_init(struct i3c_hci *hci)
goto err_out;
rh = &rings->headers[i];
rh->regs = hci->base_regs + offset;
- spin_lock_init(&rh->lock);
init_completion(&rh->op_done);
rh->xfer_entries = XFER_RING_ENTRIES;
@@ -439,26 +438,63 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci,
}
}
+static struct i3c_dma *hci_dma_map_xfer(struct device *dev, struct hci_xfer *xfer)
+{
+ enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ bool need_bounce = device_iommu_mapped(dev) && xfer->rnw && (xfer->data_len & 3);
+
+ return i3c_master_dma_map_single(dev, xfer->data, xfer->data_len, need_bounce, dir);
+}
+
+static int hci_dma_map_xfer_list(struct i3c_hci *hci, struct device *dev,
+ struct hci_xfer *xfer_list, int n)
+{
+ for (int i = 0; i < n; i++) {
+ struct hci_xfer *xfer = xfer_list + i;
+
+ if (!xfer->data)
+ continue;
+
+ xfer->dma = hci_dma_map_xfer(dev, xfer);
+ if (!xfer->dma) {
+ hci_dma_unmap_xfer(hci, xfer_list, i);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
static int hci_dma_queue_xfer(struct i3c_hci *hci,
struct hci_xfer *xfer_list, int n)
{
struct hci_rings_data *rings = hci->io_data;
struct hci_rh_data *rh;
unsigned int i, ring, enqueue_ptr;
- u32 op1_val, op2_val;
+ u32 op1_val;
+ int ret;
+
+ ret = hci_dma_map_xfer_list(hci, rings->sysdev, xfer_list, n);
+ if (ret)
+ return ret;
/* For now we only use ring 0 */
ring = 0;
rh = &rings->headers[ring];
+ spin_lock_irq(&hci->lock);
+
+ if (n > rh->xfer_space) {
+ spin_unlock_irq(&hci->lock);
+ hci_dma_unmap_xfer(hci, xfer_list, n);
+ return -EBUSY;
+ }
+
op1_val = rh_reg_read(RING_OPERATION1);
enqueue_ptr = FIELD_GET(RING_OP1_CR_ENQ_PTR, op1_val);
for (i = 0; i < n; i++) {
struct hci_xfer *xfer = xfer_list + i;
u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr;
- enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE :
- DMA_TO_DEVICE;
- bool need_bounce;
/* store cmd descriptor */
*ring_data++ = xfer->cmd_desc[0];
@@ -477,18 +513,6 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
/* 2nd and 3rd words of Data Buffer Descriptor Structure */
if (xfer->data) {
- need_bounce = device_iommu_mapped(rings->sysdev) &&
- xfer->rnw &&
- xfer->data_len != ALIGN(xfer->data_len, 4);
- xfer->dma = i3c_master_dma_map_single(rings->sysdev,
- xfer->data,
- xfer->data_len,
- need_bounce,
- dir);
- if (!xfer->dma) {
- hci_dma_unmap_xfer(hci, xfer_list, i);
- return -ENOMEM;
- }
*ring_data++ = lower_32_bits(xfer->dma->addr);
*ring_data++ = upper_32_bits(xfer->dma->addr);
} else {
@@ -503,26 +527,14 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
xfer->ring_entry = enqueue_ptr;
enqueue_ptr = (enqueue_ptr + 1) % rh->xfer_entries;
-
- /*
- * We may update the hardware view of the enqueue pointer
- * only if we didn't reach its dequeue pointer.
- */
- op2_val = rh_reg_read(RING_OPERATION2);
- if (enqueue_ptr == FIELD_GET(RING_OP2_CR_DEQ_PTR, op2_val)) {
- /* the ring is full */
- hci_dma_unmap_xfer(hci, xfer_list, i + 1);
- return -EBUSY;
- }
}
- /* take care to update the hardware enqueue pointer atomically */
- spin_lock_irq(&rh->lock);
- op1_val = rh_reg_read(RING_OPERATION1);
+ rh->xfer_space -= n;
+
op1_val &= ~RING_OP1_CR_ENQ_PTR;
op1_val |= FIELD_PREP(RING_OP1_CR_ENQ_PTR, enqueue_ptr);
rh_reg_write(RING_OPERATION1, op1_val);
- spin_unlock_irq(&rh->lock);
+ spin_unlock_irq(&hci->lock);
return 0;
}
@@ -534,18 +546,29 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number];
unsigned int i;
bool did_unqueue = false;
-
- /* stop the ring */
- rh_reg_write(RING_CONTROL, RING_CTRL_ABORT);
- if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) {
- /*
- * We're deep in it if ever this condition is ever met.
- * Hardware might still be writing to memory, etc.
- */
- dev_crit(&hci->master.dev, "unable to abort the ring\n");
- WARN_ON(1);
+ u32 ring_status;
+
+ guard(mutex)(&hci->control_mutex);
+
+ ring_status = rh_reg_read(RING_STATUS);
+ if (ring_status & RING_STATUS_RUNNING) {
+ /* stop the ring */
+ reinit_completion(&rh->op_done);
+ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT);
+ wait_for_completion_timeout(&rh->op_done, HZ);
+ ring_status = rh_reg_read(RING_STATUS);
+ if (ring_status & RING_STATUS_RUNNING) {
+ /*
+ * We're deep in it if ever this condition is ever met.
+ * Hardware might still be writing to memory, etc.
+ */
+ dev_crit(&hci->master.dev, "unable to abort the ring\n");
+ WARN_ON(1);
+ }
}
+ spin_lock_irq(&hci->lock);
+
for (i = 0; i < n; i++) {
struct hci_xfer *xfer = xfer_list + i;
int idx = xfer->ring_entry;
@@ -559,7 +582,7 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
u32 *ring_data = rh->xfer + rh->xfer_struct_sz * idx;
/* store no-op cmd descriptor */
- *ring_data++ = FIELD_PREP(CMD_0_ATTR, 0x7);
+ *ring_data++ = FIELD_PREP(CMD_0_ATTR, 0x7) | FIELD_PREP(CMD_0_TID, xfer->cmd_tid);
*ring_data++ = 0;
if (hci->cmd == &mipi_i3c_hci_cmd_v2) {
*ring_data++ = 0;
@@ -577,15 +600,25 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
}
/* restart the ring */
+ mipi_i3c_hci_resume(hci);
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE);
+ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_RUN_STOP);
+
+ spin_unlock_irq(&hci->lock);
return did_unqueue;
}
+static int hci_dma_handle_error(struct i3c_hci *hci, struct hci_xfer *xfer_list, int n)
+{
+ return hci_dma_dequeue_xfer(hci, xfer_list, n) ? -EIO : 0;
+}
+
static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh)
{
u32 op1_val, op2_val, resp, *ring_resp;
unsigned int tid, done_ptr = rh->done_ptr;
+ unsigned int done_cnt = 0;
struct hci_xfer *xfer;
for (;;) {
@@ -603,6 +636,7 @@ static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh)
dev_dbg(&hci->master.dev, "orphaned ring entry");
} else {
hci_dma_unmap_xfer(hci, xfer, 1);
+ rh->src_xfers[done_ptr] = NULL;
xfer->ring_entry = -1;
xfer->response = resp;
if (tid != xfer->cmd_tid) {
@@ -617,15 +651,14 @@ static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh)
done_ptr = (done_ptr + 1) % rh->xfer_entries;
rh->done_ptr = done_ptr;
+ done_cnt += 1;
}
- /* take care to update the software dequeue pointer atomically */
- spin_lock(&rh->lock);
+ rh->xfer_space += done_cnt;
op1_val = rh_reg_read(RING_OPERATION1);
op1_val &= ~RING_OP1_CR_SW_DEQ_PTR;
op1_val |= FIELD_PREP(RING_OP1_CR_SW_DEQ_PTR, done_ptr);
rh_reg_write(RING_OPERATION1, op1_val);
- spin_unlock(&rh->lock);
}
static int hci_dma_request_ibi(struct i3c_hci *hci, struct i3c_dev_desc *dev,
@@ -805,13 +838,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
i3c_master_queue_ibi(dev, slot);
done:
- /* take care to update the ibi dequeue pointer atomically */
- spin_lock(&rh->lock);
op1_val = rh_reg_read(RING_OPERATION1);
op1_val &= ~RING_OP1_IBI_DEQ_PTR;
op1_val |= FIELD_PREP(RING_OP1_IBI_DEQ_PTR, deq_ptr);
rh_reg_write(RING_OPERATION1, op1_val);
- spin_unlock(&rh->lock);
/* update the chunk pointer */
rh->ibi_chunk_ptr += ibi_chunks;
@@ -845,29 +875,8 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
hci_dma_xfer_done(hci, rh);
if (status & INTR_RING_OP)
complete(&rh->op_done);
-
- if (status & INTR_TRANSFER_ABORT) {
- u32 ring_status;
-
- dev_notice_ratelimited(&hci->master.dev,
- "Ring %d: Transfer Aborted\n", i);
- mipi_i3c_hci_resume(hci);
- ring_status = rh_reg_read(RING_STATUS);
- if (!(ring_status & RING_STATUS_RUNNING) &&
- status & INTR_TRANSFER_COMPLETION &&
- status & INTR_TRANSFER_ERR) {
- /*
- * Ring stop followed by run is an Intel
- * specific required quirk after resuming the
- * halted controller. Do it only when the ring
- * is not in running state after a transfer
- * error.
- */
- rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE);
- rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE |
- RING_CTRL_RUN_STOP);
- }
- }
+ if (status & INTR_TRANSFER_ABORT)
+ dev_dbg(&hci->master.dev, "Ring %d: Transfer Aborted\n", i);
if (status & INTR_IBI_RING_FULL)
dev_err_ratelimited(&hci->master.dev,
"Ring %d: IBI Ring Full Condition\n", i);
@@ -883,6 +892,7 @@ const struct hci_io_ops mipi_i3c_hci_dma = {
.cleanup = hci_dma_cleanup,
.queue_xfer = hci_dma_queue_xfer,
.dequeue_xfer = hci_dma_dequeue_xfer,
+ .handle_error = hci_dma_handle_error,
.irq_handler = hci_dma_irq_handler,
.request_ibi = hci_dma_request_ibi,
.free_ibi = hci_dma_free_ibi,
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index 337b7ab1cb06..9ac9d0e342f4 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -50,6 +50,8 @@ struct i3c_hci {
const struct hci_io_ops *io;
void *io_data;
const struct hci_cmd_ops *cmd;
+ spinlock_t lock;
+ struct mutex control_mutex;
atomic_t next_cmd_tid;
bool irq_inactive;
u32 caps;
@@ -87,6 +89,7 @@ struct hci_xfer {
unsigned int data_len;
unsigned int cmd_tid;
struct completion *completion;
+ unsigned long timeout;
union {
struct {
/* PIO specific */
@@ -120,6 +123,7 @@ struct hci_io_ops {
bool (*irq_handler)(struct i3c_hci *hci);
int (*queue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
bool (*dequeue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
+ int (*handle_error)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
int (*request_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev,
const struct i3c_ibi_setup *req);
void (*free_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev);
@@ -154,5 +158,6 @@ void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci);
void amd_set_od_pp_timing(struct i3c_hci *hci);
void amd_set_resp_buf_thld(struct i3c_hci *hci);
void i3c_hci_sync_irq_inactive(struct i3c_hci *hci);
+int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
#endif
diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c
index f8825ac81408..8f48a81e65ab 100644
--- a/drivers/i3c/master/mipi-i3c-hci/pio.c
+++ b/drivers/i3c/master/mipi-i3c-hci/pio.c
@@ -123,7 +123,6 @@ struct hci_pio_ibi_data {
};
struct hci_pio_data {
- spinlock_t lock;
struct hci_xfer *curr_xfer, *xfer_queue;
struct hci_xfer *curr_rx, *rx_queue;
struct hci_xfer *curr_tx, *tx_queue;
@@ -212,7 +211,6 @@ static int hci_pio_init(struct i3c_hci *hci)
return -ENOMEM;
hci->io_data = pio;
- spin_lock_init(&pio->lock);
__hci_pio_init(hci, &size_val);
@@ -631,7 +629,7 @@ static int hci_pio_queue_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
xfer[i].data_left = xfer[i].data_len;
}
- spin_lock_irq(&pio->lock);
+ spin_lock_irq(&hci->lock);
prev_queue_tail = pio->xfer_queue;
pio->xfer_queue = &xfer[n - 1];
if (pio->curr_xfer) {
@@ -645,7 +643,7 @@ static int hci_pio_queue_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
pio_reg_read(INTR_STATUS),
pio_reg_read(INTR_SIGNAL_ENABLE));
}
- spin_unlock_irq(&pio->lock);
+ spin_unlock_irq(&hci->lock);
return 0;
}
@@ -716,14 +714,14 @@ static bool hci_pio_dequeue_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int
struct hci_pio_data *pio = hci->io_data;
int ret;
- spin_lock_irq(&pio->lock);
+ spin_lock_irq(&hci->lock);
dev_dbg(&hci->master.dev, "n=%d status=%#x/%#x", n,
pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
dev_dbg(&hci->master.dev, "main_status = %#x/%#x",
readl(hci->base_regs + 0x20), readl(hci->base_regs + 0x28));
ret = hci_pio_dequeue_xfer_common(hci, pio, xfer, n);
- spin_unlock_irq(&pio->lock);
+ spin_unlock_irq(&hci->lock);
return ret;
}
@@ -1016,15 +1014,12 @@ static bool hci_pio_irq_handler(struct i3c_hci *hci)
struct hci_pio_data *pio = hci->io_data;
u32 status;
- spin_lock(&pio->lock);
status = pio_reg_read(INTR_STATUS);
dev_dbg(&hci->master.dev, "PIO_INTR_STATUS %#x/%#x",
status, pio->enabled_irqs);
status &= pio->enabled_irqs | STAT_LATENCY_WARNINGS;
- if (!status) {
- spin_unlock(&pio->lock);
+ if (!status)
return false;
- }
if (status & STAT_IBI_STATUS_THLD)
hci_pio_process_ibi(hci, pio);
@@ -1058,7 +1053,6 @@ static bool hci_pio_irq_handler(struct i3c_hci *hci)
pio_reg_write(INTR_SIGNAL_ENABLE, pio->enabled_irqs);
dev_dbg(&hci->master.dev, "PIO_INTR_STATUS %#x/%#x",
pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
- spin_unlock(&pio->lock);
return true;
}
diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c
index 9f5d4d2cb325..83dcac17a042 100644
--- a/drivers/iio/accel/adxl313_core.c
+++ b/drivers/iio/accel/adxl313_core.c
@@ -998,6 +998,8 @@ static int adxl313_buffer_predisable(struct iio_dev *indio_dev)
ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_BYPASS));
+ if (ret)
+ return ret;
ret = regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0);
if (ret)
diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c
index 1c1d64d5cbcb..8f90c58f4100 100644
--- a/drivers/iio/accel/adxl355_core.c
+++ b/drivers/iio/accel/adxl355_core.c
@@ -745,7 +745,7 @@ static const struct iio_chan_spec adxl355_channels[] = {
BIT(IIO_CHAN_INFO_OFFSET),
.scan_index = 3,
.scan_type = {
- .sign = 's',
+ .sign = 'u',
.realbits = 12,
.storagebits = 16,
.endianness = IIO_BE,
diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c
index 8fab2fdbe147..a51d1d61c412 100644
--- a/drivers/iio/accel/adxl380.c
+++ b/drivers/iio/accel/adxl380.c
@@ -877,7 +877,7 @@ static int adxl380_set_fifo_samples(struct adxl380_state *st)
ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG,
ADXL380_FIFO_SAMPLES_8_MSK,
FIELD_PREP(ADXL380_FIFO_SAMPLES_8_MSK,
- (fifo_samples & BIT(8))));
+ !!(fifo_samples & BIT(8))));
if (ret)
return ret;
diff --git a/drivers/iio/adc/ad4062.c b/drivers/iio/adc/ad4062.c
index dd4ad32aa6f5..8b03736d55fc 100644
--- a/drivers/iio/adc/ad4062.c
+++ b/drivers/iio/adc/ad4062.c
@@ -719,10 +719,8 @@ static int ad4062_request_irq(struct iio_dev *indio_dev)
}
st->gpo_irq[1] = true;
- return devm_request_threaded_irq(dev, ret,
- ad4062_irq_handler_drdy,
- NULL, IRQF_ONESHOT, indio_dev->name,
- indio_dev);
+ return devm_request_irq(dev, ret, ad4062_irq_handler_drdy,
+ IRQF_NO_THREAD, indio_dev->name, indio_dev);
}
static const struct iio_trigger_ops ad4062_trigger_ops = {
@@ -955,7 +953,7 @@ static int ad4062_write_raw_dispatch(struct ad4062_state *st, int val, int val2,
default:
return -EINVAL;
}
-};
+}
static int ad4062_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index fcd8aea7152e..e16dede687d3 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -531,7 +531,7 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
return ret;
}
-static void ad7768_fill_scale_tbl(struct iio_dev *dev)
+static int ad7768_fill_scale_tbl(struct iio_dev *dev)
{
struct ad7768_state *st = iio_priv(dev);
const struct iio_scan_type *scan_type;
@@ -541,6 +541,11 @@ static void ad7768_fill_scale_tbl(struct iio_dev *dev)
u64 tmp2;
scan_type = iio_get_current_scan_type(dev, &dev->channels[0]);
+ if (IS_ERR(scan_type)) {
+ dev_err(&st->spi->dev, "Failed to get scan type.\n");
+ return PTR_ERR(scan_type);
+ }
+
if (scan_type->sign == 's')
val2 = scan_type->realbits - 1;
else
@@ -565,6 +570,8 @@ static void ad7768_fill_scale_tbl(struct iio_dev *dev)
st->scale_tbl[i][0] = tmp0; /* Integer part */
st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */
}
+
+ return 0;
}
static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st,
@@ -669,7 +676,9 @@ static int ad7768_configure_dig_fil(struct iio_dev *dev,
}
/* Update scale table: scale values vary according to the precision */
- ad7768_fill_scale_tbl(dev);
+ ret = ad7768_fill_scale_tbl(dev);
+ if (ret)
+ return ret;
ad7768_fill_samp_freq_tbl(st);
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index db085dc5e526..1abbfdfcd554 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -787,7 +787,7 @@ static int ade9000_iio_push_streaming(struct iio_dev *indio_dev)
ADE9000_MIDDLE_PAGE_BIT);
if (ret) {
dev_err_ratelimited(dev, "IRQ0 WFB write fail");
- return IRQ_HANDLED;
+ return ret;
}
ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF);
@@ -1123,7 +1123,7 @@ static int ade9000_write_raw(struct iio_dev *indio_dev,
tmp &= ~ADE9000_PHASE_C_POS_BIT;
switch (tmp) {
- case ADE9000_REG_AWATTOS:
+ case ADE9000_REG_AWATT:
return regmap_write(st->regmap,
ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS,
chan->channel), val);
@@ -1706,19 +1706,19 @@ static int ade9000_probe(struct spi_device *spi)
init_completion(&st->reset_completion);
- ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev);
+ ret = devm_mutex_init(dev, &st->lock);
if (ret)
return ret;
- ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev);
+ ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev);
if (ret)
return ret;
- ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev);
+ ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev);
if (ret)
return ret;
- ret = devm_mutex_init(dev, &st->lock);
+ ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev);
if (ret)
return ret;
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 4be44c524b4d..83a9885b9ae4 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -415,6 +415,7 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
}
adc_engine_control_reg_val =
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+ adc_engine_control_reg_val &= ~ASPEED_ADC_REF_VOLTAGE;
ret = devm_regulator_get_enable_read_voltage(data->dev, "vref");
if (ret < 0 && ret != -ENODEV)
diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c
index 9efa883c277d..58103bf16aff 100644
--- a/drivers/iio/adc/nxp-sar-adc.c
+++ b/drivers/iio/adc/nxp-sar-adc.c
@@ -718,6 +718,10 @@ static int nxp_sar_adc_buffer_software_do_postenable(struct iio_dev *indio_dev)
struct nxp_sar_adc *info = iio_priv(indio_dev);
int ret;
+ info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx");
+ if (IS_ERR(info->dma_chan))
+ return PTR_ERR(info->dma_chan);
+
nxp_sar_adc_dma_channels_enable(info, *indio_dev->active_scan_mask);
nxp_sar_adc_dma_cfg(info, true);
@@ -738,6 +742,7 @@ out_stop_cyclic_dma:
out_dma_channels_disable:
nxp_sar_adc_dma_cfg(info, false);
nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask);
+ dma_release_channel(info->dma_chan);
return ret;
}
@@ -765,10 +770,6 @@ static int nxp_sar_adc_buffer_postenable(struct iio_dev *indio_dev)
unsigned long channel;
int ret;
- info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx");
- if (IS_ERR(info->dma_chan))
- return PTR_ERR(info->dma_chan);
-
info->channels_used = 0;
/*
diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c
index 28aa6b80160c..be1cc2e77862 100644
--- a/drivers/iio/adc/ti-adc161s626.c
+++ b/drivers/iio/adc/ti-adc161s626.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
@@ -70,8 +71,7 @@ struct ti_adc_data {
u8 read_size;
u8 shift;
-
- u8 buffer[16] __aligned(IIO_DMA_MINALIGN);
+ u8 buf[3] __aligned(IIO_DMA_MINALIGN);
};
static int ti_adc_read_measurement(struct ti_adc_data *data,
@@ -80,26 +80,20 @@ static int ti_adc_read_measurement(struct ti_adc_data *data,
int ret;
switch (data->read_size) {
- case 2: {
- __be16 buf;
-
- ret = spi_read(data->spi, (void *) &buf, 2);
+ case 2:
+ ret = spi_read(data->spi, data->buf, 2);
if (ret)
return ret;
- *val = be16_to_cpu(buf);
+ *val = get_unaligned_be16(data->buf);
break;
- }
- case 3: {
- __be32 buf;
-
- ret = spi_read(data->spi, (void *) &buf, 3);
+ case 3:
+ ret = spi_read(data->spi, data->buf, 3);
if (ret)
return ret;
- *val = be32_to_cpu(buf) >> 8;
+ *val = get_unaligned_be24(data->buf);
break;
- }
default:
return -EINVAL;
}
@@ -114,15 +108,20 @@ static irqreturn_t ti_adc_trigger_handler(int irq, void *private)
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct ti_adc_data *data = iio_priv(indio_dev);
- int ret;
+ struct {
+ s16 data;
+ aligned_s64 timestamp;
+ } scan = { };
+ int ret, val;
+
+ ret = ti_adc_read_measurement(data, &indio_dev->channels[0], &val);
+ if (ret)
+ goto exit_notify_done;
- ret = ti_adc_read_measurement(data, &indio_dev->channels[0],
- (int *) &data->buffer);
- if (!ret)
- iio_push_to_buffers_with_timestamp(indio_dev,
- data->buffer,
- iio_get_time_ns(indio_dev));
+ scan.data = val;
+ iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
+ exit_notify_done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c
index 6246b3cab71f..0780abd0d0db 100644
--- a/drivers/iio/adc/ti-ads1018.c
+++ b/drivers/iio/adc/ti-ads1018.c
@@ -249,7 +249,7 @@ static int ads1018_single_shot(struct ads1018 *ads1018,
struct iio_chan_spec const *chan, u16 *cnv)
{
u8 max_drate_mode = ads1018->chip_info->num_data_rate_mode_to_hz - 1;
- u8 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode];
+ u32 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode];
u8 pga_mode = ads1018->chan_data[chan->scan_index].pga_mode;
struct spi_transfer xfer[2] = {
{
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
index c9cedc59cdcd..79be71b4de96 100644
--- a/drivers/iio/adc/ti-ads1119.c
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -274,12 +274,15 @@ static int ads1119_single_conversion(struct ads1119_state *st,
ret = pm_runtime_resume_and_get(dev);
if (ret)
- goto pdown;
+ return ret;
ret = ads1119_configure_channel(st, mux, gain, datarate);
if (ret)
goto pdown;
+ if (st->client->irq)
+ reinit_completion(&st->completion);
+
ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
if (ret)
goto pdown;
@@ -735,10 +738,8 @@ static int ads1119_probe(struct i2c_client *client)
return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n");
if (client->irq > 0) {
- ret = devm_request_threaded_irq(dev, client->irq,
- ads1119_irq_handler,
- NULL, IRQF_ONESHOT,
- "ads1119", indio_dev);
+ ret = devm_request_irq(dev, client->irq, ads1119_irq_handler,
+ IRQF_NO_THREAD, "ads1119", indio_dev);
if (ret)
return dev_err_probe(dev, ret,
"Failed to allocate irq\n");
diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
index bbe1ce577789..cdc624889559 100644
--- a/drivers/iio/adc/ti-ads7950.c
+++ b/drivers/iio/adc/ti-ads7950.c
@@ -427,13 +427,15 @@ static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
+ bool state;
int ret;
mutex_lock(&st->slock);
/* If set as output, return the output */
if (st->gpio_cmd_settings_bitmask & BIT(offset)) {
- ret = st->cmd_settings_bitmask & BIT(offset);
+ state = st->cmd_settings_bitmask & BIT(offset);
+ ret = 0;
goto out;
}
@@ -444,7 +446,7 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
if (ret)
goto out;
- ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0;
+ state = (st->single_rx >> 12) & BIT(offset);
/* Revert back to original settings */
st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA;
@@ -456,7 +458,7 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
out:
mutex_unlock(&st->slock);
- return ret;
+ return ret ?: state;
}
static int ti_ads7950_get_direction(struct gpio_chip *chip,
diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c
index 70f81c4a96ba..24e0b59e2fdf 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -613,7 +613,7 @@ static int bme680_wait_for_eoc(struct bme680_data *data)
* + heater duration
*/
int wait_eoc_us = ((data->oversampling_temp + data->oversampling_press +
- data->oversampling_humid) * 1936) + (477 * 4) +
+ data->oversampling_humid) * 1963) + (477 * 4) +
(477 * 5) + 1000 + (data->heater_dur * 1000);
fsleep(wait_eoc_us);
diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c
index f692c089d17b..c92f04990c34 100644
--- a/drivers/iio/chemical/sps30_i2c.c
+++ b/drivers/iio/chemical/sps30_i2c.c
@@ -171,7 +171,7 @@ static int sps30_i2c_read_meas(struct sps30_state *state, __be32 *meas, size_t n
if (!sps30_i2c_meas_ready(state))
return -ETIMEDOUT;
- return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(num) * num);
+ return sps30_i2c_command(state, SPS30_I2C_READ_MEAS, NULL, 0, meas, sizeof(*meas) * num);
}
static int sps30_i2c_clean_fan(struct sps30_state *state)
diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c
index 008bc88590f3..a5e6bc08d5fd 100644
--- a/drivers/iio/chemical/sps30_serial.c
+++ b/drivers/iio/chemical/sps30_serial.c
@@ -303,7 +303,7 @@ static int sps30_serial_read_meas(struct sps30_state *state, __be32 *meas, size_
if (msleep_interruptible(1000))
return -EINTR;
- ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(num));
+ ret = sps30_serial_command(state, SPS30_SERIAL_READ_MEAS, NULL, 0, meas, num * sizeof(*meas));
if (ret < 0)
return ret;
/* if measurements aren't ready sensor returns empty frame */
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 5540e2d28f4a..417c4ab8c1b2 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -14,6 +14,7 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/kfifo_buf.h>
#include "hid-sensor-trigger.h"
static ssize_t _hid_sensor_set_report_latency(struct device *dev,
@@ -202,12 +203,21 @@ static void hid_sensor_set_power_work(struct work_struct *work)
_hid_sensor_power_state(attrb, true);
}
-static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
- bool state)
+static int buffer_postenable(struct iio_dev *indio_dev)
{
- return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state);
+ return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 1);
}
+static int buffer_predisable(struct iio_dev *indio_dev)
+{
+ return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 0);
+}
+
+static const struct iio_buffer_setup_ops hid_sensor_buffer_ops = {
+ .postenable = buffer_postenable,
+ .predisable = buffer_predisable,
+};
+
void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
struct hid_sensor_common *attrb)
{
@@ -219,14 +229,9 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev,
cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
- iio_triggered_buffer_cleanup(indio_dev);
}
EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID");
-static const struct iio_trigger_ops hid_sensor_trigger_ops = {
- .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
-};
-
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb)
{
@@ -239,25 +244,34 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
else
fifo_attrs = NULL;
- ret = iio_triggered_buffer_setup_ext(indio_dev,
- &iio_pollfunc_store_time, NULL,
- IIO_BUFFER_DIRECTION_IN,
- NULL, fifo_attrs);
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED;
+
+ ret = devm_iio_kfifo_buffer_setup_ext(&indio_dev->dev, indio_dev,
+ &hid_sensor_buffer_ops,
+ fifo_attrs);
if (ret) {
- dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n");
+ dev_err(&indio_dev->dev, "Kfifo Buffer Setup Failed\n");
return ret;
}
+ /*
+ * The current user space in distro "iio-sensor-proxy" is not working in
+ * trigerless mode and it expects
+ * /sys/bus/iio/devices/iio:device0/trigger/current_trigger.
+ * The change replacing iio_triggered_buffer_setup_ext() with
+ * devm_iio_kfifo_buffer_setup_ext() will not create attribute without
+ * registering a trigger with INDIO_HARDWARE_TRIGGERED.
+ * So the below code fragment is still required.
+ */
+
trig = iio_trigger_alloc(indio_dev->dev.parent,
"%s-dev%d", name, iio_device_id(indio_dev));
if (trig == NULL) {
dev_err(&indio_dev->dev, "Trigger Allocate Failed\n");
- ret = -ENOMEM;
- goto error_triggered_buffer_cleanup;
+ return -ENOMEM;
}
iio_trigger_set_drvdata(trig, attrb);
- trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig);
if (ret) {
@@ -284,8 +298,6 @@ error_unreg_trigger:
iio_trigger_unregister(trig);
error_free_trig:
iio_trigger_free(trig);
-error_triggered_buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID");
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
index cd47cb1c685c..6027e8d88b27 100644
--- a/drivers/iio/dac/ad5770r.c
+++ b/drivers/iio/dac/ad5770r.c
@@ -322,7 +322,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev,
chan->address,
st->transf_buf, 2);
if (ret)
- return 0;
+ return ret;
buf16 = get_unaligned_le16(st->transf_buf);
*val = buf16 >> 2;
diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c
index 6dda8918975a..c61868f2de31 100644
--- a/drivers/iio/dac/ds4424.c
+++ b/drivers/iio/dac/ds4424.c
@@ -140,7 +140,7 @@ static int ds4424_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (val < S8_MIN || val > S8_MAX)
+ if (val <= S8_MIN || val > S8_MAX)
return -EINVAL;
if (val > 0) {
diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c
index b218f0c3a0bd..faccb804a5ed 100644
--- a/drivers/iio/dac/mcp47feb02.c
+++ b/drivers/iio/dac/mcp47feb02.c
@@ -65,7 +65,7 @@
#define MCP47FEB02_MAX_SCALES_CH 3
#define MCP47FEB02_DAC_WIPER_UNLOCKED 0
#define MCP47FEB02_NORMAL_OPERATION 0
-#define MCP47FEB02_INTERNAL_BAND_GAP_mV 2440
+#define MCP47FEB02_INTERNAL_BAND_GAP_uV 2440000
#define NV_DAC_ADDR_OFFSET 0x10
enum mcp47feb02_vref_mode {
@@ -697,44 +697,40 @@ static const struct iio_chan_spec mcp47febxx_ch_template = {
};
static void mcp47feb02_init_scale(struct mcp47feb02_data *data, enum mcp47feb02_scale scale,
- int vref_mV, int scale_avail[])
+ int vref_uV, int scale_avail[])
{
u32 value_micro, value_int;
u64 tmp;
- /* vref_mV should not be negative */
- tmp = (u64)vref_mV * MICRO >> data->chip_features->resolution;
+ /* vref_uV should not be negative */
+ tmp = (u64)vref_uV * MILLI >> data->chip_features->resolution;
value_int = div_u64_rem(tmp, MICRO, &value_micro);
scale_avail[scale * 2] = value_int;
scale_avail[scale * 2 + 1] = value_micro;
}
-static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_mV,
- int vref_mV, int vref1_mV)
+static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_uV,
+ int vref_uV, int vref1_uV)
{
- struct device *dev = regmap_get_device(data->regmap);
int tmp_vref;
- mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale);
+ mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale);
if (data->use_vref)
- tmp_vref = vref_mV;
+ tmp_vref = vref_uV;
else
- tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV;
+ tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV;
mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale);
mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X2, tmp_vref * 2, data->scale);
if (data->phys_channels >= 4) {
- mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale_1);
-
- if (data->use_vref1 && vref1_mV <= 0)
- return dev_err_probe(dev, vref1_mV, "Invalid voltage for Vref1\n");
+ mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale_1);
if (data->use_vref1)
- tmp_vref = vref1_mV;
+ tmp_vref = vref1_uV;
else
- tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV;
+ tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV;
mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1,
tmp_vref, data->scale_1);
@@ -955,8 +951,6 @@ static int mcp47feb02_parse_fw(struct iio_dev *indio_dev,
u32 num_channels;
u8 chan_idx = 0;
- guard(mutex)(&data->lock);
-
num_channels = device_get_child_node_count(dev);
if (num_channels > chip_features->phys_channels)
return dev_err_probe(dev, -EINVAL, "More channels than the chip supports\n");
@@ -1080,8 +1074,8 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data)
return 0;
}
-static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV,
- int vref_mV, int vref1_mV)
+static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_uV,
+ int vref_uV, int vref1_uV)
{
unsigned int i;
@@ -1089,7 +1083,7 @@ static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV,
struct device *dev = regmap_get_device(data->regmap);
int ret;
- ret = mcp47feb02_init_scales_avail(data, vdd_mV, vref_mV, vref1_mV);
+ ret = mcp47feb02_init_scales_avail(data, vdd_uV, vref_uV, vref1_uV);
if (ret)
return dev_err_probe(dev, ret, "failed to init scales for ch %u\n", i);
}
@@ -1103,10 +1097,7 @@ static int mcp47feb02_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct mcp47feb02_data *data;
struct iio_dev *indio_dev;
- int vref1_mV = 0;
- int vref_mV = 0;
- int vdd_mV;
- int ret;
+ int vref1_uV, vref_uV, vdd_uV, ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
@@ -1143,13 +1134,14 @@ static int mcp47feb02_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- vdd_mV = ret / MILLI;
+ vdd_uV = ret;
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret > 0) {
- vref_mV = ret / MILLI;
+ vref_uV = ret;
data->use_vref = true;
} else {
+ vref_uV = 0;
dev_dbg(dev, "using internal band gap as voltage reference.\n");
dev_dbg(dev, "Vref is unavailable.\n");
}
@@ -1157,9 +1149,10 @@ static int mcp47feb02_probe(struct i2c_client *client)
if (chip_features->have_ext_vref1) {
ret = devm_regulator_get_enable_read_voltage(dev, "vref1");
if (ret > 0) {
- vref1_mV = ret / MILLI;
+ vref1_uV = ret;
data->use_vref1 = true;
} else {
+ vref1_uV = 0;
dev_dbg(dev, "using internal band gap as voltage reference 1.\n");
dev_dbg(dev, "Vref1 is unavailable.\n");
}
@@ -1169,7 +1162,7 @@ static int mcp47feb02_probe(struct i2c_client *client)
if (ret)
return dev_err_probe(dev, ret, "Error initialising vref register\n");
- ret = mcp47feb02_init_ch_scales(data, vdd_mV, vref_mV, vref1_mV);
+ ret = mcp47feb02_init_ch_scales(data, vdd_uV, vref_uV, vref1_uV);
if (ret)
return ret;
diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c
index fa686f785fa4..8e2da218d48a 100644
--- a/drivers/iio/frequency/adf4377.c
+++ b/drivers/iio/frequency/adf4377.c
@@ -508,7 +508,7 @@ static int adf4377_soft_reset(struct adf4377_state *st)
return ret;
return regmap_read_poll_timeout(st->regmap, 0x0, read_val,
- !(read_val & (ADF4377_0000_SOFT_RESET_R_MSK |
+ !(read_val & (ADF4377_0000_SOFT_RESET_MSK |
ADF4377_0000_SOFT_RESET_R_MSK)), 200, 200 * 100);
}
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index ee2fcd20545d..d84e04e4b431 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -322,7 +322,9 @@ static int mpu3050_read_raw(struct iio_dev *indio_dev,
}
case IIO_CHAN_INFO_RAW:
/* Resume device */
- pm_runtime_get_sync(mpu3050->dev);
+ ret = pm_runtime_resume_and_get(mpu3050->dev);
+ if (ret)
+ return ret;
mutex_lock(&mpu3050->lock);
ret = mpu3050_set_8khz_samplerate(mpu3050);
@@ -647,14 +649,20 @@ out_trigger_unlock:
static int mpu3050_buffer_preenable(struct iio_dev *indio_dev)
{
struct mpu3050 *mpu3050 = iio_priv(indio_dev);
+ int ret;
- pm_runtime_get_sync(mpu3050->dev);
+ ret = pm_runtime_resume_and_get(mpu3050->dev);
+ if (ret)
+ return ret;
/* Unless we have OUR trigger active, run at full speed */
- if (!mpu3050->hw_irq_trigger)
- return mpu3050_set_8khz_samplerate(mpu3050);
+ if (!mpu3050->hw_irq_trigger) {
+ ret = mpu3050_set_8khz_samplerate(mpu3050);
+ if (ret)
+ pm_runtime_put_autosuspend(mpu3050->dev);
+ }
- return 0;
+ return ret;
}
static int mpu3050_buffer_postdisable(struct iio_dev *indio_dev)
@@ -1121,11 +1129,16 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq)
ret = iio_trigger_register(mpu3050->trig);
if (ret)
- return ret;
+ goto err_iio_trigger;
indio_dev->trig = iio_trigger_get(mpu3050->trig);
return 0;
+
+err_iio_trigger:
+ free_irq(mpu3050->irq, mpu3050->trig);
+
+ return ret;
}
int mpu3050_common_probe(struct device *dev,
@@ -1213,12 +1226,6 @@ int mpu3050_common_probe(struct device *dev,
goto err_power_down;
}
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(dev, "device register failed\n");
- goto err_cleanup_buffer;
- }
-
dev_set_drvdata(dev, indio_dev);
/* Check if we have an assigned IRQ to use as trigger */
@@ -1241,9 +1248,20 @@ int mpu3050_common_probe(struct device *dev,
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "device register failed\n");
+ goto err_iio_device_register;
+ }
+
return 0;
-err_cleanup_buffer:
+err_iio_device_register:
+ pm_runtime_get_sync(dev);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_disable(dev);
+ if (irq)
+ free_irq(mpu3050->irq, mpu3050->trig);
iio_triggered_buffer_cleanup(indio_dev);
err_power_down:
mpu3050_power_down(mpu3050);
@@ -1256,13 +1274,13 @@ void mpu3050_common_remove(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct mpu3050 *mpu3050 = iio_priv(indio_dev);
+ iio_device_unregister(indio_dev);
pm_runtime_get_sync(dev);
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
- iio_triggered_buffer_cleanup(indio_dev);
if (mpu3050->irq)
- free_irq(mpu3050->irq, mpu3050);
- iio_device_unregister(indio_dev);
+ free_irq(mpu3050->irq, mpu3050->trig);
+ iio_triggered_buffer_cleanup(indio_dev);
mpu3050_power_down(mpu3050);
}
diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c
index 092878f2c886..6549b22e643d 100644
--- a/drivers/iio/gyro/mpu3050-i2c.c
+++ b/drivers/iio/gyro/mpu3050-i2c.c
@@ -19,8 +19,7 @@ static int mpu3050_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id)
struct mpu3050 *mpu3050 = i2c_mux_priv(mux);
/* Just power up the device, that is all that is needed */
- pm_runtime_get_sync(mpu3050->dev);
- return 0;
+ return pm_runtime_resume_and_get(mpu3050->dev);
}
static int mpu3050_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id)
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index d160147cce0b..a2bc1d14ed91 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -526,7 +526,7 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
adis->spi = spi;
adis->data = data;
- if (!adis->ops->write && !adis->ops->read && !adis->ops->reset)
+ if (!adis->ops)
adis->ops = &adis_default_ops;
else if (!adis->ops->write || !adis->ops->read || !adis->ops->reset)
return -EINVAL;
diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c
index 28f0dbd0226c..1f2af506f4bd 100644
--- a/drivers/iio/imu/adis16550.c
+++ b/drivers/iio/imu/adis16550.c
@@ -643,12 +643,12 @@ static int adis16550_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
switch (chan->type) {
case IIO_ANGL_VEL:
- ret = adis16550_get_accl_filter_freq(st, val);
+ ret = adis16550_get_gyro_filter_freq(st, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_ACCEL:
- ret = adis16550_get_gyro_filter_freq(st, val);
+ ret = adis16550_get_accl_filter_freq(st, val);
if (ret)
return ret;
return IIO_VAL_INT;
@@ -681,9 +681,9 @@ static int adis16550_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
switch (chan->type) {
case IIO_ANGL_VEL:
- return adis16550_set_accl_filter_freq(st, val);
- case IIO_ACCEL:
return adis16550_set_gyro_filter_freq(st, val);
+ case IIO_ACCEL:
+ return adis16550_set_accl_filter_freq(st, val);
default:
return -EINVAL;
}
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index 5f47708b4c5d..4abb83b75e2e 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -573,12 +573,16 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin,
int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT;
int_latch_mask = BMI160_INT1_LATCH_MASK;
int_map_mask = BMI160_INT1_MAP_DRDY_EN;
+ pin_name = "INT1";
break;
case BMI160_PIN_INT2:
int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT;
int_latch_mask = BMI160_INT2_LATCH_MASK;
int_map_mask = BMI160_INT2_MAP_DRDY_EN;
+ pin_name = "INT2";
break;
+ default:
+ return -EINVAL;
}
int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK << int_out_ctrl_shift;
@@ -612,17 +616,8 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin,
ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_MAP,
int_map_mask, int_map_mask,
write_usleep);
- if (ret) {
- switch (pin) {
- case BMI160_PIN_INT1:
- pin_name = "INT1";
- break;
- case BMI160_PIN_INT2:
- pin_name = "INT2";
- break;
- }
+ if (ret)
dev_err(dev, "Failed to configure %s IRQ pin", pin_name);
- }
return ret;
}
diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c
index 303bc308f80a..c96fec2ebb3e 100644
--- a/drivers/iio/imu/bno055/bno055.c
+++ b/drivers/iio/imu/bno055/bno055.c
@@ -64,7 +64,7 @@
#define BNO055_GRAVITY_DATA_X_LSB_REG 0x2E
#define BNO055_GRAVITY_DATA_Y_LSB_REG 0x30
#define BNO055_GRAVITY_DATA_Z_LSB_REG 0x32
-#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2)
+#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2 + 1)
#define BNO055_TEMP_REG 0x34
#define BNO055_CALIB_STAT_REG 0x35
#define BNO055_CALIB_STAT_MAGN_SHIFT 0
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 54760d8f92a2..0ab6eddf0543 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -651,6 +651,8 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev,
return -EINVAL;
conf.odr = inv_icm42600_accel_odr_conv[idx / 2];
+ if (conf.odr == st->conf.accel.odr)
+ return 0;
pm_runtime_get_sync(dev);
mutex_lock(&st->lock);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index ada968be954d..68a395758031 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -371,6 +371,8 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *sensor_st = iio_priv(indio_dev);
+ struct inv_sensors_timestamp *ts = &sensor_st->ts;
struct device *dev = regmap_get_device(st->map);
unsigned int sensor;
unsigned int *watermark;
@@ -392,6 +394,8 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
mutex_lock(&st->lock);
+ inv_sensors_timestamp_apply_odr(ts, 0, 0, 0);
+
ret = inv_icm42600_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
if (ret)
goto out_unlock;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 7ef0a25ec74f..11339ddf1da3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -358,6 +358,8 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev,
return -EINVAL;
conf.odr = inv_icm42600_gyro_odr_conv[idx / 2];
+ if (conf.odr == st->conf.gyro.odr)
+ return 0;
pm_runtime_get_sync(dev);
mutex_lock(&st->lock);
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600.h b/drivers/iio/imu/inv_icm45600/inv_icm45600.h
index c5b5446f6c3b..1c796d4b2a40 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600.h
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600.h
@@ -205,7 +205,7 @@ struct inv_icm45600_sensor_state {
#define INV_ICM45600_SPI_SLEW_RATE_38NS 0
#define INV_ICM45600_REG_INT1_CONFIG2 0x0018
-#define INV_ICM45600_INT1_CONFIG2_PUSH_PULL BIT(2)
+#define INV_ICM45600_INT1_CONFIG2_OPEN_DRAIN BIT(2)
#define INV_ICM45600_INT1_CONFIG2_LATCHED BIT(1)
#define INV_ICM45600_INT1_CONFIG2_ACTIVE_HIGH BIT(0)
#define INV_ICM45600_INT1_CONFIG2_ACTIVE_LOW 0x00
diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
index 25bd9757a594..d49053161a65 100644
--- a/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
+++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_core.c
@@ -637,8 +637,8 @@ static int inv_icm45600_irq_init(struct inv_icm45600_state *st, int irq,
break;
}
- if (!open_drain)
- val |= INV_ICM45600_INT1_CONFIG2_PUSH_PULL;
+ if (open_drain)
+ val |= INV_ICM45600_INT1_CONFIG2_OPEN_DRAIN;
ret = regmap_write(st->map, INV_ICM45600_REG_INT1_CONFIG2, val);
if (ret)
@@ -744,6 +744,11 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi
*/
fsleep(5 * USEC_PER_MSEC);
+ /* set pm_runtime active early for disable vddio resource cleanup */
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ return ret;
+
ret = inv_icm45600_enable_regulator_vddio(st);
if (ret)
return ret;
@@ -776,7 +781,7 @@ int inv_icm45600_core_probe(struct regmap *regmap, const struct inv_icm45600_chi
if (ret)
return ret;
- ret = devm_pm_runtime_set_active_enabled(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index b2fa1f4957a5..5796896d54cd 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -1943,6 +1943,14 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
irq_type);
return -EINVAL;
}
+
+ /*
+ * Acking interrupts by status register does not work reliably
+ * but seem to work when this bit is set.
+ */
+ if (st->chip_type == INV_MPU9150)
+ st->irq_mask |= INV_MPU6050_INT_RD_CLEAR;
+
device_set_wakeup_capable(dev, true);
st->vdd_supply = devm_regulator_get(dev, "vdd");
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index 211901f8b8eb..6239b1a803f7 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -390,6 +390,8 @@ struct inv_mpu6050_state {
/* enable level triggering */
#define INV_MPU6050_LATCH_INT_EN 0x20
#define INV_MPU6050_BIT_BYPASS_EN 0x2
+/* allow acking interrupts by any register read */
+#define INV_MPU6050_INT_RD_CLEAR 0x10
/* Allowed timestamp period jitter in percent */
#define INV_MPU6050_TS_PERIOD_JITTER 4
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index 10a473342075..22c1ce66f99e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -248,7 +248,6 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p)
switch (st->chip_type) {
case INV_MPU6000:
case INV_MPU6050:
- case INV_MPU9150:
/*
* WoM is not supported and interrupt status read seems to be broken for
* some chips. Since data ready is the only interrupt, bypass interrupt
@@ -257,6 +256,10 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p)
wom_bits = 0;
int_status = INV_MPU6050_BIT_RAW_DATA_RDY_INT;
goto data_ready_interrupt;
+ case INV_MPU9150:
+ /* IRQ needs to be acked */
+ wom_bits = 0;
+ break;
case INV_MPU6500:
case INV_MPU6515:
case INV_MPU6880:
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 55d877745575..5b28a3ffcc3d 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -225,6 +225,10 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
const struct st_lsm6dsx_reg *batch_reg;
u8 data;
+ /* Only internal sensors have a FIFO ODR configuration register. */
+ if (sensor->id >= ARRAY_SIZE(hw->settings->batch))
+ return 0;
+
batch_reg = &hw->settings->batch[sensor->id];
if (batch_reg->addr) {
int val;
@@ -858,12 +862,21 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
int i, ret;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ const struct iio_dev_attr **attrs;
+
if (!hw->iio_devs[i])
continue;
+ /*
+ * For the accelerometer, allow setting FIFO sampling frequency
+ * values different from the sensor sampling frequency, which
+ * may be needed to keep FIFO data rate low while sampling
+ * acceleration data at high rates for accurate event detection.
+ */
+ attrs = i == ST_LSM6DSX_ID_ACC ? st_lsm6dsx_buffer_attrs : NULL;
ret = devm_iio_kfifo_buffer_setup_ext(hw->dev, hw->iio_devs[i],
&st_lsm6dsx_buffer_ops,
- st_lsm6dsx_buffer_attrs);
+ attrs);
if (ret)
return ret;
}
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index f15a180dc49e..46f36a6ed271 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -228,8 +228,10 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf,
written = 0;
add_wait_queue(&rb->pollq, &wait);
do {
- if (!indio_dev->info)
- return -ENODEV;
+ if (!indio_dev->info) {
+ ret = -ENODEV;
+ break;
+ }
if (!iio_buffer_space_available(rb)) {
if (signal_pending(current)) {
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index 5d3c6d5276ba..a740d1f992a8 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -109,9 +109,9 @@ static int bh1780_read_raw(struct iio_dev *indio_dev,
case IIO_LIGHT:
pm_runtime_get_sync(&bh1780->client->dev);
value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
+ pm_runtime_put_autosuspend(&bh1780->client->dev);
if (value < 0)
return value;
- pm_runtime_put_autosuspend(&bh1780->client->dev);
*val = value;
return IIO_VAL_INT;
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 963747927425..16aeb17067bc 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -103,17 +103,23 @@ static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct vcnl4035_data *data = iio_priv(indio_dev);
/* Ensure naturally aligned timestamp */
- u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)] __aligned(8) = { };
+ struct {
+ u16 als_data;
+ aligned_s64 timestamp;
+ } buffer = { };
+ unsigned int val;
int ret;
- ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
+ ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, &val);
if (ret < 0) {
dev_err(&data->client->dev,
"Trigger consumer can't read from sensor.\n");
goto fail_read;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns(indio_dev));
+
+ buffer.als_data = val;
+ iio_push_to_buffers_with_timestamp(indio_dev, &buffer,
+ iio_get_time_ns(indio_dev));
fail_read:
iio_trigger_notify_done(indio_dev->trig);
@@ -381,7 +387,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
- .endianness = IIO_LE,
+ .endianness = IIO_CPU,
},
},
{
@@ -395,7 +401,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
- .endianness = IIO_LE,
+ .endianness = IIO_CPU,
},
},
};
diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c
index 6d4483c85f30..74d7246e5225 100644
--- a/drivers/iio/light/veml6070.c
+++ b/drivers/iio/light/veml6070.c
@@ -134,9 +134,7 @@ static int veml6070_read(struct veml6070_data *data)
if (ret < 0)
return ret;
- ret = (msb << 8) | lsb;
-
- return 0;
+ return (msb << 8) | lsb;
}
static const struct iio_chan_spec veml6070_channels[] = {
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index 9345fb6d5317..fb313e591e85 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -143,8 +143,7 @@ config MMC5633
tristate "MEMSIC MMC5633 3-axis magnetic sensor"
select REGMAP_I2C
select REGMAP_I3C if I3C
- depends on I2C
- depends on I3C || !I3C
+ depends on I3C_OR_I2C
help
Say yes here to build support for the MEMSIC MMC5633 3-axis
magnetic sensor.
diff --git a/drivers/iio/magnetometer/tlv493d.c b/drivers/iio/magnetometer/tlv493d.c
index ec53fd40277b..e5e050af2b74 100644
--- a/drivers/iio/magnetometer/tlv493d.c
+++ b/drivers/iio/magnetometer/tlv493d.c
@@ -171,7 +171,7 @@ static s16 tlv493d_get_channel_data(u8 *b, enum tlv493d_channels ch)
switch (ch) {
case TLV493D_AXIS_X:
val = FIELD_GET(TLV493D_BX_MAG_X_AXIS_MSB, b[TLV493D_RD_REG_BX]) << 4 |
- FIELD_GET(TLV493D_BX2_MAG_X_AXIS_LSB, b[TLV493D_RD_REG_BX2]) >> 4;
+ FIELD_GET(TLV493D_BX2_MAG_X_AXIS_LSB, b[TLV493D_RD_REG_BX2]);
break;
case TLV493D_AXIS_Y:
val = FIELD_GET(TLV493D_BY_MAG_Y_AXIS_MSB, b[TLV493D_RD_REG_BY]) << 4 |
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index e759f91a710a..5a5e6e4fbe34 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -19,8 +19,13 @@ struct dev_rot_state {
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info quaternion;
struct {
- s32 sampled_vals[4];
- aligned_s64 timestamp;
+ IIO_DECLARE_QUATERNION(s32, sampled_vals);
+ /*
+ * ABI regression avoidance: There are two copies of the same
+ * timestamp in case of userspace depending on broken alignment
+ * from older kernels.
+ */
+ aligned_s64 timestamp[2];
} scan;
int scale_pre_decml;
int scale_post_decml;
@@ -154,8 +159,19 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
if (!rot_state->timestamp)
rot_state->timestamp = iio_get_time_ns(indio_dev);
- iio_push_to_buffers_with_timestamp(indio_dev, &rot_state->scan,
- rot_state->timestamp);
+ /*
+ * ABI regression avoidance: IIO previously had an incorrect
+ * implementation of iio_push_to_buffers_with_timestamp() that
+ * put the timestamp in the last 8 bytes of the buffer, which
+ * was incorrect according to the IIO ABI. To avoid breaking
+ * userspace that may be depending on this broken behavior, we
+ * put the timestamp in both the correct place [0] and the old
+ * incorrect place [1].
+ */
+ rot_state->scan.timestamp[0] = rot_state->timestamp;
+ rot_state->scan.timestamp[1] = rot_state->timestamp;
+
+ iio_push_to_buffers(indio_dev, &rot_state->scan);
rot_state->timestamp = 0;
}
diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c
index ad082827aad5..56c9111ef5e8 100644
--- a/drivers/iio/potentiometer/mcp4131.c
+++ b/drivers/iio/potentiometer/mcp4131.c
@@ -221,7 +221,7 @@ static int mcp4131_write_raw(struct iio_dev *indio_dev,
mutex_lock(&data->lock);
- data->buf[0] = address << MCP4131_WIPER_SHIFT;
+ data->buf[0] = address;
data->buf[0] |= MCP4131_WRITE | (val >> 8);
data->buf[1] = val & 0xFF; /* 8 bits here */
diff --git a/drivers/iio/pressure/abp2030pa.c b/drivers/iio/pressure/abp2030pa.c
index 4ca056a73cef..b44f1bf4c633 100644
--- a/drivers/iio/pressure/abp2030pa.c
+++ b/drivers/iio/pressure/abp2030pa.c
@@ -520,7 +520,7 @@ int abp2_common_probe(struct device *dev, const struct abp2_ops *ops, int irq)
data->p_offset = div_s64(odelta * data->pmin, pdelta) - data->outmin;
if (data->irq > 0) {
- ret = devm_request_irq(dev, irq, abp2_eoc_handler, IRQF_ONESHOT,
+ ret = devm_request_irq(dev, irq, abp2_eoc_handler, 0,
dev_name(dev), data);
if (ret)
return ret;
diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c
index 2918dfc0df54..17e00ee2b6f8 100644
--- a/drivers/iio/proximity/hx9023s.c
+++ b/drivers/iio/proximity/hx9023s.c
@@ -719,6 +719,9 @@ static int hx9023s_set_samp_freq(struct hx9023s_data *data, int val, int val2)
struct device *dev = regmap_get_device(data->regmap);
unsigned int i, period_ms;
+ if (!val && !val2)
+ return -EINVAL;
+
period_ms = div_u64(NANO, (val * MEGA + val2));
for (i = 0; i < ARRAY_SIZE(hx9023s_samp_freq_table); i++) {
@@ -1034,9 +1037,8 @@ static int hx9023s_send_cfg(const struct firmware *fw, struct hx9023s_data *data
if (!bin)
return -ENOMEM;
- memcpy(bin->data, fw->data, fw->size);
-
bin->fw_size = fw->size;
+ memcpy(bin->data, fw->data, bin->fw_size);
bin->fw_ver = bin->data[FW_VER_OFFSET];
bin->reg_count = get_unaligned_le16(bin->data + FW_REG_CNT_OFFSET);
diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c
index 6afdbfca3e5a..81b8daf17a54 100644
--- a/drivers/iio/proximity/rfd77402.c
+++ b/drivers/iio/proximity/rfd77402.c
@@ -173,10 +173,8 @@ static int rfd77402_wait_for_result(struct rfd77402_data *data)
struct i2c_client *client = data->client;
int val, ret;
- if (data->irq_en) {
- reinit_completion(&data->completion);
+ if (data->irq_en)
return rfd77402_wait_for_irq(data);
- }
/*
* As per RFD77402 datasheet section '3.1.1 Single Measure', the
@@ -204,6 +202,9 @@ static int rfd77402_measure(struct rfd77402_data *data)
if (ret < 0)
return ret;
+ if (data->irq_en)
+ reinit_completion(&data->completion);
+
ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R,
RFD77402_CMD_SINGLE |
RFD77402_CMD_VALID);
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 794b9778816b..78ac2ff5befd 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -6,6 +6,7 @@ menuconfig INFINIBAND
depends on INET
depends on m || IPV6 != m
depends on !ALPHA
+ select DMA_SHARED_BUFFER
select IRQ_POLL
select DIMLIB
help
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index b415d4aad04f..ee4a2bc68fb2 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -926,6 +926,13 @@ static int gid_table_setup_one(struct ib_device *ib_dev)
if (err)
return err;
+ /*
+ * Mark the device as ready for GID cache updates. This allows netdev
+ * event handlers to update the GID cache even before the device is
+ * fully registered.
+ */
+ ib_device_enable_gid_updates(ib_dev);
+
rdma_roce_rescan_device(ib_dev);
return err;
@@ -1637,6 +1644,12 @@ void ib_cache_release_one(struct ib_device *device)
void ib_cache_cleanup_one(struct ib_device *device)
{
+ /*
+ * Clear the GID updates mark first to prevent event handlers from
+ * accessing the device while it's being torn down.
+ */
+ ib_device_disable_gid_updates(device);
+
/* The cleanup function waits for all in-progress workqueue
* elements and cleans up the GID cache. This function should be
* called after the device was removed from the devices list and
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index e54c07c74575..9480d1a51c11 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -2729,6 +2729,9 @@ static int cma_listen_on_dev(struct rdma_id_private *id_priv,
*to_destroy = NULL;
if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
return 0;
+ if (id_priv->restricted_node_type != RDMA_NODE_UNSPECIFIED &&
+ id_priv->restricted_node_type != cma_dev->device->node_type)
+ return 0;
dev_id_priv =
__rdma_create_id(net, cma_listen_handler, id_priv,
@@ -2736,6 +2739,7 @@ static int cma_listen_on_dev(struct rdma_id_private *id_priv,
if (IS_ERR(dev_id_priv))
return PTR_ERR(dev_id_priv);
+ dev_id_priv->restricted_node_type = id_priv->restricted_node_type;
dev_id_priv->state = RDMA_CM_ADDR_BOUND;
memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
rdma_addr_size(cma_src_addr(id_priv)));
@@ -4194,7 +4198,7 @@ int rdma_restrict_node_type(struct rdma_cm_id *id, u8 node_type)
}
mutex_lock(&lock);
- if (id_priv->cma_dev)
+ if (READ_ONCE(id_priv->state) != RDMA_CM_IDLE)
ret = -EALREADY;
else
id_priv->restricted_node_type = node_type;
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index 05102769a918..a2c36666e6fc 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -100,6 +100,9 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
roce_netdev_callback cb,
void *cookie);
+void ib_device_enable_gid_updates(struct ib_device *device);
+void ib_device_disable_gid_updates(struct ib_device *device);
+
typedef int (*nldev_callback)(struct ib_device *device,
struct sk_buff *skb,
struct netlink_callback *cb,
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 1b5f1ee0a557..7945614be36d 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -93,6 +93,7 @@ static struct workqueue_struct *ib_unreg_wq;
static DEFINE_XARRAY_FLAGS(devices, XA_FLAGS_ALLOC);
static DECLARE_RWSEM(devices_rwsem);
#define DEVICE_REGISTERED XA_MARK_1
+#define DEVICE_GID_UPDATES XA_MARK_2
static u32 highest_client_id;
#define CLIENT_REGISTERED XA_MARK_1
@@ -508,12 +509,13 @@ static int ib_device_uevent(const struct device *device,
return 0;
}
-static const void *net_namespace(const struct device *d)
+static const struct ns_common *net_namespace(const struct device *d)
{
const struct ib_core_device *coredev =
container_of(d, struct ib_core_device, dev);
+ struct net *net = read_pnet(&coredev->rdma_net);
- return read_pnet(&coredev->rdma_net);
+ return net ? to_ns_common(net) : NULL;
}
static struct class ib_class = {
@@ -2412,11 +2414,42 @@ void ib_enum_all_roce_netdevs(roce_netdev_filter filter,
unsigned long index;
down_read(&devices_rwsem);
- xa_for_each_marked (&devices, index, dev, DEVICE_REGISTERED)
+ xa_for_each_marked(&devices, index, dev, DEVICE_GID_UPDATES)
ib_enum_roce_netdev(dev, filter, filter_cookie, cb, cookie);
up_read(&devices_rwsem);
}
+/**
+ * ib_device_enable_gid_updates - Mark device as ready for GID cache updates
+ * @device: Device to mark
+ *
+ * Called after GID table is allocated and initialized. After this mark is set,
+ * netdevice event handlers can update the device's GID cache. This allows
+ * events that arrive during device registration to be processed, avoiding
+ * stale GID entries when netdev properties change during the device
+ * registration process.
+ */
+void ib_device_enable_gid_updates(struct ib_device *device)
+{
+ down_write(&devices_rwsem);
+ xa_set_mark(&devices, device->index, DEVICE_GID_UPDATES);
+ up_write(&devices_rwsem);
+}
+
+/**
+ * ib_device_disable_gid_updates - Clear the GID updates mark
+ * @device: Device to unmark
+ *
+ * Called before GID table cleanup to prevent event handlers from accessing
+ * the device while it's being torn down.
+ */
+void ib_device_disable_gid_updates(struct ib_device *device)
+{
+ down_write(&devices_rwsem);
+ xa_clear_mark(&devices, device->index, DEVICE_GID_UPDATES);
+ up_write(&devices_rwsem);
+}
+
/*
* ib_enum_all_devs - enumerate all ib_devices
* @cb: Callback to call for each found ib_device
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index fc45c384833f..4fafe393a48c 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -608,14 +608,29 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num,
if (rdma_rw_io_needs_mr(qp->device, port_num, dir, sg_cnt)) {
ret = rdma_rw_init_mr_wrs(ctx, qp, port_num, sg, sg_cnt,
sg_offset, remote_addr, rkey, dir);
- } else if (sg_cnt > 1) {
+ /*
+ * If MR init succeeded or failed for a reason other
+ * than pool exhaustion, that result is final.
+ *
+ * Pool exhaustion (-EAGAIN) from the max_sgl_rd
+ * optimization is recoverable: fall back to
+ * direct SGE posting. iWARP and force_mr require
+ * MRs unconditionally, so -EAGAIN is terminal.
+ */
+ if (ret != -EAGAIN ||
+ rdma_protocol_iwarp(qp->device, port_num) ||
+ unlikely(rdma_rw_force_mr))
+ goto out;
+ }
+
+ if (sg_cnt > 1)
ret = rdma_rw_init_map_wrs(ctx, qp, sg, sg_cnt, sg_offset,
remote_addr, rkey, dir);
- } else {
+ else
ret = rdma_rw_init_single_wr(ctx, qp, sg, sg_offset,
remote_addr, rkey, dir);
- }
+out:
if (ret < 0)
goto out_unmap_sg;
return ret;
@@ -686,14 +701,16 @@ int rdma_rw_ctx_init_bvec(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
return ret;
/*
- * IOVA mapping not available. Check if MR registration provides
- * better performance than multiple SGE entries.
+ * IOVA not available; fall back to the map_wrs path, which maps
+ * each bvec as a direct SGE. This is always correct: the MR path
+ * is a throughput optimization, not a correctness requirement.
+ * (iWARP, which does require MRs, is handled by the check above.)
+ *
+ * The rdma_rw_io_needs_mr() gate is not used here because nr_bvec
+ * is a raw page count that overstates DMA entry demand -- the bvec
+ * caller has no post-DMA-coalescing segment count, and feeding the
+ * inflated count into the MR path exhausts the pool on RDMA READs.
*/
- if (rdma_rw_io_needs_mr(dev, port_num, dir, nr_bvec))
- return rdma_rw_init_mr_wrs_bvec(ctx, qp, port_num, bvecs,
- nr_bvec, &iter, remote_addr,
- rkey, dir);
-
return rdma_rw_init_map_wrs_bvec(ctx, qp, bvecs, nr_bvec, &iter,
remote_addr, rkey, dir);
}
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index cff4fcca2c34..edc34c69f0f2 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -55,7 +55,8 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
if (dirty)
ib_dma_unmap_sgtable_attrs(dev, &umem->sgt_append.sgt,
- DMA_BIDIRECTIONAL, 0);
+ DMA_BIDIRECTIONAL,
+ DMA_ATTR_REQUIRE_COHERENT);
for_each_sgtable_sg(&umem->sgt_append.sgt, sg, i) {
unpin_user_page_range_dirty_lock(sg_page(sg),
@@ -169,7 +170,7 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr,
unsigned long lock_limit;
unsigned long new_pinned;
unsigned long cur_base;
- unsigned long dma_attr = 0;
+ unsigned long dma_attr = DMA_ATTR_REQUIRE_COHERENT;
struct mm_struct *mm;
unsigned long npages;
int pinned, ret;
diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c
index f5298c33e581..d30f24b90bca 100644
--- a/drivers/infiniband/core/umem_dmabuf.c
+++ b/drivers/infiniband/core/umem_dmabuf.c
@@ -218,13 +218,11 @@ ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device,
err = ib_umem_dmabuf_map_pages(umem_dmabuf);
if (err)
- goto err_unpin;
+ goto err_release;
dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
return umem_dmabuf;
-err_unpin:
- dma_buf_unpin(umem_dmabuf->attach);
err_release:
dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
ib_umem_release(&umem_dmabuf->umem);
diff --git a/drivers/infiniband/core/uverbs_std_types_dmabuf.c b/drivers/infiniband/core/uverbs_std_types_dmabuf.c
index dfdfcd1d1a44..4a7f8b6f9dc8 100644
--- a/drivers/infiniband/core/uverbs_std_types_dmabuf.c
+++ b/drivers/infiniband/core/uverbs_std_types_dmabuf.c
@@ -10,6 +10,8 @@
#include "rdma_core.h"
#include "uverbs.h"
+MODULE_IMPORT_NS("DMA_BUF");
+
static int uverbs_dmabuf_attach(struct dma_buf *dmabuf,
struct dma_buf_attachment *attachment)
{
diff --git a/drivers/infiniband/hw/bng_re/bng_dev.c b/drivers/infiniband/hw/bng_re/bng_dev.c
index cf3bf08e5f26..71a7ca2196ad 100644
--- a/drivers/infiniband/hw/bng_re/bng_dev.c
+++ b/drivers/infiniband/hw/bng_re/bng_dev.c
@@ -54,9 +54,6 @@ static void bng_re_destroy_chip_ctx(struct bng_re_dev *rdev)
{
struct bng_re_chip_ctx *chip_ctx;
- if (!rdev->chip_ctx)
- return;
-
kfree(rdev->dev_attr);
rdev->dev_attr = NULL;
@@ -124,12 +121,6 @@ static int bng_re_net_ring_free(struct bng_re_dev *rdev,
struct bnge_fw_msg fw_msg = {};
int rc = -EINVAL;
- if (!rdev)
- return rc;
-
- if (!aux_dev)
- return rc;
-
bng_re_init_hwrm_hdr((void *)&req, HWRM_RING_FREE);
req.ring_type = type;
req.ring_id = cpu_to_le16(fw_ring_id);
@@ -150,10 +141,7 @@ static int bng_re_net_ring_alloc(struct bng_re_dev *rdev,
struct hwrm_ring_alloc_input req = {};
struct hwrm_ring_alloc_output resp;
struct bnge_fw_msg fw_msg = {};
- int rc = -EINVAL;
-
- if (!aux_dev)
- return rc;
+ int rc;
bng_re_init_hwrm_hdr((void *)&req, HWRM_RING_ALLOC);
req.enables = 0;
@@ -184,10 +172,7 @@ static int bng_re_stats_ctx_free(struct bng_re_dev *rdev)
struct hwrm_stat_ctx_free_input req = {};
struct hwrm_stat_ctx_free_output resp = {};
struct bnge_fw_msg fw_msg = {};
- int rc = -EINVAL;
-
- if (!aux_dev)
- return rc;
+ int rc;
bng_re_init_hwrm_hdr((void *)&req, HWRM_STAT_CTX_FREE);
req.stat_ctx_id = cpu_to_le32(rdev->stats_ctx.fw_id);
@@ -208,13 +193,10 @@ static int bng_re_stats_ctx_alloc(struct bng_re_dev *rdev)
struct hwrm_stat_ctx_alloc_output resp = {};
struct hwrm_stat_ctx_alloc_input req = {};
struct bnge_fw_msg fw_msg = {};
- int rc = -EINVAL;
+ int rc;
stats->fw_id = BNGE_INVALID_STATS_CTX_ID;
- if (!aux_dev)
- return rc;
-
bng_re_init_hwrm_hdr((void *)&req, HWRM_STAT_CTX_ALLOC);
req.update_period_ms = cpu_to_le32(1000);
req.stats_dma_addr = cpu_to_le64(stats->dma_map);
@@ -228,7 +210,7 @@ static int bng_re_stats_ctx_alloc(struct bng_re_dev *rdev)
return rc;
}
-static void bng_re_query_hwrm_version(struct bng_re_dev *rdev)
+static int bng_re_query_hwrm_version(struct bng_re_dev *rdev)
{
struct bnge_auxr_dev *aux_dev = rdev->aux_dev;
struct hwrm_ver_get_output ver_get_resp = {};
@@ -248,7 +230,7 @@ static void bng_re_query_hwrm_version(struct bng_re_dev *rdev)
if (rc) {
ibdev_err(&rdev->ibdev, "Failed to query HW version, rc = 0x%x",
rc);
- return;
+ return rc;
}
cctx = rdev->chip_ctx;
@@ -262,6 +244,8 @@ static void bng_re_query_hwrm_version(struct bng_re_dev *rdev)
if (!cctx->hwrm_cmd_max_timeout)
cctx->hwrm_cmd_max_timeout = BNG_ROCE_FW_MAX_TIMEOUT;
+
+ return 0;
}
static void bng_re_dev_uninit(struct bng_re_dev *rdev)
@@ -303,7 +287,7 @@ static int bng_re_dev_init(struct bng_re_dev *rdev)
if (rc) {
ibdev_err(&rdev->ibdev,
"Failed to register with netedev: %#x\n", rc);
- return -EINVAL;
+ goto reg_netdev_fail;
}
set_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags);
@@ -312,37 +296,34 @@ static int bng_re_dev_init(struct bng_re_dev *rdev)
ibdev_err(&rdev->ibdev,
"RoCE requires minimum 2 MSI-X vectors, but only %d reserved\n",
rdev->aux_dev->auxr_info->msix_requested);
- bnge_unregister_dev(rdev->aux_dev);
- clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags);
- return -EINVAL;
+ rc = -EINVAL;
+ goto msix_ctx_fail;
}
ibdev_dbg(&rdev->ibdev, "Got %d MSI-X vectors\n",
rdev->aux_dev->auxr_info->msix_requested);
rc = bng_re_setup_chip_ctx(rdev);
if (rc) {
- bnge_unregister_dev(rdev->aux_dev);
- clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags);
ibdev_err(&rdev->ibdev, "Failed to get chip context\n");
- return -EINVAL;
+ goto msix_ctx_fail;
}
- bng_re_query_hwrm_version(rdev);
+ rc = bng_re_query_hwrm_version(rdev);
+ if (rc)
+ goto destroy_chip_ctx;
rc = bng_re_alloc_fw_channel(&rdev->bng_res, &rdev->rcfw);
if (rc) {
ibdev_err(&rdev->ibdev,
"Failed to allocate RCFW Channel: %#x\n", rc);
- goto fail;
+ goto destroy_chip_ctx;
}
/* Allocate nq record memory */
rdev->nqr = kzalloc_obj(*rdev->nqr);
if (!rdev->nqr) {
- bng_re_destroy_chip_ctx(rdev);
- bnge_unregister_dev(rdev->aux_dev);
- clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto nq_alloc_fail;
}
rdev->nqr->num_msix = rdev->aux_dev->auxr_info->msix_requested;
@@ -411,9 +392,15 @@ disable_rcfw:
free_ring:
bng_re_net_ring_free(rdev, rdev->rcfw.creq.ring_id, type);
free_rcfw:
+ kfree(rdev->nqr);
+nq_alloc_fail:
bng_re_free_rcfw_channel(&rdev->rcfw);
-fail:
- bng_re_dev_uninit(rdev);
+destroy_chip_ctx:
+ bng_re_destroy_chip_ctx(rdev);
+msix_ctx_fail:
+ bnge_unregister_dev(rdev->aux_dev);
+ clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags);
+reg_netdev_fail:
return rc;
}
@@ -486,8 +473,7 @@ static void bng_re_remove(struct auxiliary_device *adev)
rdev = dev_info->rdev;
- if (rdev)
- bng_re_remove_device(rdev, adev);
+ bng_re_remove_device(rdev, adev);
kfree(dev_info);
}
diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c
index 229b0ad3b0cb..e97b5f0d7003 100644
--- a/drivers/infiniband/hw/efa/efa_com.c
+++ b/drivers/infiniband/hw/efa/efa_com.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
- * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include <linux/log2.h>
@@ -310,23 +310,19 @@ static inline struct efa_comp_ctx *efa_com_get_comp_ctx_by_cmd_id(struct efa_com
return &aq->comp_ctx[ctx_id];
}
-static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
- struct efa_admin_aq_entry *cmd,
- size_t cmd_size_in_bytes,
- struct efa_admin_acq_entry *comp,
- size_t comp_size_in_bytes)
+static void __efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
+ struct efa_comp_ctx *comp_ctx,
+ struct efa_admin_aq_entry *cmd,
+ size_t cmd_size_in_bytes,
+ struct efa_admin_acq_entry *comp,
+ size_t comp_size_in_bytes)
{
struct efa_admin_aq_entry *aqe;
- struct efa_comp_ctx *comp_ctx;
u16 queue_size_mask;
u16 cmd_id;
u16 ctx_id;
u16 pi;
- comp_ctx = efa_com_alloc_comp_ctx(aq);
- if (!comp_ctx)
- return ERR_PTR(-EINVAL);
-
queue_size_mask = aq->depth - 1;
pi = aq->sq.pc & queue_size_mask;
ctx_id = efa_com_get_comp_ctx_id(aq, comp_ctx);
@@ -360,8 +356,6 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queu
/* barrier not needed in case of writel */
writel(aq->sq.pc, aq->sq.db_addr);
-
- return comp_ctx;
}
static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq)
@@ -394,28 +388,25 @@ static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq)
return 0;
}
-static struct efa_comp_ctx *efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
- struct efa_admin_aq_entry *cmd,
- size_t cmd_size_in_bytes,
- struct efa_admin_acq_entry *comp,
- size_t comp_size_in_bytes)
+static int efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq,
+ struct efa_comp_ctx *comp_ctx,
+ struct efa_admin_aq_entry *cmd,
+ size_t cmd_size_in_bytes,
+ struct efa_admin_acq_entry *comp,
+ size_t comp_size_in_bytes)
{
- struct efa_comp_ctx *comp_ctx;
-
spin_lock(&aq->sq.lock);
if (!test_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state)) {
ibdev_err_ratelimited(aq->efa_dev, "Admin queue is closed\n");
spin_unlock(&aq->sq.lock);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
- comp_ctx = __efa_com_submit_admin_cmd(aq, cmd, cmd_size_in_bytes, comp,
- comp_size_in_bytes);
+ __efa_com_submit_admin_cmd(aq, comp_ctx, cmd, cmd_size_in_bytes, comp,
+ comp_size_in_bytes);
spin_unlock(&aq->sq.lock);
- if (IS_ERR(comp_ctx))
- clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- return comp_ctx;
+ return 0;
}
static int efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq,
@@ -512,7 +503,6 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
{
unsigned long timeout;
unsigned long flags;
- int err;
timeout = jiffies + usecs_to_jiffies(aq->completion_timeout);
@@ -532,24 +522,20 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c
atomic64_inc(&aq->stats.no_completion);
clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- err = -ETIME;
- goto out;
+ return -ETIME;
}
msleep(aq->poll_interval);
}
- err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status);
-out:
- efa_com_dealloc_comp_ctx(aq, comp_ctx);
- return err;
+ return efa_com_comp_status_to_errno(
+ comp_ctx->user_cqe->acq_common_descriptor.status);
}
static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *comp_ctx,
struct efa_com_admin_queue *aq)
{
unsigned long flags;
- int err;
wait_for_completion_timeout(&comp_ctx->wait_event,
usecs_to_jiffies(aq->completion_timeout));
@@ -585,14 +571,11 @@ static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *com
aq->cq.cc);
clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
- err = -ETIME;
- goto out;
+ return -ETIME;
}
- err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status);
-out:
- efa_com_dealloc_comp_ctx(aq, comp_ctx);
- return err;
+ return efa_com_comp_status_to_errno(
+ comp_ctx->user_cqe->acq_common_descriptor.status);
}
/*
@@ -642,30 +625,39 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq,
ibdev_dbg(aq->efa_dev, "%s (opcode %d)\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
cmd->aq_common_descriptor.opcode);
- comp_ctx = efa_com_submit_admin_cmd(aq, cmd, cmd_size, comp, comp_size);
- if (IS_ERR(comp_ctx)) {
+
+ comp_ctx = efa_com_alloc_comp_ctx(aq);
+ if (!comp_ctx) {
+ clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state);
+ up(&aq->avail_cmds);
+ return -EINVAL;
+ }
+
+ err = efa_com_submit_admin_cmd(aq, comp_ctx, cmd, cmd_size, comp, comp_size);
+ if (err) {
ibdev_err_ratelimited(
aq->efa_dev,
- "Failed to submit command %s (opcode %u) err %pe\n",
+ "Failed to submit command %s (opcode %u) err %d\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
- cmd->aq_common_descriptor.opcode, comp_ctx);
+ cmd->aq_common_descriptor.opcode, err);
+ efa_com_dealloc_comp_ctx(aq, comp_ctx);
up(&aq->avail_cmds);
atomic64_inc(&aq->stats.cmd_err);
- return PTR_ERR(comp_ctx);
+ return err;
}
err = efa_com_wait_and_process_admin_cq(comp_ctx, aq);
if (err) {
ibdev_err_ratelimited(
aq->efa_dev,
- "Failed to process command %s (opcode %u) comp_status %d err %d\n",
+ "Failed to process command %s (opcode %u) err %d\n",
efa_com_cmd_str(cmd->aq_common_descriptor.opcode),
- cmd->aq_common_descriptor.opcode,
- comp_ctx->user_cqe->acq_common_descriptor.status, err);
+ cmd->aq_common_descriptor.opcode, err);
atomic64_inc(&aq->stats.cmd_err);
}
+ efa_com_dealloc_comp_ctx(aq, comp_ctx);
up(&aq->avail_cmds);
return err;
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c
index b5b93b42e6c4..b0aa7c0238ed 100644
--- a/drivers/infiniband/hw/efa/efa_verbs.c
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
@@ -1661,7 +1661,7 @@ static struct efa_mr *efa_alloc_mr(struct ib_pd *ibpd, int access_flags,
struct efa_mr *mr;
if (udata && udata->inlen &&
- !ib_is_udata_cleared(udata, 0, sizeof(udata->inlen))) {
+ !ib_is_udata_cleared(udata, 0, udata->inlen)) {
ibdev_dbg(&dev->ibdev,
"Incompatible ABI params, udata not cleared\n");
return ERR_PTR(-EINVAL);
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 5b3f40bd98d8..a5671da3db64 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -508,6 +508,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev,
{
const struct ib_global_route *grh;
enum rdma_network_type net;
+ u8 smac[ETH_ALEN];
u16 vlan;
int rc;
@@ -518,7 +519,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev,
grh = rdma_ah_read_grh(attr);
- rc = rdma_read_gid_l2_fields(grh->sgid_attr, &vlan, &hdr->eth.smac_h[0]);
+ rc = rdma_read_gid_l2_fields(grh->sgid_attr, &vlan, smac);
if (rc)
return rc;
@@ -536,6 +537,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev,
if (rc)
return rc;
+ ether_addr_copy(hdr->eth.smac_h, smac);
ether_addr_copy(hdr->eth.dmac_h, attr->roce.dmac);
if (net == RDMA_NETWORK_IPV4) {
@@ -1218,7 +1220,7 @@ int ionic_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
rdma_udata_to_drv_context(udata, struct ionic_ctx, ibctx);
struct ionic_vcq *vcq = to_ionic_vcq(ibcq);
struct ionic_tbl_buf buf = {};
- struct ionic_cq_resp resp;
+ struct ionic_cq_resp resp = {};
struct ionic_cq_req req;
int udma_idx = 0, rc;
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c
index 164046d00e5d..bd4c73e530d0 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.c
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c
@@ -81,6 +81,8 @@ static int ionic_query_port(struct ib_device *ibdev, u32 port,
return -EINVAL;
ndev = ib_device_get_netdev(ibdev, port);
+ if (!ndev)
+ return -ENODEV;
if (netif_running(ndev) && netif_carrier_ok(ndev)) {
attr->state = IB_PORT_ACTIVE;
diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c
index 3d084d4ff577..91c0e7298283 100644
--- a/drivers/infiniband/hw/irdma/cm.c
+++ b/drivers/infiniband/hw/irdma/cm.c
@@ -2241,11 +2241,12 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
int oldarpindex;
int arpindex;
struct net_device *netdev = iwdev->netdev;
+ int ret;
/* create an hte and cm_node for this instance */
cm_node = kzalloc_obj(*cm_node, GFP_ATOMIC);
if (!cm_node)
- return NULL;
+ return ERR_PTR(-ENOMEM);
/* set our node specific transport info */
cm_node->ipv4 = cm_info->ipv4;
@@ -2348,8 +2349,10 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
arpindex = -EINVAL;
}
- if (arpindex < 0)
+ if (arpindex < 0) {
+ ret = -EINVAL;
goto err;
+ }
ether_addr_copy(cm_node->rem_mac,
iwdev->rf->arp_table[arpindex].mac_addr);
@@ -2360,7 +2363,7 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,
err:
kfree(cm_node);
- return NULL;
+ return ERR_PTR(ret);
}
static void irdma_destroy_connection(struct irdma_cm_node *cm_node)
@@ -3021,8 +3024,8 @@ static int irdma_create_cm_node(struct irdma_cm_core *cm_core,
/* create a CM connection node */
cm_node = irdma_make_cm_node(cm_core, iwdev, cm_info, NULL);
- if (!cm_node)
- return -ENOMEM;
+ if (IS_ERR(cm_node))
+ return PTR_ERR(cm_node);
/* set our node side to client (active) side */
cm_node->tcp_cntxt.client = 1;
@@ -3219,9 +3222,9 @@ void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf)
cm_info.cm_id = listener->cm_id;
cm_node = irdma_make_cm_node(cm_core, iwdev, &cm_info,
listener);
- if (!cm_node) {
+ if (IS_ERR(cm_node)) {
ibdev_dbg(&cm_core->iwdev->ibdev,
- "CM: allocate node failed\n");
+ "CM: allocate node failed ret=%ld\n", PTR_ERR(cm_node));
refcount_dec(&listener->refcnt);
return;
}
@@ -4239,21 +4242,21 @@ static void irdma_cm_event_handler(struct work_struct *work)
irdma_cm_event_reset(event);
break;
case IRDMA_CM_EVENT_CONNECTED:
- if (!event->cm_node->cm_id ||
- event->cm_node->state != IRDMA_CM_STATE_OFFLOADED)
+ if (!cm_node->cm_id ||
+ cm_node->state != IRDMA_CM_STATE_OFFLOADED)
break;
irdma_cm_event_connected(event);
break;
case IRDMA_CM_EVENT_MPA_REJECT:
- if (!event->cm_node->cm_id ||
+ if (!cm_node->cm_id ||
cm_node->state == IRDMA_CM_STATE_OFFLOADED)
break;
irdma_send_cm_event(cm_node, cm_node->cm_id,
IW_CM_EVENT_CONNECT_REPLY, -ECONNREFUSED);
break;
case IRDMA_CM_EVENT_ABORTED:
- if (!event->cm_node->cm_id ||
- event->cm_node->state == IRDMA_CM_STATE_OFFLOADED)
+ if (!cm_node->cm_id ||
+ cm_node->state == IRDMA_CM_STATE_OFFLOADED)
break;
irdma_event_connect_error(event);
break;
@@ -4263,7 +4266,7 @@ static void irdma_cm_event_handler(struct work_struct *work)
break;
}
- irdma_rem_ref_cm_node(event->cm_node);
+ irdma_rem_ref_cm_node(cm_node);
kfree(event);
}
diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c
index ac3721a5747a..4718acf6c6fd 100644
--- a/drivers/infiniband/hw/irdma/uk.c
+++ b/drivers/infiniband/hw/irdma/uk.c
@@ -1438,7 +1438,7 @@ exit:
* irdma_round_up_wq - return round up qp wq depth
* @wqdepth: wq depth in quanta to round up
*/
-static int irdma_round_up_wq(u32 wqdepth)
+static u64 irdma_round_up_wq(u64 wqdepth)
{
int scount = 1;
@@ -1491,15 +1491,16 @@ void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge,
int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift,
u32 *sqdepth)
{
- u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift;
+ u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift;
+ u64 hw_quanta =
+ irdma_round_up_wq(((u64)sq_size << shift) + IRDMA_SQ_RSVD);
- *sqdepth = irdma_round_up_wq((sq_size << shift) + IRDMA_SQ_RSVD);
-
- if (*sqdepth < min_size)
- *sqdepth = min_size;
- else if (*sqdepth > uk_attrs->max_hw_wq_quanta)
+ if (hw_quanta < min_hw_quanta)
+ hw_quanta = min_hw_quanta;
+ else if (hw_quanta > uk_attrs->max_hw_wq_quanta)
return -EINVAL;
+ *sqdepth = hw_quanta;
return 0;
}
@@ -1513,15 +1514,16 @@ int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift,
int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift,
u32 *rqdepth)
{
- u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift;
-
- *rqdepth = irdma_round_up_wq((rq_size << shift) + IRDMA_RQ_RSVD);
+ u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift;
+ u64 hw_quanta =
+ irdma_round_up_wq(((u64)rq_size << shift) + IRDMA_RQ_RSVD);
- if (*rqdepth < min_size)
- *rqdepth = min_size;
- else if (*rqdepth > uk_attrs->max_hw_rq_quanta)
+ if (hw_quanta < min_hw_quanta)
+ hw_quanta = min_hw_quanta;
+ else if (hw_quanta > uk_attrs->max_hw_rq_quanta)
return -EINVAL;
+ *rqdepth = hw_quanta;
return 0;
}
@@ -1535,13 +1537,16 @@ int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift,
int irdma_get_srqdepth(struct irdma_uk_attrs *uk_attrs, u32 srq_size, u8 shift,
u32 *srqdepth)
{
- *srqdepth = irdma_round_up_wq((srq_size << shift) + IRDMA_RQ_RSVD);
+ u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift;
+ u64 hw_quanta =
+ irdma_round_up_wq(((u64)srq_size << shift) + IRDMA_RQ_RSVD);
- if (*srqdepth < ((u32)uk_attrs->min_hw_wq_size << shift))
- *srqdepth = uk_attrs->min_hw_wq_size << shift;
- else if (*srqdepth > uk_attrs->max_hw_srq_quanta)
+ if (hw_quanta < min_hw_quanta)
+ hw_quanta = min_hw_quanta;
+ else if (hw_quanta > uk_attrs->max_hw_srq_quanta)
return -EINVAL;
+ *srqdepth = hw_quanta;
return 0;
}
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index ab8c5284d4be..495e5daff4b4 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -2322,8 +2322,6 @@ void irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp)
struct irdma_qp *qp = sc_qp->qp_uk.back_qp;
struct ib_qp_attr attr;
- if (qp->iwdev->rf->reset)
- return;
attr.qp_state = IB_QPS_ERR;
if (rdma_protocol_roce(qp->ibqp.device, 1))
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index 15af53237217..95f590c10c05 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -558,7 +558,8 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
}
irdma_qp_rem_ref(&iwqp->ibqp);
- wait_for_completion(&iwqp->free_qp);
+ if (!iwdev->rf->reset)
+ wait_for_completion(&iwqp->free_qp);
irdma_free_lsmm_rsrc(iwqp);
irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp);
@@ -1105,6 +1106,7 @@ static int irdma_create_qp(struct ib_qp *ibqp,
spin_lock_init(&iwqp->sc_qp.pfpdu.lock);
iwqp->sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
rf->qp_table[qp_num] = iwqp;
+ init_completion(&iwqp->free_qp);
if (udata) {
/* GEN_1 legacy support with libi40iw does not have expanded uresp struct */
@@ -1129,7 +1131,6 @@ static int irdma_create_qp(struct ib_qp *ibqp,
}
}
- init_completion(&iwqp->free_qp);
return 0;
error:
@@ -1462,8 +1463,6 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
ctx_info->remote_atomics_en = true;
}
- wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
-
ibdev_dbg(&iwdev->ibdev,
"VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d attr_mask=0x%x\n",
__builtin_return_address(0), ibqp->qp_num, attr->qp_state,
@@ -1540,6 +1539,7 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
case IB_QPS_ERR:
case IB_QPS_RESET:
if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
+ iwqp->ibqp_state = attr->qp_state;
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata && udata->inlen) {
if (ib_copy_from_udata(&ureq, udata,
@@ -1745,6 +1745,7 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
case IB_QPS_ERR:
case IB_QPS_RESET:
if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
+ iwqp->ibqp_state = attr->qp_state;
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata && udata->inlen) {
if (ib_copy_from_udata(&ureq, udata,
@@ -3723,6 +3724,7 @@ static int irdma_rereg_mr_trans(struct irdma_mr *iwmr, u64 start, u64 len,
err:
ib_umem_release(region);
+ iwmr->region = NULL;
return err;
}
@@ -5212,7 +5214,7 @@ static int irdma_create_user_ah(struct ib_ah *ibah,
#define IRDMA_CREATE_AH_MIN_RESP_LEN offsetofend(struct irdma_create_ah_resp, rsvd)
struct irdma_ah *ah = container_of(ibah, struct irdma_ah, ibah);
struct irdma_device *iwdev = to_iwdev(ibah->pd->device);
- struct irdma_create_ah_resp uresp;
+ struct irdma_create_ah_resp uresp = {};
struct irdma_ah *parent_ah;
int err;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index ef0635064fba..5c182ae4fc2f 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -428,6 +428,8 @@ static int mthca_create_srq(struct ib_srq *ibsrq,
if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof(__u32))) {
mthca_free_srq(to_mdev(ibsrq->device), srq);
+ mthca_unmap_user_db(to_mdev(ibsrq->device), &context->uar,
+ context->db_tab, ucmd.db_index);
return -EFAULT;
}
@@ -436,6 +438,7 @@ static int mthca_create_srq(struct ib_srq *ibsrq,
static int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
{
+ mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
if (udata) {
struct mthca_ucontext *context =
rdma_udata_to_drv_context(
@@ -446,8 +449,6 @@ static int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
mthca_unmap_user_db(to_mdev(srq->device), &context->uar,
context->db_tab, to_msrq(srq)->db_index);
}
-
- mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
return 0;
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 30339dcabb4d..b58868e1cf11 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -43,6 +43,7 @@
#include <linux/jiffies.h>
#include <linux/lockdep.h>
#include <linux/inet.h>
+#include <net/net_namespace.h>
#include <rdma/ib_cache.h>
#include <linux/atomic.h>
@@ -1048,7 +1049,7 @@ static void srp_remove_target(struct srp_target_port *target)
scsi_remove_host(target->scsi_host);
srp_stop_rport_timers(target->rport);
srp_disconnect_target(target);
- kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
+ kobj_ns_drop(KOBJ_NS_TYPE_NET, to_ns_common(target->net));
for (i = 0; i < target->ch_count; i++) {
ch = &target->ch[i];
srp_free_ch_ib(target, ch);
@@ -3713,7 +3714,7 @@ static ssize_t add_target_store(struct device *dev,
target = host_to_target(target_host);
- target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
+ target->net = to_net_ns(kobj_ns_grab_current(KOBJ_NS_TYPE_NET));
target->io_class = SRP_REV16A_IB_IO_CLASS;
target->scsi_host = target_host;
target->srp_host = host;
@@ -3905,7 +3906,7 @@ put:
* earlier in this function.
*/
if (target->state != SRP_TARGET_REMOVED)
- kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
+ kobj_ns_drop(KOBJ_NS_TYPE_NET, to_ns_common(target->net));
scsi_host_put(target->scsi_host);
}
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index bf4accf3f581..d6fc3d6006bb 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -313,6 +313,8 @@ static const struct xpad_device {
{ 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
{ 0x1532, 0x0a29, "Razer Wolverine V2", 0, XTYPE_XBOXONE },
+ { 0x1532, 0x0a57, "Razer Wolverine V3 Pro (Wired)", 0, XTYPE_XBOX360 },
+ { 0x1532, 0x0a59, "Razer Wolverine V3 Pro (2.4 GHz Dongle)", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 },
@@ -360,6 +362,8 @@ static const struct xpad_device {
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
{ 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 },
+ { 0x20bc, 0x5134, "BETOP BTP-KP50B Xinput Dongle", 0, XTYPE_XBOX360 },
+ { 0x20bc, 0x514a, "BETOP BTP-KP50C Xinput Dongle", 0, XTYPE_XBOX360 },
{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
@@ -562,6 +566,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */
XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */
XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */
+ XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */
XPAD_XBOX360_VENDOR(0x20d6), /* PowerA controllers */
XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA controllers */
XPAD_XBOX360_VENDOR(0x2345), /* Machenike Controllers */
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index e589060db280..d32fa4b508fc 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -25,8 +25,10 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/lockdep.h>
#include <linux/miscdevice.h>
#include <linux/overflow.h>
+#include <linux/spinlock.h>
#include <linux/input/mt.h>
#include "../input-compat.h"
@@ -57,6 +59,7 @@ struct uinput_device {
struct input_dev *dev;
struct mutex mutex;
enum uinput_state state;
+ spinlock_t state_lock;
wait_queue_head_t waitq;
unsigned char ready;
unsigned char head;
@@ -75,6 +78,8 @@ static int uinput_dev_event(struct input_dev *dev,
struct uinput_device *udev = input_get_drvdata(dev);
struct timespec64 ts;
+ lockdep_assert_held(&dev->event_lock);
+
ktime_get_ts64(&ts);
udev->buff[udev->head] = (struct input_event) {
@@ -146,27 +151,26 @@ static void uinput_request_release_slot(struct uinput_device *udev,
static int uinput_request_send(struct uinput_device *udev,
struct uinput_request *request)
{
- int retval;
+ unsigned long flags;
+ int retval = 0;
- retval = mutex_lock_interruptible(&udev->mutex);
- if (retval)
- return retval;
+ spin_lock(&udev->state_lock);
if (udev->state != UIST_CREATED) {
retval = -ENODEV;
goto out;
}
- init_completion(&request->done);
-
/*
* Tell our userspace application about this new request
* by queueing an input event.
*/
+ spin_lock_irqsave(&udev->dev->event_lock, flags);
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
+ spin_unlock_irqrestore(&udev->dev->event_lock, flags);
out:
- mutex_unlock(&udev->mutex);
+ spin_unlock(&udev->state_lock);
return retval;
}
@@ -175,6 +179,13 @@ static int uinput_request_submit(struct uinput_device *udev,
{
int retval;
+ /*
+ * Initialize completion before allocating the request slot.
+ * Once the slot is allocated, uinput_flush_requests() may
+ * complete it at any time, so it must be initialized first.
+ */
+ init_completion(&request->done);
+
retval = uinput_request_reserve_slot(udev, request);
if (retval)
return retval;
@@ -289,7 +300,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
struct input_dev *dev = udev->dev;
enum uinput_state old_state = udev->state;
+ /*
+ * Update state under state_lock so that concurrent
+ * uinput_request_send() sees the state change before we
+ * flush pending requests and tear down the device.
+ */
+ spin_lock(&udev->state_lock);
udev->state = UIST_NEW_DEVICE;
+ spin_unlock(&udev->state_lock);
if (dev) {
name = dev->name;
@@ -366,7 +384,9 @@ static int uinput_create_device(struct uinput_device *udev)
if (error)
goto fail2;
+ spin_lock(&udev->state_lock);
udev->state = UIST_CREATED;
+ spin_unlock(&udev->state_lock);
return 0;
@@ -384,6 +404,7 @@ static int uinput_open(struct inode *inode, struct file *file)
return -ENOMEM;
mutex_init(&newdev->mutex);
+ spin_lock_init(&newdev->state_lock);
spin_lock_init(&newdev->requests_lock);
init_waitqueue_head(&newdev->requests_waitq);
init_waitqueue_head(&newdev->waitq);
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 8e3cea9db365..e772bac3b64c 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -286,6 +286,8 @@ struct bcm5974 {
const struct tp_finger *index[MAX_FINGERS]; /* finger index data */
struct input_mt_pos pos[MAX_FINGERS]; /* position array */
int slots[MAX_FINGERS]; /* slot assignments */
+ struct work_struct mode_reset_work;
+ unsigned long last_mode_reset;
};
/* trackpad finger block data, le16-aligned */
@@ -696,6 +698,32 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
return retval;
}
+/*
+ * Mode switches sent before the control response are ignored.
+ * Fixing this state requires switching to normal mode and waiting
+ * about 1ms before switching back to wellspring mode.
+ */
+static void bcm5974_mode_reset_work(struct work_struct *work)
+{
+ struct bcm5974 *dev = container_of(work, struct bcm5974, mode_reset_work);
+ int error;
+
+ guard(mutex)(&dev->pm_mutex);
+ dev->last_mode_reset = jiffies;
+
+ error = bcm5974_wellspring_mode(dev, false);
+ if (error) {
+ dev_err(&dev->intf->dev, "reset to normal mode failed\n");
+ return;
+ }
+
+ fsleep(1000);
+
+ error = bcm5974_wellspring_mode(dev, true);
+ if (error)
+ dev_err(&dev->intf->dev, "mode switch after reset failed\n");
+}
+
static void bcm5974_irq_button(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
@@ -752,10 +780,20 @@ static void bcm5974_irq_trackpad(struct urb *urb)
if (dev->tp_urb->actual_length == 2)
goto exit;
- if (report_tp_state(dev, dev->tp_urb->actual_length))
+ if (report_tp_state(dev, dev->tp_urb->actual_length)) {
dprintk(1, "bcm5974: bad trackpad package, length: %d\n",
dev->tp_urb->actual_length);
+ /*
+ * Receiving a HID packet means we aren't in wellspring mode.
+ * If we haven't tried a reset in the last second, try now.
+ */
+ if (dev->tp_urb->actual_length == 8 &&
+ time_after(jiffies, dev->last_mode_reset + msecs_to_jiffies(1000))) {
+ schedule_work(&dev->mode_reset_work);
+ }
+ }
+
exit:
error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
if (error)
@@ -906,6 +944,7 @@ static int bcm5974_probe(struct usb_interface *iface,
dev->intf = iface;
dev->input = input_dev;
dev->cfg = *cfg;
+ INIT_WORK(&dev->mode_reset_work, bcm5974_mode_reset_work);
mutex_init(&dev->pm_mutex);
/* setup urbs */
@@ -998,6 +1037,7 @@ static void bcm5974_disconnect(struct usb_interface *iface)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
+ disable_work_sync(&dev->mode_reset_work);
usb_set_intfdata(iface, NULL);
input_unregister_device(dev->input);
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index ac4041a69fcd..61909e1a39e2 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -538,6 +538,8 @@ static void rmi_f54_work(struct work_struct *work)
int error;
int i;
+ mutex_lock(&f54->data_mutex);
+
report_size = rmi_f54_get_report_size(f54);
if (report_size == 0) {
dev_err(&fn->dev, "Bad report size, report type=%d\n",
@@ -546,8 +548,6 @@ static void rmi_f54_work(struct work_struct *work)
goto error; /* retry won't help */
}
- mutex_lock(&f54->data_mutex);
-
/*
* Need to check if command has completed.
* If not try again later.
diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
index d2cf940b105a..8ebdf4fb9030 100644
--- a/drivers/input/serio/i8042-acpipnpio.h
+++ b/drivers/input/serio/i8042-acpipnpio.h
@@ -1189,6 +1189,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "WUJIE Series-X5SP4NAG"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c
index 669a638bf3ef..c88327d200ac 100644
--- a/drivers/interconnect/qcom/sm8450.c
+++ b/drivers/interconnect/qcom/sm8450.c
@@ -800,7 +800,7 @@ static struct qcom_icc_node qhs_compute_cfg = {
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .link_nodes = { MASTER_CDSP_NOC_CFG },
+ .link_nodes = { &qhm_nsp_noc_config },
};
static struct qcom_icc_node qhs_cpr_cx = {
@@ -874,7 +874,7 @@ static struct qcom_icc_node qhs_lpass_cfg = {
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .link_nodes = { MASTER_CNOC_LPASS_AG_NOC },
+ .link_nodes = { &qhm_config_noc },
};
static struct qcom_icc_node qhs_mss_cfg = {
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 81c4d7733872..760d5f4623b5 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2909,8 +2909,21 @@ static struct iommu_domain blocked_domain = {
static struct protection_domain identity_domain;
+static int amd_iommu_identity_attach(struct iommu_domain *dom, struct device *dev,
+ struct iommu_domain *old)
+{
+ /*
+ * Don't allow attaching a device to the identity domain if SNP is
+ * enabled.
+ */
+ if (amd_iommu_snp_en)
+ return -EINVAL;
+
+ return amd_iommu_attach_device(dom, dev, old);
+}
+
static const struct iommu_domain_ops identity_domain_ops = {
- .attach_dev = amd_iommu_attach_device,
+ .attach_dev = amd_iommu_identity_attach,
};
void amd_iommu_init_identity_domain(void)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 5dac64be61bb..94d514169642 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1211,7 +1211,7 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
*/
if (dev_use_swiotlb(dev, size, dir) &&
iova_unaligned(iovad, phys, size)) {
- if (attrs & DMA_ATTR_MMIO)
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
return DMA_MAPPING_ERROR;
phys = iommu_dma_map_swiotlb(dev, phys, size, dir, attrs);
@@ -1223,7 +1223,8 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
arch_sync_dma_for_device(phys, size, dir);
iova = __iommu_dma_map(dev, phys, size, prot, dma_mask);
- if (iova == DMA_MAPPING_ERROR && !(attrs & DMA_ATTR_MMIO))
+ if (iova == DMA_MAPPING_ERROR &&
+ !(attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)))
swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs);
return iova;
}
@@ -1233,7 +1234,7 @@ void iommu_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle,
{
phys_addr_t phys;
- if (attrs & DMA_ATTR_MMIO) {
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) {
__iommu_dma_unmap(dev, dma_handle, size);
return;
}
@@ -1945,9 +1946,21 @@ int dma_iova_link(struct device *dev, struct dma_iova_state *state,
if (WARN_ON_ONCE(iova_start_pad && offset > 0))
return -EIO;
+ /*
+ * DMA_IOVA_USE_SWIOTLB is set on state after some entry
+ * took SWIOTLB path, which we were supposed to prevent
+ * for DMA_ATTR_REQUIRE_COHERENT attribute.
+ */
+ if (WARN_ON_ONCE((state->__size & DMA_IOVA_USE_SWIOTLB) &&
+ (attrs & DMA_ATTR_REQUIRE_COHERENT)))
+ return -EOPNOTSUPP;
+
+ if (!dev_is_dma_coherent(dev) && (attrs & DMA_ATTR_REQUIRE_COHERENT))
+ return -EOPNOTSUPP;
+
if (dev_use_swiotlb(dev, size, dir) &&
iova_unaligned(iovad, phys, size)) {
- if (attrs & DMA_ATTR_MMIO)
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
return -EPERM;
return iommu_dma_iova_link_swiotlb(dev, state, phys, offset,
diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h
index 3b2c41d9654d..8d11b08291d7 100644
--- a/drivers/iommu/generic_pt/fmt/amdv1.h
+++ b/drivers/iommu/generic_pt/fmt/amdv1.h
@@ -191,7 +191,7 @@ static inline enum pt_entry_type amdv1pt_load_entry_raw(struct pt_state *pts)
}
#define pt_load_entry_raw amdv1pt_load_entry_raw
-static inline void
+static __always_inline void
amdv1pt_install_leaf_entry(struct pt_state *pts, pt_oaddr_t oa,
unsigned int oasz_lg2,
const struct pt_write_attrs *attrs)
diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h
index 3e33fe64feab..7e7a6e7abdee 100644
--- a/drivers/iommu/generic_pt/iommu_pt.h
+++ b/drivers/iommu/generic_pt/iommu_pt.h
@@ -1057,7 +1057,7 @@ size_t DOMAIN_NS(unmap_pages)(struct iommu_domain *domain, unsigned long iova,
pt_walk_range(&range, __unmap_range, &unmap);
- gather_range_pages(iotlb_gather, iommu_table, iova, len,
+ gather_range_pages(iotlb_gather, iommu_table, iova, unmap.unmapped,
&unmap.free_list);
return unmap.unmapped;
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index d68c06025cac..69222dbd2af0 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -1314,7 +1314,6 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)
if (fault & DMA_FSTS_ITE) {
head = readl(iommu->reg + DMAR_IQH_REG);
head = ((head >> shift) - 1 + QI_LENGTH) % QI_LENGTH;
- head |= 1;
tail = readl(iommu->reg + DMAR_IQT_REG);
tail = ((tail >> shift) - 1 + QI_LENGTH) % QI_LENGTH;
@@ -1331,7 +1330,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)
do {
if (qi->desc_status[head] == QI_IN_USE)
qi->desc_status[head] = QI_ABORT;
- head = (head - 2 + QI_LENGTH) % QI_LENGTH;
+ head = (head - 1 + QI_LENGTH) % QI_LENGTH;
} while (head != tail);
/*
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index fea10acd4f02..57cd1db7207a 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -164,9 +164,12 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
if (IS_ERR(dev_pasid))
return PTR_ERR(dev_pasid);
- ret = iopf_for_domain_replace(domain, old, dev);
- if (ret)
- goto out_remove_dev_pasid;
+ /* SVA with non-IOMMU/PRI IOPF handling is allowed. */
+ if (info->pri_supported) {
+ ret = iopf_for_domain_replace(domain, old, dev);
+ if (ret)
+ goto out_remove_dev_pasid;
+ }
/* Setup the pasid table: */
sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
@@ -181,7 +184,8 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
return 0;
out_unwind_iopf:
- iopf_for_domain_replace(old, domain, dev);
+ if (info->pri_supported)
+ iopf_for_domain_replace(old, domain, dev);
out_remove_dev_pasid:
domain_remove_dev_pasid(domain, dev, pasid);
return ret;
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
index 07d64908a05f..bc7c7232a43e 100644
--- a/drivers/iommu/iommu-sva.c
+++ b/drivers/iommu/iommu-sva.c
@@ -182,13 +182,13 @@ void iommu_sva_unbind_device(struct iommu_sva *handle)
iommu_detach_device_pasid(domain, dev, iommu_mm->pasid);
if (--domain->users == 0) {
list_del(&domain->next);
- iommu_domain_free(domain);
- }
+ if (list_empty(&iommu_mm->sva_domains)) {
+ list_del(&iommu_mm->mm_list_elm);
+ if (list_empty(&iommu_sva_mms))
+ iommu_sva_present = false;
+ }
- if (list_empty(&iommu_mm->sva_domains)) {
- list_del(&iommu_mm->mm_list_elm);
- if (list_empty(&iommu_sva_mms))
- iommu_sva_present = false;
+ iommu_domain_free(domain);
}
mutex_unlock(&iommu_sva_lock);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 35db51780954..ee83850c7060 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1213,7 +1213,11 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
if (addr == end)
goto map_end;
- phys_addr = iommu_iova_to_phys(domain, addr);
+ /*
+ * Return address by iommu_iova_to_phys for 0 is
+ * ambiguous. Offset to address 1 if addr is 0.
+ */
+ phys_addr = iommu_iova_to_phys(domain, addr ? addr : 1);
if (!phys_addr) {
map_size += pg_size;
continue;
@@ -2713,6 +2717,12 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
pr_debug("unmapped: iova 0x%lx size 0x%zx\n",
iova, unmapped_page);
+ /*
+ * If the driver itself isn't using the gather, make sure
+ * it looks non-empty so iotlb_sync will still be called.
+ */
+ if (iotlb_gather->start >= iotlb_gather->end)
+ iommu_iotlb_gather_add_range(iotlb_gather, iova, size);
iova += unmapped_page;
unmapped += unmapped_page;
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 30783814f9d9..291d7668cc8d 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3474,6 +3474,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int lpi_base;
int nr_lpis;
int nr_ites;
+ int id_bits;
int sz;
if (!its_alloc_device_table(its, dev_id))
@@ -3485,7 +3486,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
/*
* Even if the device wants a single LPI, the ITT must be
* sized as a power of two (and you need at least one bit...).
+ * Also honor the ITS's own EID limit.
*/
+ id_bits = FIELD_GET(GITS_TYPER_IDBITS, its->typer) + 1;
+ nvecs = min_t(unsigned int, nvecs, BIT(id_bits));
nr_ites = max(2, nvecs);
sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
sz = max(sz, ITS_ITT_ALIGN);
diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c
index e518e5dfede7..f3fce0b1e25d 100644
--- a/drivers/irqchip/irq-gic-v5-irs.c
+++ b/drivers/irqchip/irq-gic-v5-irs.c
@@ -699,7 +699,7 @@ static int __init gicv5_irs_init(struct gicv5_irs_chip_data *irs_data)
*/
if (list_empty(&irs_nodes)) {
idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR0);
- gicv5_global_data.virt_capable = !FIELD_GET(GICV5_IRS_IDR0_VIRT, idr);
+ gicv5_global_data.virt_capable = !!FIELD_GET(GICV5_IRS_IDR0_VIRT, idr);
idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1);
irs_setup_pri_bits(idr);
diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
index a7e9c3885b09..d724fe843980 100644
--- a/drivers/irqchip/irq-ls-extirq.c
+++ b/drivers/irqchip/irq-ls-extirq.c
@@ -125,32 +125,45 @@ static const struct irq_domain_ops extirq_domain_ops = {
static int
ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node)
{
- struct of_imap_parser imap_parser;
- struct of_imap_item imap_item;
+ const __be32 *map;
+ u32 mapsize;
int ret;
- ret = of_imap_parser_init(&imap_parser, node, &imap_item);
- if (ret)
- return ret;
+ map = of_get_property(node, "interrupt-map", &mapsize);
+ if (!map)
+ return -ENOENT;
+ if (mapsize % sizeof(*map))
+ return -EINVAL;
+ mapsize /= sizeof(*map);
- for_each_of_imap_item(&imap_parser, &imap_item) {
+ while (mapsize) {
struct device_node *ipar;
- u32 hwirq;
- int i;
+ u32 hwirq, intsize, j;
- hwirq = imap_item.child_imap[0];
- if (hwirq >= MAXIRQ) {
- of_node_put(imap_item.parent_args.np);
+ if (mapsize < 3)
+ return -EINVAL;
+ hwirq = be32_to_cpup(map);
+ if (hwirq >= MAXIRQ)
return -EINVAL;
- }
priv->nirq = max(priv->nirq, hwirq + 1);
- ipar = of_node_get(imap_item.parent_args.np);
- priv->map[hwirq].fwnode = of_fwnode_handle(ipar);
+ ipar = of_find_node_by_phandle(be32_to_cpup(map + 2));
+ map += 3;
+ mapsize -= 3;
+ if (!ipar)
+ return -EINVAL;
+ priv->map[hwirq].fwnode = &ipar->fwnode;
+ ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
+ if (ret)
+ return ret;
- priv->map[hwirq].param_count = imap_item.parent_args.args_count;
- for (i = 0; i < priv->map[hwirq].param_count; i++)
- priv->map[hwirq].param[i] = imap_item.parent_args.args[i];
+ if (intsize > mapsize)
+ return -EINVAL;
+
+ priv->map[hwirq].param_count = intsize;
+ for (j = 0; j < intsize; ++j)
+ priv->map[hwirq].param[j] = be32_to_cpup(map++);
+ mapsize -= intsize;
}
return 0;
}
@@ -177,8 +190,10 @@ static int ls_extirq_probe(struct platform_device *pdev)
return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n");
priv->intpcr = devm_of_iomap(dev, node, 0, NULL);
- if (!priv->intpcr)
- return dev_err_probe(dev, -ENOMEM, "Cannot ioremap OF node %pOF\n", node);
+ if (IS_ERR(priv->intpcr)) {
+ return dev_err_probe(dev, PTR_ERR(priv->intpcr),
+ "Cannot ioremap OF node %pOF\n", node);
+ }
ret = ls_extirq_parse_map(priv, node);
if (ret)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 09e640430208..8e210cb451be 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -136,7 +136,7 @@ static void icu_unmask_irq(struct irq_data *d)
}
}
-struct irq_chip icu_irq_chip = {
+static const struct irq_chip icu_irq_chip = {
.name = "icu_irq",
.irq_mask = icu_mask_irq,
.irq_mask_ack = icu_mask_ack_irq,
diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c
index 83f31ea657b7..181320528a47 100644
--- a/drivers/irqchip/irq-qcom-mpm.c
+++ b/drivers/irqchip/irq-qcom-mpm.c
@@ -306,6 +306,8 @@ static int mpm_pd_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
return ret;
+ mbox_client_txdone(priv->mbox_chan, 0);
+
return 0;
}
@@ -434,6 +436,7 @@ static int qcom_mpm_probe(struct platform_device *pdev, struct device_node *pare
}
priv->mbox_client.dev = dev;
+ priv->mbox_client.knows_txdone = true;
priv->mbox_chan = mbox_request_channel(&priv->mbox_client, 0);
if (IS_ERR(priv->mbox_chan)) {
ret = PTR_ERR(priv->mbox_chan);
diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index da2bc43a0e12..03e93b061edd 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -621,7 +621,7 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
return 0;
pm_put:
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
return ret;
}
diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c
index 4495ca26abf5..d9afb6ae98cf 100644
--- a/drivers/irqchip/irq-riscv-aplic-main.c
+++ b/drivers/irqchip/irq-riscv-aplic-main.c
@@ -116,6 +116,16 @@ static struct syscore aplic_syscore = {
.ops = &aplic_syscore_ops,
};
+static bool aplic_syscore_registered __ro_after_init;
+
+static void aplic_syscore_init(void)
+{
+ if (!aplic_syscore_registered) {
+ register_syscore(&aplic_syscore);
+ aplic_syscore_registered = true;
+ }
+}
+
static int aplic_pm_notifier(struct notifier_block *nb, unsigned long action, void *data)
{
struct aplic_priv *priv = container_of(nb, struct aplic_priv, genpd_nb);
@@ -140,7 +150,7 @@ static void aplic_pm_remove(void *data)
struct device *dev = priv->dev;
list_del(&priv->head);
- if (dev->pm_domain)
+ if (dev->pm_domain && dev->of_node)
dev_pm_genpd_remove_notifier(dev);
}
@@ -155,7 +165,7 @@ static int aplic_pm_add(struct device *dev, struct aplic_priv *priv)
priv->saved_hw_regs.srcs = srcs;
list_add(&priv->head, &aplics);
- if (dev->pm_domain) {
+ if (dev->pm_domain && dev->of_node) {
priv->genpd_nb.notifier_call = aplic_pm_notifier;
ret = dev_pm_genpd_add_notifier(dev, &priv->genpd_nb);
if (ret)
@@ -372,18 +382,21 @@ static int aplic_probe(struct platform_device *pdev)
rc = aplic_msi_setup(dev, regs);
else
rc = aplic_direct_setup(dev, regs);
- if (rc)
+
+ if (rc) {
dev_err_probe(dev, rc, "failed to setup APLIC in %s mode\n",
msi_mode ? "MSI" : "direct");
- else
- register_syscore(&aplic_syscore);
+ return rc;
+ }
+
+ aplic_syscore_init();
#ifdef CONFIG_ACPI
if (!acpi_disabled)
acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
#endif
- return rc;
+ return 0;
}
static const struct of_device_id aplic_match[] = {
diff --git a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
index 5c74c561ce31..612f3972f7af 100644
--- a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
+++ b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
@@ -250,6 +250,7 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev)
rc = riscv_acpi_get_gsi_info(fwnode, &priv->gsi_base, &id,
&nr_irqs, NULL);
if (rc) {
+ mbox_free_channel(priv->chan);
dev_err(dev, "failed to find GSI mapping\n");
return rc;
}
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 686d39254426..5b0dac104814 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -172,8 +172,13 @@ static void plic_irq_disable(struct irq_data *d)
static void plic_irq_eoi(struct irq_data *d)
{
struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
+ u32 __iomem *reg;
+ bool enabled;
+
+ reg = handler->enable_base + (d->hwirq / 32) * sizeof(u32);
+ enabled = readl(reg) & BIT(d->hwirq % 32);
- if (unlikely(irqd_irq_disabled(d))) {
+ if (unlikely(!enabled)) {
plic_toggle(handler, d->hwirq, 1);
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
plic_toggle(handler, d->hwirq, 0);
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index 7cfed24054d0..3c8bc75e4d6c 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -168,7 +168,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
mutex_unlock(&dmxdev->mutex);
return -ENOMEM;
}
- dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+ dmxdev->dvr_buffer.data = mem;
+ dmxdev->dvr_buffer.size = DVR_BUFFER_SIZE;
+ dvb_ringbuffer_reset(&dmxdev->dvr_buffer);
if (dmxdev->may_do_mmap)
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
&dmxdev->mutex,
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 8bb8dd34c223..a2159b2bc176 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -228,6 +228,9 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
unsigned char htype = p->ule_sndu_type & 0x00FF;
+ if (htype >= ARRAY_SIZE(ule_mandatory_ext_handlers))
+ return -1;
+
/* Discriminate mandatory and optional extension headers. */
if (hlen == 0) {
/* Mandatory extension header */
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
index aa4dd7e7cf5a..8e25f970fd12 100644
--- a/drivers/media/i2c/ccs/ccs-core.c
+++ b/drivers/media/i2c/ccs/ccs-core.c
@@ -3080,8 +3080,6 @@ static int ccs_init_state(struct v4l2_subdev *sd,
struct v4l2_rect *crop =
v4l2_subdev_state_get_crop(sd_state, pad);
- guard(mutex)(&sensor->mutex);
-
ccs_get_native_size(ssd, crop);
fmt->width = crop->width;
diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
index c7c7d4a86c6b..13e77648807c 100644
--- a/drivers/media/mc/mc-request.c
+++ b/drivers/media/mc/mc-request.c
@@ -192,6 +192,8 @@ static long media_request_ioctl_reinit(struct media_request *req)
struct media_device *mdev = req->mdev;
unsigned long flags;
+ mutex_lock(&mdev->req_queue_mutex);
+
spin_lock_irqsave(&req->lock, flags);
if (req->state != MEDIA_REQUEST_STATE_IDLE &&
req->state != MEDIA_REQUEST_STATE_COMPLETE) {
@@ -199,6 +201,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
"request: %s not in idle or complete state, cannot reinit\n",
req->debug_str);
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return -EBUSY;
}
if (req->access_count) {
@@ -206,6 +209,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
"request: %s is being accessed, cannot reinit\n",
req->debug_str);
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return -EBUSY;
}
req->state = MEDIA_REQUEST_STATE_CLEANING;
@@ -216,6 +220,7 @@ static long media_request_ioctl_reinit(struct media_request *req)
spin_lock_irqsave(&req->lock, flags);
req->state = MEDIA_REQUEST_STATE_IDLE;
spin_unlock_irqrestore(&req->lock, flags);
+ mutex_unlock(&mdev->req_queue_mutex);
return 0;
}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 28267ee30190..3119f3bc9f98 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -500,11 +500,15 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx,
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS);
run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL;
+ } else {
+ run->ext_sps_st_rps = NULL;
}
if (ctx->has_sps_lt_rps) {
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS);
run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL;
+ } else {
+ run->ext_sps_lt_rps = NULL;
}
rkvdec_run_preamble(ctx, &run->base);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
index 97f1efde2e47..fb4f849d7366 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c
@@ -130,7 +130,7 @@ struct rkvdec_h264_ctx {
struct vdpu383_regs_h26x regs;
};
-static void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_dpb_entry *dpb)
+static noinline_for_stack void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_dpb_entry *dpb)
{
pps->top_field_order_cnt0 = dpb[0].top_field_order_cnt;
pps->bot_field_order_cnt0 = dpb[0].bottom_field_order_cnt;
@@ -166,6 +166,31 @@ static void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_d
pps->bot_field_order_cnt15 = dpb[15].bottom_field_order_cnt;
}
+static noinline_for_stack void set_dec_params(struct rkvdec_pps *pps, const struct v4l2_ctrl_h264_decode_params *dec_params)
+{
+ const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
+
+ for (int i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
+ pps->is_longterm |= (1 << i);
+ pps->ref_field_flags |=
+ (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
+ pps->ref_colmv_use_flag |=
+ (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
+ pps->ref_topfield_used |=
+ (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
+ pps->ref_botfield_used |=
+ (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
+ }
+ pps->pic_field_flag =
+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
+ pps->pic_associated_flag =
+ !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
+
+ pps->cur_top_field = dec_params->top_field_order_cnt;
+ pps->cur_bot_field = dec_params->bottom_field_order_cnt;
+}
+
static void assemble_hw_pps(struct rkvdec_ctx *ctx,
struct rkvdec_h264_run *run)
{
@@ -177,7 +202,6 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu;
struct rkvdec_sps_pps *hw_ps;
u32 pic_width, pic_height;
- u32 i;
/*
* HW read the SPS/PPS information from PPS packet index by PPS id.
@@ -261,28 +285,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
set_field_order_cnt(&hw_ps->pps, dpb);
+ set_dec_params(&hw_ps->pps, dec_params);
- for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
- if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
- hw_ps->pps.is_longterm |= (1 << i);
-
- hw_ps->pps.ref_field_flags |=
- (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i;
- hw_ps->pps.ref_colmv_use_flag |=
- (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i;
- hw_ps->pps.ref_topfield_used |=
- (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i;
- hw_ps->pps.ref_botfield_used |=
- (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i;
- }
-
- hw_ps->pps.pic_field_flag =
- !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC);
- hw_ps->pps.pic_associated_flag =
- !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD);
-
- hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt;
- hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt;
}
static void rkvdec_write_regs(struct rkvdec_ctx *ctx)
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index e4cdd2122873..2751f5396ee8 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -893,7 +893,8 @@ out_update_last:
update_ctx_last_info(vp9_ctx);
}
-static void rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx)
+static noinline_for_stack void
+rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx)
{
struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
struct rkvdec_vp9_intra_frame_symbol_counts *intra_cnts = vp9_ctx->count_tbl.cpu;
diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig
index e798ec00b189..bf2ac092fbb3 100644
--- a/drivers/media/platform/synopsys/Kconfig
+++ b/drivers/media/platform/synopsys/Kconfig
@@ -7,6 +7,7 @@ config VIDEO_DW_MIPI_CSI2RX
depends on VIDEO_DEV
depends on V4L_PLATFORM_DRIVERS
depends on PM && COMMON_CLK
+ select GENERIC_PHY_MIPI_DPHY
select MEDIA_CONTROLLER
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index 170346ae1a59..4d96171a650b 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -301,7 +301,7 @@ dw_mipi_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
case DW_MIPI_CSI2RX_PAD_SINK:
- if (code->index > csi2->formats_num)
+ if (code->index >= csi2->formats_num)
return -EINVAL;
code->code = csi2->formats[code->index].code;
diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
index 6f8e43b7f157..fa4224de4b99 100644
--- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c
@@ -343,7 +343,7 @@ const struct hantro_variant imx8mq_vpu_variant = {
.num_regs = ARRAY_SIZE(imx8mq_reg_names)
};
-static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = {
+static const struct of_device_id imx8mq_vpu_shared_resources[] = {
{ .compatible = "nxp,imx8mq-vpu-g1", },
{ .compatible = "nxp,imx8mq-vpu-g2", },
{ /* sentinel */ }
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 40c76c051da2..f6c8e3223796 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1751,7 +1751,8 @@ static void uvc_video_complete(struct urb *urb)
/*
* Free transfer buffers.
*/
-static void uvc_free_urb_buffers(struct uvc_streaming *stream)
+static void uvc_free_urb_buffers(struct uvc_streaming *stream,
+ unsigned int size)
{
struct usb_device *udev = stream->dev->udev;
struct uvc_urb *uvc_urb;
@@ -1760,7 +1761,7 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream)
if (!uvc_urb->buffer)
continue;
- usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer,
+ usb_free_noncoherent(udev, size, uvc_urb->buffer,
uvc_stream_dir(stream), uvc_urb->sgt);
uvc_urb->buffer = NULL;
uvc_urb->sgt = NULL;
@@ -1820,7 +1821,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
if (!uvc_alloc_urb_buffer(stream, uvc_urb, urb_size,
gfp_flags)) {
- uvc_free_urb_buffers(stream);
+ uvc_free_urb_buffers(stream, urb_size);
break;
}
@@ -1868,7 +1869,7 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream,
}
if (free_buffers)
- uvc_free_urb_buffers(stream);
+ uvc_free_urb_buffers(stream, stream->urb_size);
}
/*
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 37d33d4a363d..a2b650f4ec3c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -3082,13 +3082,14 @@ static long __video_do_ioctl(struct file *file,
}
/*
- * We need to serialize streamon/off with queueing new requests.
+ * We need to serialize streamon/off/reqbufs with queueing new requests.
* These ioctls may trigger the cancellation of a streaming
* operation, and that should not be mixed with queueing a new
* request at the same time.
*/
if (v4l2_device_supports_requests(vfd->v4l2_dev) &&
- (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) {
+ (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF ||
+ cmd == VIDIOC_REQBUFS)) {
req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;
if (mutex_lock_interruptible(req_queue_lock))
diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
index be022c71a90c..30e7fad7356c 100644
--- a/drivers/misc/amd-sbi/Kconfig
+++ b/drivers/misc/amd-sbi/Kconfig
@@ -1,10 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
config AMD_SBRMI_I2C
tristate "AMD side band RMI support"
- depends on I2C
+ depends on I3C_OR_I2C
depends on ARM || ARM64 || COMPILE_TEST
select REGMAP_I2C
- depends on I3C || !I3C
select REGMAP_I3C if I3C
help
Side band RMI over I2C/I3C support for AMD out of band management.
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 47356a5d5804..1080f9acf70a 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -1401,6 +1401,7 @@ err_invoke:
}
err_map:
fastrpc_buf_free(fl->cctx->remote_heap);
+ fl->cctx->remote_heap = NULL;
err_name:
kfree(name);
err:
@@ -2389,8 +2390,10 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
if (!err) {
src_perms = BIT(QCOM_SCM_VMID_HLOS);
- qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms,
+ err = qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms,
data->vmperms, data->vmcount);
+ if (err)
+ goto err_free_data;
}
}
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index 9c68f8b1d5d6..21e8ad0a7444 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -1230,10 +1230,12 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
else
thread_fn = NULL;
+ if (thread_fn)
+ irq_flags |= IRQF_ONESHOT;
+
err = request_threaded_irq(lis3->irq, lis302dl_interrupt,
thread_fn,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT |
- irq_flags,
+ irq_flags | IRQF_TRIGGER_RISING,
DRIVER_NAME, lis3);
if (err < 0) {
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index 5902dd1ee44b..094fb1dde0fe 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -3,6 +3,7 @@
config INTEL_MEI
tristate "Intel Management Engine Interface"
depends on PCI
+ depends on X86 || DRM_XE!=n || COMPILE_TEST
default X86_64 || MATOM
help
The Intel Management Engine (Intel ME) provides Manageability,
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index d4612c659784..1e4a41ac428f 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -1337,19 +1337,13 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
- /* synchronized by dev mutex */
- if (waitqueue_active(&dev->wait_hw_ready)) {
- dev_dbg(&dev->dev, "we need to start the dev.\n");
- dev->recvd_hw_ready = true;
- wake_up(&dev->wait_hw_ready);
- } else if (dev->dev_state != MEI_DEV_UNINITIALIZED &&
- dev->dev_state != MEI_DEV_POWERING_DOWN &&
- dev->dev_state != MEI_DEV_POWER_DOWN) {
+ if (dev->dev_state == MEI_DEV_ENABLED) {
dev_dbg(&dev->dev, "Force link reset.\n");
schedule_work(&dev->reset_work);
} else {
- dev_dbg(&dev->dev, "Ignore this interrupt in state = %d\n",
- dev->dev_state);
+ dev_dbg(&dev->dev, "we need to start the dev.\n");
+ dev->recvd_hw_ready = true;
+ wake_up(&dev->wait_hw_ready);
}
} else {
dev_dbg(&dev->dev, "Spurious Interrupt\n");
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 4e3423a19bdf..ac069d0c42b2 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -36,6 +36,8 @@ struct dw_mci_rockchip_priv_data {
int default_sample_phase;
int num_phases;
bool internal_phase;
+ int sample_phase;
+ int drv_phase;
};
/*
@@ -573,9 +575,43 @@ static void dw_mci_rockchip_remove(struct platform_device *pdev)
dw_mci_pltfm_remove(pdev);
}
+static int dw_mci_rockchip_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_mci *host = platform_get_drvdata(pdev);
+ struct dw_mci_rockchip_priv_data *priv = host->priv;
+
+ if (priv->internal_phase) {
+ priv->sample_phase = rockchip_mmc_get_phase(host, true);
+ priv->drv_phase = rockchip_mmc_get_phase(host, false);
+ }
+
+ return dw_mci_runtime_suspend(dev);
+}
+
+static int dw_mci_rockchip_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_mci *host = platform_get_drvdata(pdev);
+ struct dw_mci_rockchip_priv_data *priv = host->priv;
+ int ret;
+
+ ret = dw_mci_runtime_resume(dev);
+ if (ret)
+ return ret;
+
+ if (priv->internal_phase) {
+ rockchip_mmc_set_phase(host, true, priv->sample_phase);
+ rockchip_mmc_set_phase(host, false, priv->drv_phase);
+ mci_writel(host, MISC_CON, MEM_CLK_AUTOGATE_ENABLE);
+ }
+
+ return ret;
+}
+
static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
- RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_runtime_resume, NULL)
+ RUNTIME_PM_OPS(dw_mci_rockchip_runtime_suspend, dw_mci_rockchip_runtime_resume, NULL)
};
static struct platform_driver dw_mci_rockchip_pltfm_driver = {
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
index 3da6112fbe39..67371389cc33 100644
--- a/drivers/mmc/host/mmci_qcom_dml.c
+++ b/drivers/mmc/host/mmci_qcom_dml.c
@@ -109,6 +109,7 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
&dma_spec))
return -ENODEV;
+ of_node_put(dma_spec.np);
if (dma_spec.args_count)
return dma_spec.args[0];
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index c9442499876c..57e45951644e 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -116,7 +116,7 @@ static void sdhci_brcmstb_restore_regs(struct mmc_host *mmc, enum cfg_core_ver v
writel(sr->boot_main_ctl, priv->boot_regs + SDIO_BOOT_MAIN_CTL);
if (ver == SDIO_CFG_CORE_V1) {
- writel(sr->sd_pin_sel, cr + SDIO_CFG_SD_PIN_SEL);
+ writel(sr->sd_pin_sel, cr + SDIO_CFG_V1_SD_PIN_SEL);
return;
}
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index b0f91cc9e40e..6e4084407662 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -68,6 +68,9 @@
#define GLI_9750_MISC_TX1_DLY_VALUE 0x5
#define SDHCI_GLI_9750_MISC_SSC_OFF BIT(26)
+#define SDHCI_GLI_9750_GM_BURST_SIZE 0x510
+#define SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT GENMASK(17, 16)
+
#define SDHCI_GLI_9750_TUNING_CONTROL 0x540
#define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4)
#define GLI_9750_TUNING_CONTROL_EN_ON 0x1
@@ -345,10 +348,16 @@ static void gli_set_9750(struct sdhci_host *host)
u32 misc_value;
u32 parameter_value;
u32 control_value;
+ u32 burst_value;
u16 ctrl2;
gl9750_wt_on(host);
+ /* clear R_OSRC_Lmt to avoid DMA write corruption */
+ burst_value = sdhci_readl(host, SDHCI_GLI_9750_GM_BURST_SIZE);
+ burst_value &= ~SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT;
+ sdhci_writel(host, burst_value, SDHCI_GLI_9750_GM_BURST_SIZE);
+
driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ac7e11f37af7..fec9329e1edb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4532,8 +4532,15 @@ int sdhci_setup_host(struct sdhci_host *host)
* their platform code before calling sdhci_add_host(), and we
* won't assume 8-bit width for hosts without that CAP.
*/
- if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
+ if (host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA) {
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
+ if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400)
+ host->caps1 &= ~SDHCI_SUPPORT_HS400;
+ mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
+ mmc->caps &= ~(MMC_CAP_DDR | MMC_CAP_UHS);
+ } else {
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ }
if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23)
mmc->caps &= ~MMC_CAP_CMD23;
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index ff49d0770506..3c9df27f9fa7 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -369,11 +369,14 @@ struct vub300_mmc_host {
static void vub300_delete(struct kref *kref)
{ /* kref callback - softirq */
struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
+ struct mmc_host *mmc = vub300->mmc;
+
usb_free_urb(vub300->command_out_urb);
vub300->command_out_urb = NULL;
usb_free_urb(vub300->command_res_urb);
vub300->command_res_urb = NULL;
usb_put_dev(vub300->udev);
+ mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
@@ -2112,7 +2115,7 @@ static int vub300_probe(struct usb_interface *interface,
goto error1;
}
/* this also allocates memory for our VUB300 mmc host device */
- mmc = devm_mmc_alloc_host(&udev->dev, sizeof(*vub300));
+ mmc = mmc_alloc_host(sizeof(*vub300), &udev->dev);
if (!mmc) {
retval = -ENOMEM;
dev_err(&udev->dev, "not enough memory for the mmc_host\n");
@@ -2269,7 +2272,7 @@ static int vub300_probe(struct usb_interface *interface,
dev_err(&vub300->udev->dev,
"Could not find two sets of bulk-in/out endpoint pairs\n");
retval = -EINVAL;
- goto error4;
+ goto err_free_host;
}
retval =
usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
@@ -2278,14 +2281,14 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->hc_info,
sizeof(vub300->hc_info), 1000);
if (retval < 0)
- goto error4;
+ goto err_free_host;
retval =
usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
SET_ROM_WAIT_STATES,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
if (retval < 0)
- goto error4;
+ goto err_free_host;
dev_info(&vub300->udev->dev,
"operating_mode = %s %s %d MHz %s %d byte USB packets\n",
(mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
@@ -2300,7 +2303,7 @@ static int vub300_probe(struct usb_interface *interface,
0x0000, 0x0000, &vub300->system_port_status,
sizeof(vub300->system_port_status), 1000);
if (retval < 0) {
- goto error4;
+ goto err_free_host;
} else if (sizeof(vub300->system_port_status) == retval) {
vub300->card_present =
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
@@ -2308,7 +2311,7 @@ static int vub300_probe(struct usb_interface *interface,
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
} else {
retval = -EINVAL;
- goto error4;
+ goto err_free_host;
}
usb_set_intfdata(interface, vub300);
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@@ -2338,6 +2341,8 @@ static int vub300_probe(struct usb_interface *interface,
return 0;
error6:
timer_delete_sync(&vub300->inactivity_timer);
+err_free_host:
+ mmc_free_host(mmc);
/*
* and hence also frees vub300
* which is contained at the end of struct mmc
@@ -2365,8 +2370,8 @@ static void vub300_disconnect(struct usb_interface *interface)
usb_set_intfdata(interface, NULL);
/* prevent more I/O from starting */
vub300->interface = NULL;
- kref_put(&vub300->kref, vub300_delete);
mmc_remove_host(mmc);
+ kref_put(&vub300->kref, vub300_delete);
pr_info("USB vub300 remote SDIO host controller[%d]"
" now disconnected", ifnum);
return;
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 0427d76f45d0..5b9dadd5405e 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2350,14 +2350,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
for (i = 0; i < ctrl->max_oob; i += 4)
oob_reg_write(ctrl, i, 0xffffffff);
- if (mtd->oops_panic_write)
+ if (mtd->oops_panic_write) {
/* switch to interrupt polling and PIO mode */
disable_ctrl_irqs(ctrl);
-
- if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
+ } else if (use_dma(ctrl) && (has_edu(ctrl) || !oob) && flash_dma_buf_ok(buf)) {
if (ctrl->dma_trans(host, addr, (u32 *)buf, oob, mtd->writesize,
CMD_PROGRAM_PAGE))
-
ret = -EIO;
goto out;
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
index 99135ec23010..d53b35a8b3cb 100644
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
@@ -3133,7 +3133,7 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
sizeof(*cdns_ctrl->cdma_desc),
&cdns_ctrl->dma_cdma_desc,
GFP_KERNEL);
- if (!cdns_ctrl->dma_cdma_desc)
+ if (!cdns_ctrl->cdma_desc)
return -ENOMEM;
cdns_ctrl->buf_size = SZ_16K;
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 38429363251c..dfd8361bdd36 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4737,11 +4737,16 @@ static void nand_shutdown(struct mtd_info *mtd)
static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
if (!chip->ops.lock_area)
return -ENOTSUPP;
- return chip->ops.lock_area(chip, ofs, len);
+ nand_get_device(chip);
+ ret = chip->ops.lock_area(chip, ofs, len);
+ nand_release_device(chip);
+
+ return ret;
}
/**
@@ -4753,11 +4758,16 @@ static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret;
if (!chip->ops.unlock_area)
return -ENOTSUPP;
- return chip->ops.unlock_area(chip, ofs, len);
+ nand_get_device(chip);
+ ret = chip->ops.unlock_area(chip, ofs, len);
+ nand_release_device(chip);
+
+ return ret;
}
/* Set default functions */
diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c
index 947fd86ac5fa..f2c65eb7a8d9 100644
--- a/drivers/mtd/nand/raw/pl35x-nand-controller.c
+++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c
@@ -862,6 +862,9 @@ static int pl35x_nfc_setup_interface(struct nand_chip *chip, int cs,
PL35X_SMC_NAND_TAR_CYCLES(tmgs.t_ar) |
PL35X_SMC_NAND_TRR_CYCLES(tmgs.t_rr);
+ writel(plnand->timings, nfc->conf_regs + PL35X_SMC_CYCLES);
+ pl35x_smc_update_regs(nfc);
+
return 0;
}
diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c
index 558905160ddb..bf162c44eafe 100644
--- a/drivers/mtd/parsers/redboot.c
+++ b/drivers/mtd/parsers/redboot.c
@@ -270,9 +270,9 @@ nogood:
strcpy(names, fl->img->name);
#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
- if (!memcmp(names, "RedBoot", 8) ||
- !memcmp(names, "RedBoot config", 15) ||
- !memcmp(names, "FIS directory", 14)) {
+ if (!strcmp(names, "RedBoot") ||
+ !strcmp(names, "RedBoot config") ||
+ !strcmp(names, "FIS directory")) {
parts[i].mask_flags = MTD_WRITEABLE;
}
#endif
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 8ffeb41c3e08..1eee519c01e5 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2345,15 +2345,15 @@ int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
}
/**
- * spi_nor_spimem_check_op - check if the operation is supported
- * by controller
+ * spi_nor_spimem_check_read_pp_op - check if a read or a page program operation is
+ * supported by controller
*@nor: pointer to a 'struct spi_nor'
*@op: pointer to op template to be checked
*
* Returns 0 if operation is supported, -EOPNOTSUPP otherwise.
*/
-static int spi_nor_spimem_check_op(struct spi_nor *nor,
- struct spi_mem_op *op)
+static int spi_nor_spimem_check_read_pp_op(struct spi_nor *nor,
+ struct spi_mem_op *op)
{
/*
* First test with 4 address bytes. The opcode itself might
@@ -2396,7 +2396,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor,
if (spi_nor_protocol_is_dtr(nor->read_proto))
op.dummy.nbytes *= 2;
- return spi_nor_spimem_check_op(nor, &op);
+ return spi_nor_spimem_check_read_pp_op(nor, &op);
}
/**
@@ -2414,7 +2414,7 @@ static int spi_nor_spimem_check_pp(struct spi_nor *nor,
spi_nor_spimem_setup_op(nor, &op, pp->proto);
- return spi_nor_spimem_check_op(nor, &op);
+ return spi_nor_spimem_check_read_pp_op(nor, &op);
}
/**
@@ -2466,7 +2466,7 @@ spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps)
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
- if (spi_nor_spimem_check_op(nor, &op))
+ if (!spi_mem_supports_op(nor->spimem, &op))
nor->flags |= SNOR_F_NO_READ_CR;
}
}
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 8adbec7c5084..8967b65f6d84 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -34,11 +34,17 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
for (; hash_index != RLB_NULL_INDEX;
hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
- seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
- &client_info->ip_src,
- &client_info->ip_dst,
- &client_info->mac_dst,
- client_info->slave->dev->name);
+ if (client_info->slave)
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst,
+ client_info->slave->dev->name);
+ else
+ seq_printf(m, "%-15pI4 %-15pI4 %-17pM (none)\n",
+ &client_info->ip_src,
+ &client_info->ip_dst,
+ &client_info->mac_dst);
}
spin_unlock_bh(&bond->mode_lock);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a1de08ee3815..a5484d11553d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -324,7 +324,7 @@ static bool bond_sk_check(struct bonding *bond)
}
}
-bool bond_xdp_check(struct bonding *bond, int mode)
+bool __bond_xdp_check(int mode, int xmit_policy)
{
switch (mode) {
case BOND_MODE_ROUNDROBIN:
@@ -335,7 +335,7 @@ bool bond_xdp_check(struct bonding *bond, int mode)
/* vlan+srcmac is not supported with XDP as in most cases the 802.1q
* payload is not in the packet due to hardware offload.
*/
- if (bond->params.xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
+ if (xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
return true;
fallthrough;
default:
@@ -343,6 +343,11 @@ bool bond_xdp_check(struct bonding *bond, int mode)
}
}
+bool bond_xdp_check(struct bonding *bond, int mode)
+{
+ return __bond_xdp_check(mode, bond->params.xmit_policy);
+}
+
/*---------------------------------- VLAN -----------------------------------*/
/* In the following 2 functions, bond_vlan_rx_add_vid and bond_vlan_rx_kill_vid,
@@ -1504,6 +1509,52 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
return features;
}
+static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ const struct header_ops *slave_ops;
+ struct slave *slave;
+ int ret = 0;
+
+ rcu_read_lock();
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave) {
+ slave_ops = READ_ONCE(slave->dev->header_ops);
+ if (slave_ops && slave_ops->create)
+ ret = slave_ops->create(skb, slave->dev,
+ type, daddr, saddr, len);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static int bond_header_parse(const struct sk_buff *skb,
+ const struct net_device *dev,
+ unsigned char *haddr)
+{
+ struct bonding *bond = netdev_priv(dev);
+ const struct header_ops *slave_ops;
+ struct slave *slave;
+ int ret = 0;
+
+ rcu_read_lock();
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave) {
+ slave_ops = READ_ONCE(slave->dev->header_ops);
+ if (slave_ops && slave_ops->parse)
+ ret = slave_ops->parse(skb, slave->dev, haddr);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static const struct header_ops bond_header_ops = {
+ .create = bond_header_create,
+ .parse = bond_header_parse,
+};
+
static void bond_setup_by_slave(struct net_device *bond_dev,
struct net_device *slave_dev)
{
@@ -1511,7 +1562,8 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
dev_close(bond_dev);
- bond_dev->header_ops = slave_dev->header_ops;
+ bond_dev->header_ops = slave_dev->header_ops ?
+ &bond_header_ops : NULL;
bond_dev->type = slave_dev->type;
bond_dev->hard_header_len = slave_dev->hard_header_len;
@@ -2796,8 +2848,14 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
+ case BOND_LINK_FAIL:
+ case BOND_LINK_BACK:
+ slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
+ slave->link_new_state);
+ continue;
+
default:
- slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",
+ slave_err(bond->dev, slave->dev, "invalid link_new_state %d on slave\n",
slave->link_new_state);
bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
@@ -3372,7 +3430,7 @@ int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond,
} else if (is_arp) {
return bond_arp_rcv(skb, bond, slave);
#if IS_ENABLED(CONFIG_IPV6)
- } else if (is_ipv6) {
+ } else if (is_ipv6 && likely(ipv6_mod_enabled())) {
return bond_na_rcv(skb, bond, slave);
#endif
} else {
@@ -5064,13 +5122,18 @@ static void bond_set_slave_arr(struct bonding *bond,
{
struct bond_up_slave *usable, *all;
- usable = rtnl_dereference(bond->usable_slaves);
- rcu_assign_pointer(bond->usable_slaves, usable_slaves);
- kfree_rcu(usable, rcu);
-
all = rtnl_dereference(bond->all_slaves);
rcu_assign_pointer(bond->all_slaves, all_slaves);
kfree_rcu(all, rcu);
+
+ if (BOND_MODE(bond) == BOND_MODE_BROADCAST) {
+ kfree_rcu(usable_slaves, rcu);
+ return;
+ }
+
+ usable = rtnl_dereference(bond->usable_slaves);
+ rcu_assign_pointer(bond->usable_slaves, usable_slaves);
+ kfree_rcu(usable, rcu);
}
static void bond_reset_slave_arr(struct bonding *bond)
@@ -5263,7 +5326,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb,
if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
continue;
- if (bond_is_last_slave(bond, slave)) {
+ if (i + 1 == slaves_count) {
skb2 = skb;
skb_used = true;
} else {
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index dcee384c2f06..7380cc4ee75a 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1575,6 +1575,8 @@ static int bond_option_fail_over_mac_set(struct bonding *bond,
static int bond_option_xmit_hash_policy_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
+ if (bond->xdp_prog && !__bond_xdp_check(BOND_MODE(bond), newval->value))
+ return -EOPNOTSUPP;
netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
newval->string, newval->value);
bond->params.xmit_policy = newval->value;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 9a75ad3181ab..eaba44c76a5e 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -808,7 +808,7 @@ int __net_init bond_create_sysfs(struct bond_net *bn)
sysfs_attr_init(&bn->class_attr_bonding_masters.attr);
ret = netdev_class_create_file_ns(&bn->class_attr_bonding_masters,
- bn->net);
+ to_ns_common(bn->net));
/* Permit multiple loads of the module by ignoring failures to
* create the bonding_masters sysfs file. Bonding devices
* created by second or subsequent loads of the module will
@@ -835,7 +835,7 @@ int __net_init bond_create_sysfs(struct bond_net *bn)
/* Remove /sys/class/net/bonding_masters. */
void __net_exit bond_destroy_sysfs(struct bond_net *bn)
{
- netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, bn->net);
+ netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, to_ns_common(bn->net));
}
/* Initialize sysfs for each bond. This sets up and registers
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index b90890030751..1873d8287bb9 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -297,6 +297,7 @@ static void ser_release(struct work_struct *work)
dev_close(ser->dev);
unregister_netdevice(ser->dev);
debugfs_deinit(ser);
+ tty_kref_put(tty->link);
tty_kref_put(tty);
}
rtnl_unlock();
@@ -331,6 +332,7 @@ static int ldisc_open(struct tty_struct *tty)
ser = netdev_priv(dev);
ser->tty = tty_kref_get(tty);
+ tty_kref_get(tty->link);
ser->dev = dev;
debugfs_init(ser, tty);
tty->receive_room = 4096;
@@ -339,6 +341,7 @@ static int ldisc_open(struct tty_struct *tty)
rtnl_lock();
result = register_netdevice(dev);
if (result) {
+ tty_kref_put(tty->link);
tty_kref_put(tty);
rtnl_unlock();
free_netdev(dev);
diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c
index cc4022241553..42498e9d3f38 100644
--- a/drivers/net/can/dev/calc_bittiming.c
+++ b/drivers/net/can/dev/calc_bittiming.c
@@ -8,7 +8,7 @@
#include <linux/units.h>
#include <linux/can/dev.h>
-#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
+#define CAN_CALC_MAX_ERROR 500 /* max error 5% */
/* CiA recommended sample points for Non Return to Zero encoding. */
static int can_calc_sample_point_nrz(const struct can_bittiming *bt)
diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
index 0498198a4696..766d455950f5 100644
--- a/drivers/net/can/dev/netlink.c
+++ b/drivers/net/can/dev/netlink.c
@@ -601,7 +601,9 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
/* We need synchronization with dev->stop() */
ASSERT_RTNL();
- can_ctrlmode_changelink(dev, data, extack);
+ err = can_ctrlmode_changelink(dev, data, extack);
+ if (err)
+ return err;
if (data[IFLA_CAN_BITTIMING]) {
struct can_bittiming bt;
diff --git a/drivers/net/can/dummy_can.c b/drivers/net/can/dummy_can.c
index 41953655e3d3..cd23de488edc 100644
--- a/drivers/net/can/dummy_can.c
+++ b/drivers/net/can/dummy_can.c
@@ -241,6 +241,7 @@ static int __init dummy_can_init(void)
dev->netdev_ops = &dummy_can_netdev_ops;
dev->ethtool_ops = &dummy_can_ethtool_ops;
+ dev->flags |= IFF_ECHO; /* enable echo handling */
priv = netdev_priv(dev);
priv->can.bittiming_const = &dummy_can_bittiming_const;
priv->can.bitrate_max = 20 * MEGA /* BPS */;
diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c
index e00d3dbc4cf4..91b1fa970f8f 100644
--- a/drivers/net/can/spi/hi311x.c
+++ b/drivers/net/can/spi/hi311x.c
@@ -755,7 +755,9 @@ static int hi3110_open(struct net_device *net)
return ret;
mutex_lock(&priv->hi3110_lock);
- hi3110_power_enable(priv->transceiver, 1);
+ ret = hi3110_power_enable(priv->transceiver, 1);
+ if (ret)
+ goto out_close_candev;
priv->force_quit = 0;
priv->tx_skb = NULL;
@@ -790,6 +792,7 @@ static int hi3110_open(struct net_device *net)
hi3110_hw_sleep(spi);
out_close:
hi3110_power_enable(priv->transceiver, 0);
+ out_close_candev:
close_candev(net);
mutex_unlock(&priv->hi3110_lock);
return ret;
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index fa97adf25b73..0d0190ae094a 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1214,6 +1214,7 @@ static int mcp251x_open(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
+ bool release_irq = false;
unsigned long flags = 0;
int ret;
@@ -1224,7 +1225,11 @@ static int mcp251x_open(struct net_device *net)
}
mutex_lock(&priv->mcp_lock);
- mcp251x_power_enable(priv->transceiver, 1);
+ ret = mcp251x_power_enable(priv->transceiver, 1);
+ if (ret) {
+ dev_err(&spi->dev, "failed to enable transceiver power: %pe\n", ERR_PTR(ret));
+ goto out_close_candev;
+ }
priv->force_quit = 0;
priv->tx_skb = NULL;
@@ -1257,12 +1262,25 @@ static int mcp251x_open(struct net_device *net)
return 0;
out_free_irq:
- free_irq(spi->irq, priv);
+ /* The IRQ handler might be running, and if so it will be waiting
+ * for the lock. But free_irq() must wait for the handler to finish
+ * so calling it here would deadlock.
+ *
+ * Setting priv->force_quit will let the handler exit right away
+ * without any access to the hardware. This make it safe to call
+ * free_irq() after the lock is released.
+ */
+ priv->force_quit = 1;
+ release_irq = true;
+
mcp251x_hw_sleep(spi);
out_close:
mcp251x_power_enable(priv->transceiver, 0);
+out_close_candev:
close_candev(net);
mutex_unlock(&priv->mcp_lock);
+ if (release_irq)
+ free_irq(spi->irq, priv);
return ret;
}
@@ -1503,11 +1521,25 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct mcp251x_priv *priv = spi_get_drvdata(spi);
+ int ret = 0;
- if (priv->after_suspend & AFTER_SUSPEND_POWER)
- mcp251x_power_enable(priv->power, 1);
- if (priv->after_suspend & AFTER_SUSPEND_UP)
- mcp251x_power_enable(priv->transceiver, 1);
+ if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+ ret = mcp251x_power_enable(priv->power, 1);
+ if (ret) {
+ dev_err(dev, "failed to restore power: %pe\n", ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ ret = mcp251x_power_enable(priv->transceiver, 1);
+ if (ret) {
+ dev_err(dev, "failed to restore transceiver power: %pe\n", ERR_PTR(ret));
+ if (priv->after_suspend & AFTER_SUSPEND_POWER)
+ mcp251x_power_enable(priv->power, 0);
+ return ret;
+ }
+ }
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
queue_work(priv->wq, &priv->restart_work);
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 4c219a5b139b..9b25dda7c183 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -445,6 +445,11 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
start = CPC_HEADER_SIZE;
while (msg_count) {
+ if (start + CPC_MSG_HEADER_LEN > urb->actual_length) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+
msg = (struct ems_cpc_msg *)&ibuf[start];
switch (msg->type) {
@@ -474,7 +479,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
start += CPC_MSG_HEADER_LEN + msg->length;
msg_count--;
- if (start > urb->transfer_buffer_length) {
+ if (start > urb->actual_length) {
netdev_err(netdev, "format error\n");
break;
}
diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c
index 2892a68f510a..d257440fa01f 100644
--- a/drivers/net/can/usb/esd_usb.c
+++ b/drivers/net/can/usb/esd_usb.c
@@ -272,6 +272,9 @@ struct esd_usb {
struct usb_anchor rx_submitted;
+ unsigned int rx_pipe;
+ unsigned int tx_pipe;
+
int net_count;
u32 version;
int rxinitdone;
@@ -537,7 +540,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb)
}
resubmit_urb:
- usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+ usb_fill_bulk_urb(urb, dev->udev, dev->rx_pipe,
urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE,
esd_usb_read_bulk_callback, dev);
@@ -626,9 +629,7 @@ static int esd_usb_send_msg(struct esd_usb *dev, union esd_usb_msg *msg)
{
int actual_length;
- return usb_bulk_msg(dev->udev,
- usb_sndbulkpipe(dev->udev, 2),
- msg,
+ return usb_bulk_msg(dev->udev, dev->tx_pipe, msg,
msg->hdr.len * sizeof(u32), /* convert to # of bytes */
&actual_length,
1000);
@@ -639,12 +640,8 @@ static int esd_usb_wait_msg(struct esd_usb *dev,
{
int actual_length;
- return usb_bulk_msg(dev->udev,
- usb_rcvbulkpipe(dev->udev, 1),
- msg,
- sizeof(*msg),
- &actual_length,
- 1000);
+ return usb_bulk_msg(dev->udev, dev->rx_pipe, msg,
+ sizeof(*msg), &actual_length, 1000);
}
static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
@@ -677,8 +674,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
urb->transfer_dma = buf_dma;
- usb_fill_bulk_urb(urb, dev->udev,
- usb_rcvbulkpipe(dev->udev, 1),
+ usb_fill_bulk_urb(urb, dev->udev, dev->rx_pipe,
buf, ESD_USB_RX_BUFFER_SIZE,
esd_usb_read_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -903,7 +899,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
/* hnd must not be 0 - MSB is stripped in txdone handling */
msg->tx.hnd = BIT(31) | i; /* returned in TX done message */
- usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
+ usb_fill_bulk_urb(urb, dev->udev, dev->tx_pipe, buf,
msg->hdr.len * sizeof(u32), /* convert to # of bytes */
esd_usb_write_bulk_callback, context);
@@ -1298,10 +1294,16 @@ done:
static int esd_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
struct esd_usb *dev;
union esd_usb_msg *msg;
int i, err;
+ err = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out,
+ NULL, NULL);
+ if (err)
+ return err;
+
dev = kzalloc_obj(*dev);
if (!dev) {
err = -ENOMEM;
@@ -1309,6 +1311,8 @@ static int esd_usb_probe(struct usb_interface *intf,
}
dev->udev = interface_to_usbdev(intf);
+ dev->rx_pipe = usb_rcvbulkpipe(dev->udev, ep_in->bEndpointAddress);
+ dev->tx_pipe = usb_sndbulkpipe(dev->udev, ep_out->bEndpointAddress);
init_usb_anchor(&dev->rx_submitted);
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
index 2d248deb69dc..b259f6109808 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
@@ -1461,12 +1461,18 @@ static void es58x_read_bulk_callback(struct urb *urb)
}
resubmit_urb:
+ usb_anchor_urb(urb, &es58x_dev->rx_urbs);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!ret)
+ return;
+
+ usb_unanchor_urb(urb);
+
if (ret == -ENODEV) {
for (i = 0; i < es58x_dev->num_can_ch; i++)
if (es58x_dev->netdev[i])
netif_device_detach(es58x_dev->netdev[i]);
- } else if (ret)
+ } else
dev_err_ratelimited(dev,
"Failed resubmitting read bulk urb: %pe\n",
ERR_PTR(ret));
diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
index 76578063ac82..f12318268e46 100644
--- a/drivers/net/can/usb/f81604.c
+++ b/drivers/net/can/usb/f81604.c
@@ -413,6 +413,7 @@ static void f81604_read_bulk_callback(struct urb *urb)
{
struct f81604_can_frame *frame = urb->transfer_buffer;
struct net_device *netdev = urb->context;
+ struct f81604_port_priv *priv = netdev_priv(netdev);
int ret;
if (!netif_device_present(netdev))
@@ -445,10 +446,15 @@ static void f81604_read_bulk_callback(struct urb *urb)
f81604_process_rx_packet(netdev, frame);
resubmit_urb:
+ usb_anchor_urb(urb, &priv->urbs_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!ret)
+ return;
+ usb_unanchor_urb(urb);
+
if (ret == -ENODEV)
netif_device_detach(netdev);
- else if (ret)
+ else
netdev_err(netdev,
"%s: failed to resubmit read bulk urb: %pe\n",
__func__, ERR_PTR(ret));
@@ -620,6 +626,12 @@ static void f81604_read_int_callback(struct urb *urb)
netdev_info(netdev, "%s: Int URB aborted: %pe\n", __func__,
ERR_PTR(urb->status));
+ if (urb->actual_length < sizeof(*data)) {
+ netdev_warn(netdev, "%s: short int URB: %u < %zu\n",
+ __func__, urb->actual_length, sizeof(*data));
+ goto resubmit_urb;
+ }
+
switch (urb->status) {
case 0: /* success */
break;
@@ -646,10 +658,15 @@ static void f81604_read_int_callback(struct urb *urb)
f81604_handle_tx(priv, data);
resubmit_urb:
+ usb_anchor_urb(urb, &priv->urbs_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!ret)
+ return;
+ usb_unanchor_urb(urb);
+
if (ret == -ENODEV)
netif_device_detach(netdev);
- else if (ret)
+ else
netdev_err(netdev, "%s: failed to resubmit int urb: %pe\n",
__func__, ERR_PTR(ret));
}
@@ -874,9 +891,27 @@ static void f81604_write_bulk_callback(struct urb *urb)
if (!netif_device_present(netdev))
return;
- if (urb->status)
- netdev_info(netdev, "%s: Tx URB error: %pe\n", __func__,
- ERR_PTR(urb->status));
+ if (!urb->status)
+ return;
+
+ switch (urb->status) {
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ return;
+ default:
+ break;
+ }
+
+ if (net_ratelimit())
+ netdev_err(netdev, "%s: Tx URB error: %pe\n", __func__,
+ ERR_PTR(urb->status));
+
+ can_free_echo_skb(netdev, 0, NULL);
+ netdev->stats.tx_dropped++;
+ netdev->stats.tx_errors++;
+
+ netif_wake_queue(netdev);
}
static void f81604_clear_reg_work(struct work_struct *work)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 9d27d6f0c0b5..ec9a7cbbbc69 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -772,9 +772,8 @@ device_detach:
}
}
-static int gs_usb_set_bittiming(struct net_device *netdev)
+static int gs_usb_set_bittiming(struct gs_can *dev)
{
- struct gs_can *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.bittiming;
struct gs_device_bittiming dbt = {
.prop_seg = cpu_to_le32(bt->prop_seg),
@@ -791,9 +790,8 @@ static int gs_usb_set_bittiming(struct net_device *netdev)
GFP_KERNEL);
}
-static int gs_usb_set_data_bittiming(struct net_device *netdev)
+static int gs_usb_set_data_bittiming(struct gs_can *dev)
{
- struct gs_can *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.fd.data_bittiming;
struct gs_device_bittiming dbt = {
.prop_seg = cpu_to_le32(bt->prop_seg),
@@ -1057,6 +1055,20 @@ static int gs_can_open(struct net_device *netdev)
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
flags |= GS_CAN_MODE_HW_TIMESTAMP;
+ rc = gs_usb_set_bittiming(dev);
+ if (rc) {
+ netdev_err(netdev, "failed to set bittiming: %pe\n", ERR_PTR(rc));
+ goto out_usb_kill_anchored_urbs;
+ }
+
+ if (ctrlmode & CAN_CTRLMODE_FD) {
+ rc = gs_usb_set_data_bittiming(dev);
+ if (rc) {
+ netdev_err(netdev, "failed to set data bittiming: %pe\n", ERR_PTR(rc));
+ goto out_usb_kill_anchored_urbs;
+ }
+ }
+
/* finally start device */
dev->can.state = CAN_STATE_ERROR_ACTIVE;
dm.flags = cpu_to_le32(flags);
@@ -1370,7 +1382,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->can.state = CAN_STATE_STOPPED;
dev->can.clock.freq = le32_to_cpu(bt_const.fclk_can);
dev->can.bittiming_const = &dev->bt_const;
- dev->can.do_set_bittiming = gs_usb_set_bittiming;
dev->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC;
@@ -1394,7 +1405,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
* GS_CAN_FEATURE_BT_CONST_EXT is set.
*/
dev->can.fd.data_bittiming_const = &dev->bt_const;
- dev->can.fd.do_set_data_bittiming = gs_usb_set_data_bittiming;
}
if (feature & GS_CAN_FEATURE_TERMINATION) {
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index c79508b1c43e..0ea0ac75e42f 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -748,7 +748,7 @@ static void ucan_read_bulk_callback(struct urb *urb)
len = le16_to_cpu(m->len);
/* check sanity (length of content) */
- if (urb->actual_length - pos < len) {
+ if ((len == 0) || (urb->actual_length - pos < len)) {
netdev_warn(up->netdev,
"invalid message (short; no data; l:%d)\n",
urb->actual_length);
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 960685596093..de3efa3ce9a7 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -980,15 +980,19 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
ret = bcm_sf2_sw_rst(priv);
if (ret) {
pr_err("%s: failed to software reset switch\n", __func__);
+ if (!priv->wol_ports_mask)
+ clk_disable_unprepare(priv->clk);
return ret;
}
bcm_sf2_crossbar_setup(priv);
ret = bcm_sf2_cfp_resume(ds);
- if (ret)
+ if (ret) {
+ if (!priv->wol_ports_mask)
+ clk_disable_unprepare(priv->clk);
return ret;
-
+ }
if (priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(ds, true);
diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c
index 4a2cc57a628f..8b98039320ad 100644
--- a/drivers/net/dsa/microchip/ksz_ptp.c
+++ b/drivers/net/dsa/microchip/ksz_ptp.c
@@ -1108,6 +1108,7 @@ static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n)
const struct ksz_dev_ops *ops = port->ksz_dev->dev_ops;
struct ksz_irq *ptpirq = &port->ptpirq;
struct ksz_ptp_irq *ptpmsg_irq;
+ int ret;
ptpmsg_irq = &port->ptpmsg_irq[n];
ptpmsg_irq->num = irq_create_mapping(ptpirq->domain, n);
@@ -1119,9 +1120,13 @@ static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n)
strscpy(ptpmsg_irq->name, name[n]);
- return request_threaded_irq(ptpmsg_irq->num, NULL,
- ksz_ptp_msg_thread_fn, IRQF_ONESHOT,
- ptpmsg_irq->name, ptpmsg_irq);
+ ret = request_threaded_irq(ptpmsg_irq->num, NULL,
+ ksz_ptp_msg_thread_fn, IRQF_ONESHOT,
+ ptpmsg_irq->name, ptpmsg_irq);
+ if (ret)
+ irq_dispose_mapping(ptpmsg_irq->num);
+
+ return ret;
}
int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p)
diff --git a/drivers/net/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c
index b1e2094b5816..d7ab04f5afef 100644
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -149,7 +149,6 @@ static int mxl862xx_setup_mdio(struct dsa_switch *ds)
return -ENOMEM;
bus->priv = priv;
- ds->user_mii_bus = bus;
bus->name = KBUILD_MODNAME "-mii";
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
bus->read_c45 = mxl862xx_phy_read_c45_mii_bus;
diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
index c575e164368c..31fa94dac627 100644
--- a/drivers/net/dsa/realtek/rtl8365mb.c
+++ b/drivers/net/dsa/realtek/rtl8365mb.c
@@ -769,7 +769,7 @@ static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy,
out:
rtl83xx_unlock(priv);
- return 0;
+ return ret;
}
static int rtl8365mb_phy_read(struct realtek_priv *priv, int phy, int regnum)
@@ -1480,8 +1480,7 @@ static void rtl8365mb_stats_update(struct realtek_priv *priv, int port)
stats->rx_packets = cnt[RTL8365MB_MIB_ifInUcastPkts] +
cnt[RTL8365MB_MIB_ifInMulticastPkts] +
- cnt[RTL8365MB_MIB_ifInBroadcastPkts] -
- cnt[RTL8365MB_MIB_ifOutDiscards];
+ cnt[RTL8365MB_MIB_ifInBroadcastPkts];
stats->tx_packets = cnt[RTL8365MB_MIB_ifOutUcastPkts] +
cnt[RTL8365MB_MIB_ifOutMulticastPkts] +
diff --git a/drivers/net/dsa/realtek/rtl8366rb-leds.c b/drivers/net/dsa/realtek/rtl8366rb-leds.c
index 99c890681ae6..509ffd3f8db5 100644
--- a/drivers/net/dsa/realtek/rtl8366rb-leds.c
+++ b/drivers/net/dsa/realtek/rtl8366rb-leds.c
@@ -12,11 +12,11 @@ static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port)
case 0:
return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
case 1:
- return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
+ return FIELD_PREP(RTL8366RB_LED_X_1_CTRL_MASK, BIT(port));
case 2:
- return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
+ return FIELD_PREP(RTL8366RB_LED_2_X_CTRL_MASK, BIT(port));
case 3:
- return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
+ return FIELD_PREP(RTL8366RB_LED_X_3_CTRL_MASK, BIT(port));
default:
return 0;
}
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 71a817c07a90..c72c2bfdcffb 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2278,6 +2278,12 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
* change it through the dynamic interface later.
*/
dsa_switch_for_each_available_port(dp, ds) {
+ /* May be called during unbind when we unoffload a VLAN-aware
+ * bridge from port 1 while port 0 was already torn down
+ */
+ if (!dp->pl)
+ continue;
+
phylink_replay_link_begin(dp->pl);
mac[dp->index].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
}
@@ -2333,13 +2339,13 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
goto out;
}
- dsa_switch_for_each_available_port(dp, ds)
- phylink_replay_link_end(dp->pl);
-
rc = sja1105_reload_cbs(priv);
- if (rc < 0)
- goto out;
+
out:
+ dsa_switch_for_each_available_port(dp, ds)
+ if (dp->pl)
+ phylink_replay_link_end(dp->pl);
+
mutex_unlock(&priv->mgmt_lock);
mutex_unlock(&priv->fdb_lock);
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 62bcbbbe2a95..91cb63a32d99 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -697,9 +697,8 @@ free_frag:
if (q->skb) {
dev_kfree_skb(q->skb);
q->skb = NULL;
- } else {
- page_pool_put_full_page(q->page_pool, page, true);
}
+ page_pool_put_full_page(q->page_pool, page, true);
}
airoha_qdma_fill_rx_queue(q);
@@ -794,18 +793,34 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
{
- struct airoha_eth *eth = q->qdma->eth;
+ struct airoha_qdma *qdma = q->qdma;
+ struct airoha_eth *eth = qdma->eth;
+ int qid = q - &qdma->q_rx[0];
while (q->queued) {
struct airoha_queue_entry *e = &q->entry[q->tail];
+ struct airoha_qdma_desc *desc = &q->desc[q->tail];
struct page *page = virt_to_head_page(e->buf);
dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
page_pool_get_dma_dir(q->page_pool));
page_pool_put_full_page(q->page_pool, page, false);
+ /* Reset DMA descriptor */
+ WRITE_ONCE(desc->ctrl, 0);
+ WRITE_ONCE(desc->addr, 0);
+ WRITE_ONCE(desc->data, 0);
+ WRITE_ONCE(desc->msg0, 0);
+ WRITE_ONCE(desc->msg1, 0);
+ WRITE_ONCE(desc->msg2, 0);
+ WRITE_ONCE(desc->msg3, 0);
+
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
}
+
+ q->head = q->tail;
+ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
+ FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail));
}
static int airoha_qdma_init_rx(struct airoha_qdma *qdma)
@@ -2946,6 +2961,8 @@ static int airoha_register_gdm_devices(struct airoha_eth *eth)
return err;
}
+ set_bit(DEV_STATE_REGISTERED, &eth->state);
+
return 0;
}
@@ -3083,7 +3100,6 @@ static void airoha_remove(struct platform_device *pdev)
if (!port)
continue;
- airoha_dev_stop(port->dev);
unregister_netdev(port->dev);
airoha_metadata_dst_free(port);
}
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index 20e602d61e61..a97903569335 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -88,6 +88,7 @@ enum {
enum {
DEV_STATE_INITIALIZED,
+ DEV_STATE_REGISTERED,
};
enum {
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 42dbe8f93231..c2c32b6833df 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -227,7 +227,9 @@ static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr,
if (!dev)
return -ENODEV;
+ rcu_read_lock();
err = dev_fill_forward_path(dev, addr, &stack);
+ rcu_read_unlock();
if (err)
return err;
@@ -1366,6 +1368,13 @@ int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data)
struct airoha_eth *eth = ppe->eth;
int err = 0;
+ /* Netfilter flowtable can try to offload flower rules while not all
+ * the net_devices are registered or initialized. Delay offloading
+ * until all net_devices are registered in the system.
+ */
+ if (!test_bit(DEV_STATE_REGISTERED, &eth->state))
+ return -EBUSY;
+
mutex_lock(&flow_offload_mutex);
if (!eth->npu)
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index 4342e2d026f8..9eed0be4411e 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -570,6 +570,7 @@ static netdev_tx_t tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, dma_addr)) {
netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+ dev_kfree_skb_any(skb);
ret = NETDEV_TX_OK;
goto out;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index 711f295eb777..80c2c27ac9dc 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -431,7 +431,7 @@
#define MAC_SSIR_SSINC_INDEX 16
#define MAC_SSIR_SSINC_WIDTH 8
#define MAC_TCR_SS_INDEX 29
-#define MAC_TCR_SS_WIDTH 2
+#define MAC_TCR_SS_WIDTH 3
#define MAC_TCR_TE_INDEX 0
#define MAC_TCR_TE_WIDTH 1
#define MAC_TCR_VNE_INDEX 24
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 62bb4b8a68e1..23beea48ae26 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1120,7 +1120,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned long flags;
DBGPR("-->xgbe_powerdown\n");
@@ -1131,8 +1130,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
if (caller == XGMAC_DRIVER_CONTEXT)
netif_device_detach(netdev);
@@ -1148,8 +1145,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
pdata->power_down = 1;
- spin_unlock_irqrestore(&pdata->lock, flags);
-
DBGPR("<--xgbe_powerdown\n");
return 0;
@@ -1159,7 +1154,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned long flags;
DBGPR("-->xgbe_powerup\n");
@@ -1170,8 +1164,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
pdata->power_down = 0;
xgbe_napi_enable(pdata, 0);
@@ -1186,8 +1178,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
xgbe_start_timers(pdata);
- spin_unlock_irqrestore(&pdata->lock, flags);
-
DBGPR("<--xgbe_powerup\n");
return 0;
@@ -1281,20 +1271,25 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
if (ret)
goto err_napi;
+ /* Reset the phy settings */
+ ret = xgbe_phy_reset(pdata);
+ if (ret)
+ goto err_irqs;
+
+ /* Start the phy */
ret = phy_if->phy_start(pdata);
if (ret)
goto err_irqs;
hw_if->enable_tx(pdata);
hw_if->enable_rx(pdata);
+ /* Synchronize flag with hardware state after enabling TX/RX.
+ * This prevents stale state after device restart cycles.
+ */
+ pdata->data_path_stopped = false;
udp_tunnel_nic_reset_ntf(netdev);
- /* Reset the phy settings */
- ret = xgbe_phy_reset(pdata);
- if (ret)
- goto err_txrx;
-
netif_tx_start_all_queues(netdev);
xgbe_start_timers(pdata);
@@ -1304,10 +1299,6 @@ static int xgbe_start(struct xgbe_prv_data *pdata)
return 0;
-err_txrx:
- hw_if->disable_rx(pdata);
- hw_if->disable_tx(pdata);
-
err_irqs:
xgbe_free_irqs(pdata);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index d1f0419edb23..7d45ea22a02e 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -76,7 +76,6 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev)
pdata->netdev = netdev;
pdata->dev = dev;
- spin_lock_init(&pdata->lock);
spin_lock_init(&pdata->xpcs_lock);
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index c63ddb12237e..b8cf6ccfe641 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -1942,7 +1942,7 @@ static void xgbe_set_rx_adap_mode(struct xgbe_prv_data *pdata,
static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata)
{
struct xgbe_phy_data *phy_data = pdata->phy_data;
- unsigned int reg;
+ int reg;
/* step 2: force PCS to send RX_ADAPT Req to PHY */
XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL4,
@@ -1964,11 +1964,20 @@ static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata)
/* Step 4: Check for Block lock */
- /* Link status is latched low, so read once to clear
- * and then read again to get current state
- */
- reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ if (reg < 0)
+ goto set_mode;
+
+ /* Link status is latched low so that momentary link drops
+ * can be detected. If link was already down read again
+ * to get the latest state.
+ */
+ if (!pdata->phy.link && !(reg & MDIO_STAT1_LSTATUS)) {
+ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1);
+ if (reg < 0)
+ goto set_mode;
+ }
+
if (reg & MDIO_STAT1_LSTATUS) {
/* If the block lock is found, update the helpers
* and declare the link up
@@ -2008,6 +2017,48 @@ rx_adapt_reinit:
xgbe_rx_adaptation(pdata);
}
+/*
+ * xgbe_phy_stop_data_path - Stop TX/RX to prevent packet corruption
+ * @pdata: driver private data
+ *
+ * This function stops the data path (TX and RX) to prevent packet
+ * corruption during critical PHY operations like RX adaptation.
+ * Must be called before initiating RX adaptation when link goes down.
+ */
+static void xgbe_phy_stop_data_path(struct xgbe_prv_data *pdata)
+{
+ if (pdata->data_path_stopped)
+ return;
+
+ /* Stop TX/RX to prevent packet corruption during RX adaptation */
+ pdata->hw_if.disable_tx(pdata);
+ pdata->hw_if.disable_rx(pdata);
+ pdata->data_path_stopped = true;
+
+ netif_dbg(pdata, link, pdata->netdev,
+ "stopping data path for RX adaptation\n");
+}
+
+/*
+ * xgbe_phy_start_data_path - Re-enable TX/RX after RX adaptation
+ * @pdata: driver private data
+ *
+ * This function re-enables the data path (TX and RX) after RX adaptation
+ * has completed successfully. Only called when link is confirmed up.
+ */
+static void xgbe_phy_start_data_path(struct xgbe_prv_data *pdata)
+{
+ if (!pdata->data_path_stopped)
+ return;
+
+ pdata->hw_if.enable_rx(pdata);
+ pdata->hw_if.enable_tx(pdata);
+ pdata->data_path_stopped = false;
+
+ netif_dbg(pdata, link, pdata->netdev,
+ "restarting data path after RX adaptation\n");
+}
+
static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
{
int reg;
@@ -2801,13 +2852,27 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
if (pdata->en_rx_adap) {
/* if the link is available and adaptation is done,
* declare link up
+ *
+ * Note: When link is up and adaptation is done, we can
+ * safely re-enable the data path if it was stopped
+ * for adaptation.
*/
- if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done)
+ if ((reg & MDIO_STAT1_LSTATUS) && pdata->rx_adapt_done) {
+ xgbe_phy_start_data_path(pdata);
return 1;
+ }
/* If either link is not available or adaptation is not done,
* retrigger the adaptation logic. (if the mode is not set,
* then issue mailbox command first)
*/
+
+ /* CRITICAL: Stop data path BEFORE triggering RX adaptation
+ * to prevent CRC errors from packets corrupted during
+ * the adaptation process. This is especially important
+ * when AN is OFF in 10G KR mode.
+ */
+ xgbe_phy_stop_data_path(pdata);
+
if (pdata->mode_set) {
xgbe_phy_rx_adaptation(pdata);
} else {
@@ -2815,8 +2880,11 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
xgbe_phy_set_mode(pdata, phy_data->cur_mode);
}
- if (pdata->rx_adapt_done)
+ if (pdata->rx_adapt_done) {
+ /* Adaptation complete, safe to re-enable data path */
+ xgbe_phy_start_data_path(pdata);
return 1;
+ }
} else if (reg & MDIO_STAT1_LSTATUS)
return 1;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 1269b8ce9249..438033a71523 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -1004,9 +1004,6 @@ struct xgbe_prv_data {
unsigned int pp3;
unsigned int pp4;
- /* Overall device lock */
- spinlock_t lock;
-
/* XPCS indirect addressing lock */
spinlock_t xpcs_lock;
unsigned int xpcs_window_def_reg;
@@ -1246,6 +1243,10 @@ struct xgbe_prv_data {
bool en_rx_adap;
int rx_adapt_retries;
bool rx_adapt_done;
+ /* Flag to track if data path (TX/RX) was stopped for RX adaptation.
+ * This prevents packet corruption during the adaptation window.
+ */
+ bool data_path_stopped;
bool mode_set;
bool sph;
};
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index 8283aeee35fb..dde4046cbf01 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -934,6 +934,17 @@ int arc_emac_probe(struct net_device *ndev, int interface)
/* Set poll rate so that it polls every 1 ms */
arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
+ /*
+ * Put the device into a known quiescent state before requesting
+ * the IRQ. Clear only EMAC interrupt status bits here; leave the
+ * MDIO completion bit alone and avoid writing TXPL_MASK, which is
+ * used to force TX polling rather than acknowledge interrupts.
+ */
+ arc_reg_set(priv, R_ENABLE, 0);
+ arc_reg_set(priv, R_STATUS, RXINT_MASK | TXINT_MASK | ERR_MASK |
+ TXCH_MASK | MSER_MASK | RXCR_MASK |
+ RXFR_MASK | RXFL_MASK);
+
ndev->irq = irq;
dev_info(dev, "IRQ is %d\n", ndev->irq);
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index cd7dddeb91dd..9787c1857e13 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -25,7 +25,7 @@ config B44
select SSB
select MII
select PHYLIB
- select FIXED_PHY if BCM47XX
+ select FIXED_PHY
help
If you have a network (Ethernet) controller of this type, say Y
or M here.
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
index aa6d8606849f..972474893a6b 100644
--- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
@@ -1152,12 +1152,6 @@ void bcmasp_enable_wol(struct bcmasp_intf *intf, bool en)
}
}
-static void bcmasp_wol_irq_destroy(struct bcmasp_priv *priv)
-{
- if (priv->wol_irq > 0)
- free_irq(priv->wol_irq, priv);
-}
-
static void bcmasp_eee_fixup(struct bcmasp_intf *intf, bool en)
{
u32 reg, phy_lpi_overwrite;
@@ -1255,7 +1249,7 @@ static int bcmasp_probe(struct platform_device *pdev)
if (priv->irq <= 0)
return -EINVAL;
- priv->clk = devm_clk_get_optional_enabled(dev, "sw_asp");
+ priv->clk = devm_clk_get_optional(dev, "sw_asp");
if (IS_ERR(priv->clk))
return dev_err_probe(dev, PTR_ERR(priv->clk),
"failed to request clock\n");
@@ -1283,6 +1277,10 @@ static int bcmasp_probe(struct platform_device *pdev)
bcmasp_set_pdata(priv, pdata);
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to start clock\n");
+
/* Enable all clocks to ensure successful probing */
bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0);
@@ -1294,8 +1292,10 @@ static int bcmasp_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, priv->irq, bcmasp_isr, 0,
pdev->name, priv);
- if (ret)
- return dev_err_probe(dev, ret, "failed to request ASP interrupt: %d", ret);
+ if (ret) {
+ dev_err(dev, "Failed to request ASP interrupt: %d", ret);
+ goto err_clock_disable;
+ }
/* Register mdio child nodes */
of_platform_populate(dev->of_node, bcmasp_mdio_of_match, NULL, dev);
@@ -1307,13 +1307,17 @@ static int bcmasp_probe(struct platform_device *pdev)
priv->mda_filters = devm_kcalloc(dev, priv->num_mda_filters,
sizeof(*priv->mda_filters), GFP_KERNEL);
- if (!priv->mda_filters)
- return -ENOMEM;
+ if (!priv->mda_filters) {
+ ret = -ENOMEM;
+ goto err_clock_disable;
+ }
priv->net_filters = devm_kcalloc(dev, priv->num_net_filters,
sizeof(*priv->net_filters), GFP_KERNEL);
- if (!priv->net_filters)
- return -ENOMEM;
+ if (!priv->net_filters) {
+ ret = -ENOMEM;
+ goto err_clock_disable;
+ }
bcmasp_core_init_filters(priv);
@@ -1322,7 +1326,8 @@ static int bcmasp_probe(struct platform_device *pdev)
ports_node = of_find_node_by_name(dev->of_node, "ethernet-ports");
if (!ports_node) {
dev_warn(dev, "No ports found\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_clock_disable;
}
i = 0;
@@ -1344,8 +1349,6 @@ static int bcmasp_probe(struct platform_device *pdev)
*/
bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE);
- clk_disable_unprepare(priv->clk);
-
/* Now do the registration of the network ports which will take care
* of managing the clock properly.
*/
@@ -1358,13 +1361,16 @@ static int bcmasp_probe(struct platform_device *pdev)
count++;
}
+ clk_disable_unprepare(priv->clk);
+
dev_info(dev, "Initialized %d port(s)\n", count);
return ret;
err_cleanup:
- bcmasp_wol_irq_destroy(priv);
bcmasp_remove_intfs(priv);
+err_clock_disable:
+ clk_disable_unprepare(priv->clk);
return ret;
}
@@ -1376,7 +1382,6 @@ static void bcmasp_remove(struct platform_device *pdev)
if (!priv)
return;
- bcmasp_wol_irq_destroy(priv);
bcmasp_remove_intfs(priv);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index e062d5d400da..3f775196ef81 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -2929,6 +2929,8 @@ static int bnxt_async_event_process(struct bnxt *bp,
u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1);
u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2);
+ if (type >= ARRAY_SIZE(bp->bs_trace))
+ goto async_event_process_exit;
bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset);
goto async_event_process_exit;
}
@@ -6232,6 +6234,9 @@ int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp,
int rc;
set_bit(BNXT_FLTR_FW_DELETED, &fltr->base.state);
+ if (!test_bit(BNXT_STATE_OPEN, &bp->state))
+ return 0;
+
rc = hwrm_req_init(bp, req, HWRM_CFA_NTUPLE_FILTER_FREE);
if (rc)
return rc;
@@ -8040,6 +8045,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
if (!ulp_msix)
bnxt_set_ulp_stat_ctxs(bp, 0);
+ else
+ bnxt_set_dflt_ulp_stat_ctxs(bp);
if (ulp_msix > bp->ulp_num_msix_want)
ulp_msix = bp->ulp_num_msix_want;
@@ -8666,7 +8673,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
struct hwrm_func_backing_store_qcaps_v2_output *resp;
struct hwrm_func_backing_store_qcaps_v2_input *req;
struct bnxt_ctx_mem_info *ctx = bp->ctx;
- u16 type;
+ u16 type, next_type = 0;
int rc;
rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2);
@@ -8682,7 +8689,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
resp = hwrm_req_hold(bp, req);
- for (type = 0; type < BNXT_CTX_V2_MAX; ) {
+ for (type = 0; type < BNXT_CTX_V2_MAX; type = next_type) {
struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
u8 init_val, init_off, i;
u32 max_entries;
@@ -8695,7 +8702,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
if (rc)
goto ctx_done;
flags = le32_to_cpu(resp->flags);
- type = le16_to_cpu(resp->next_valid_type);
+ next_type = le16_to_cpu(resp->next_valid_type);
if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) {
bnxt_free_one_ctx_mem(bp, ctxm, true);
continue;
@@ -8710,7 +8717,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
else
continue;
}
- ctxm->type = le16_to_cpu(resp->type);
+ ctxm->type = type;
ctxm->entry_size = entry_size;
ctxm->flags = flags;
ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
@@ -10879,12 +10886,10 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx,
struct bnxt_ntuple_filter *ntp_fltr;
int i;
- if (netif_running(bp->dev)) {
- bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic);
- for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) {
- if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
- bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i);
- }
+ bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic);
+ for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) {
+ if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
+ bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i);
}
if (!all)
return;
@@ -12989,6 +12994,21 @@ static int bnxt_tx_nr_rings_per_tc(struct bnxt *bp)
return bp->num_tc ? bp->tx_nr_rings / bp->num_tc : bp->tx_nr_rings;
}
+static void bnxt_set_xdp_tx_rings(struct bnxt *bp)
+{
+ bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc;
+ bp->tx_nr_rings += bp->tx_nr_rings_xdp;
+}
+
+static void bnxt_adj_tx_rings(struct bnxt *bp)
+{
+ /* Make adjustments if reserved TX rings are less than requested */
+ bp->tx_nr_rings -= bp->tx_nr_rings_xdp;
+ bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+ if (bp->tx_nr_rings_xdp)
+ bnxt_set_xdp_tx_rings(bp);
+}
+
static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
{
int rc = 0;
@@ -13006,13 +13026,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
if (rc)
return rc;
- /* Make adjustments if reserved TX rings are less than requested */
- bp->tx_nr_rings -= bp->tx_nr_rings_xdp;
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
- if (bp->tx_nr_rings_xdp) {
- bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc;
- bp->tx_nr_rings += bp->tx_nr_rings_xdp;
- }
+ bnxt_adj_tx_rings(bp);
rc = bnxt_alloc_mem(bp, irq_re_init);
if (rc) {
netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
@@ -15433,11 +15447,19 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+void bnxt_set_cp_rings(struct bnxt *bp, bool sh)
+{
+ int tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+
+ bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
+ tx_cp + bp->rx_nr_rings;
+}
+
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
{
struct bnxt *bp = netdev_priv(dev);
bool sh = false;
- int rc, tx_cp;
+ int rc;
if (tc > bp->max_tc) {
netdev_err(dev, "Too many traffic classes requested: %d. Max supported is %d.\n",
@@ -15470,9 +15492,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
bp->num_tc = 0;
}
bp->tx_nr_rings += bp->tx_nr_rings_xdp;
- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
- bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
- tx_cp + bp->rx_nr_rings;
+ bnxt_set_cp_rings(bp, sh);
if (netif_running(bp->dev))
return bnxt_open_nic(bp, true, false);
@@ -16522,6 +16542,19 @@ static void bnxt_trim_dflt_sh_rings(struct bnxt *bp)
bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
}
+static void bnxt_adj_dflt_rings(struct bnxt *bp, bool sh)
+{
+ if (sh)
+ bnxt_trim_dflt_sh_rings(bp);
+ else
+ bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
+ bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
+ if (sh && READ_ONCE(bp->xdp_prog)) {
+ bnxt_set_xdp_tx_rings(bp);
+ bnxt_set_cp_rings(bp, true);
+ }
+}
+
static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
{
int dflt_rings, max_rx_rings, max_tx_rings, rc;
@@ -16547,11 +16580,8 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
return rc;
bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings);
bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings);
- if (sh)
- bnxt_trim_dflt_sh_rings(bp);
- else
- bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings;
- bp->tx_nr_rings = bnxt_tx_nr_rings(bp);
+
+ bnxt_adj_dflt_rings(bp, sh);
avail_msix = bnxt_get_max_func_irqs(bp) - bp->cp_nr_rings;
if (avail_msix >= BNXT_MIN_ROCE_CP_RINGS) {
@@ -16564,16 +16594,17 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
rc = __bnxt_reserve_rings(bp);
if (rc && rc != -ENODEV)
netdev_warn(bp->dev, "Unable to reserve tx rings\n");
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+
+ bnxt_adj_tx_rings(bp);
if (sh)
- bnxt_trim_dflt_sh_rings(bp);
+ bnxt_adj_dflt_rings(bp, true);
/* Rings may have been trimmed, re-reserve the trimmed rings. */
if (bnxt_need_reserve_rings(bp)) {
rc = __bnxt_reserve_rings(bp);
if (rc && rc != -ENODEV)
netdev_warn(bp->dev, "2nd rings reservation failed.\n");
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+ bnxt_adj_tx_rings(bp);
}
if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
bp->rx_nr_rings++;
@@ -16607,7 +16638,7 @@ static int bnxt_init_dflt_ring_mode(struct bnxt *bp)
if (rc)
goto init_dflt_ring_err;
- bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp);
+ bnxt_adj_tx_rings(bp);
bnxt_set_dflt_rfs(bp);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 9a41b9e0423c..4bc7f7aeaab3 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -2146,7 +2146,7 @@ enum board_idx {
};
#define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc)
-#define BNXT_TRACE_MAX 11
+#define BNXT_TRACE_MAX (DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ERR_QPC_TRACE + 1)
struct bnxt_bs_trace_info {
u8 *magic_byte;
@@ -2985,6 +2985,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
int tx_xdp);
int bnxt_fw_init_one(struct bnxt *bp);
bool bnxt_hwrm_reset_permitted(struct bnxt *bp);
+void bnxt_set_cp_rings(struct bnxt *bp, bool sh);
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
struct bnxt_ntuple_filter *bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp,
struct bnxt_ntuple_filter *fltr, u32 idx);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index ba47e8294fff..0407aa1b3190 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -945,7 +945,6 @@ static int bnxt_set_channels(struct net_device *dev,
bool sh = false;
int tx_xdp = 0;
int rc = 0;
- int tx_cp;
if (channel->other_count)
return -EINVAL;
@@ -979,8 +978,8 @@ static int bnxt_set_channels(struct net_device *dev,
if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=
bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) &&
- netif_is_rxfh_configured(dev)) {
- netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n");
+ (netif_is_rxfh_configured(dev) || bp->num_rss_ctx)) {
+ netdev_warn(dev, "RSS table size change required, RSS table entries must be default (with no additional RSS contexts present) to proceed\n");
return -EINVAL;
}
@@ -1013,9 +1012,7 @@ static int bnxt_set_channels(struct net_device *dev,
if (tcs > 1)
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
- bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
- tx_cp + bp->rx_nr_rings;
+ bnxt_set_cp_rings(bp, sh);
/* After changing number of rx channels, update NTUPLE feature. */
netdev_update_features(dev);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index 85cbeb35681c..bebe37e139c9 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -384,7 +384,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
struct net_device *dev = bp->dev;
- int tx_xdp = 0, tx_cp, rc, tc;
+ int tx_xdp = 0, rc, tc;
struct bpf_prog *old;
netdev_assert_locked(dev);
@@ -431,8 +431,7 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
- tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
- bp->cp_nr_rings = max_t(int, tx_cp, bp->rx_nr_rings);
+ bnxt_set_cp_rings(bp, true);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index a71cd729fde6..482a31e7b72b 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -1342,8 +1342,7 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev,
}
}
-void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
- bool tx_lpi_enabled)
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
u32 off = priv->hw_params->tbuf_offset + TBUF_ENERGY_CTRL;
@@ -1363,7 +1362,7 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
/* Enable EEE and switch to a 27Mhz clock automatically */
reg = bcmgenet_readl(priv->base + off);
- if (tx_lpi_enabled)
+ if (enable)
reg |= TBUF_EEE_EN | TBUF_PM_EN;
else
reg &= ~(TBUF_EEE_EN | TBUF_PM_EN);
@@ -1382,14 +1381,12 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
priv->clk_eee_enabled = false;
}
- priv->eee.eee_enabled = enable;
- priv->eee.tx_lpi_enabled = tx_lpi_enabled;
}
static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
- struct ethtool_keee *p = &priv->eee;
+ int ret;
if (GENET_IS_V1(priv))
return -EOPNOTSUPP;
@@ -1397,17 +1394,21 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e)
if (!dev->phydev)
return -ENODEV;
- e->tx_lpi_enabled = p->tx_lpi_enabled;
+ ret = phy_ethtool_get_eee(dev->phydev, e);
+ if (ret)
+ return ret;
+
+ /* tx_lpi_timer is maintained by the MAC hardware register; the
+ * PHY-level eee_cfg timer is not set for GENET.
+ */
e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER);
- return phy_ethtool_get_eee(dev->phydev, e);
+ return 0;
}
static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
- struct ethtool_keee *p = &priv->eee;
- bool active;
if (GENET_IS_V1(priv))
return -EOPNOTSUPP;
@@ -1415,15 +1416,7 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e)
if (!dev->phydev)
return -ENODEV;
- p->eee_enabled = e->eee_enabled;
-
- if (!p->eee_enabled) {
- bcmgenet_eee_enable_set(dev, false, false);
- } else {
- active = phy_init_eee(dev->phydev, false) >= 0;
- bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER);
- bcmgenet_eee_enable_set(dev, active, e->tx_lpi_enabled);
- }
+ bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER);
return phy_ethtool_set_eee(dev->phydev, e);
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 5ec3979779ec..9e4110c7fdf6 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -665,8 +665,6 @@ struct bcmgenet_priv {
u8 sopass[SOPASS_MAX];
struct bcmgenet_mib_counters mib;
-
- struct ethtool_keee eee;
};
static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv)
@@ -749,7 +747,6 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
int bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
enum bcmgenet_power_mode mode);
-void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
- bool tx_lpi_enabled);
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable);
#endif /* __BCMGENET_H__ */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 8fb551288298..96d5d4f7f51f 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -123,7 +123,7 @@ static int bcmgenet_poll_wol_status(struct bcmgenet_priv *priv)
while (!(bcmgenet_rbuf_readl(priv, RBUF_STATUS)
& RBUF_STATUS_WOL)) {
retries++;
- if (retries > 5) {
+ if (retries > 50) {
netdev_crit(dev, "polling wol mode timeout\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 38f854b94a79..a4e0d5a68268 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -29,7 +29,6 @@ static void bcmgenet_mac_config(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev);
struct phy_device *phydev = dev->phydev;
u32 reg, cmd_bits = 0;
- bool active;
/* speed */
if (phydev->speed == SPEED_1000)
@@ -90,10 +89,6 @@ static void bcmgenet_mac_config(struct net_device *dev)
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
spin_unlock_bh(&priv->reg_lock);
- active = phy_init_eee(phydev, 0) >= 0;
- bcmgenet_eee_enable_set(dev,
- priv->eee.eee_enabled && active,
- priv->eee.tx_lpi_enabled);
}
/* setup netdev link state when PHY link status change and
@@ -113,6 +108,8 @@ void bcmgenet_mii_setup(struct net_device *dev)
bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
}
+ bcmgenet_eee_enable_set(dev, phydev->enable_tx_lpi);
+
phy_print_status(phydev);
}
@@ -412,6 +409,9 @@ int bcmgenet_mii_probe(struct net_device *dev)
/* Indicate that the MAC is responsible for PHY PM */
dev->phydev->mac_managed_pm = true;
+ if (!GENET_IS_V1(priv))
+ phy_support_eee(dev->phydev);
+
return 0;
}
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 2328fce33644..73a4b569b03e 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -12299,7 +12299,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
advertising);
- if (netif_running(dev) && tp->link_up) {
+ if (netif_running(dev) && netif_carrier_ok(dev)) {
cmd->base.speed = tp->link_config.active_speed;
cmd->base.duplex = tp->link_config.active_duplex;
ethtool_convert_legacy_u32_to_link_mode(
@@ -17029,6 +17029,13 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
return err;
}
+static int tg3_is_default_mac_address(u8 *addr)
+{
+ static const u8 default_mac_address[ETH_ALEN] = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 };
+
+ return ether_addr_equal(default_mac_address, addr);
+}
+
static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
{
u32 hi, lo, mac_offset;
@@ -17102,6 +17109,10 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr)
if (!is_valid_ether_addr(addr))
return -EINVAL;
+
+ if (tg3_is_default_mac_address(addr))
+ return device_get_mac_address(&tp->pdev->dev, addr);
+
return 0;
}
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 5bc35f651ebd..99e7d5cf3786 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -36,6 +36,7 @@
#include <linux/tcp.h>
#include <linux/types.h>
#include <linux/udp.h>
+#include <linux/gcd.h>
#include <net/pkt_sched.h>
#include "macb.h"
@@ -668,6 +669,97 @@ static void macb_mac_link_down(struct phylink_config *config, unsigned int mode,
netif_tx_stop_all_queues(ndev);
}
+/* Use juggling algorithm to left rotate tx ring and tx skb array */
+static void gem_shuffle_tx_one_ring(struct macb_queue *queue)
+{
+ unsigned int head, tail, count, ring_size, desc_size;
+ struct macb_tx_skb tx_skb, *skb_curr, *skb_next;
+ struct macb_dma_desc *desc_curr, *desc_next;
+ unsigned int i, cycles, shift, curr, next;
+ struct macb *bp = queue->bp;
+ unsigned char desc[24];
+ unsigned long flags;
+
+ desc_size = macb_dma_desc_get_size(bp);
+
+ if (WARN_ON_ONCE(desc_size > ARRAY_SIZE(desc)))
+ return;
+
+ spin_lock_irqsave(&queue->tx_ptr_lock, flags);
+ head = queue->tx_head;
+ tail = queue->tx_tail;
+ ring_size = bp->tx_ring_size;
+ count = CIRC_CNT(head, tail, ring_size);
+
+ if (!(tail % ring_size))
+ goto unlock;
+
+ if (!count) {
+ queue->tx_head = 0;
+ queue->tx_tail = 0;
+ goto unlock;
+ }
+
+ shift = tail % ring_size;
+ cycles = gcd(ring_size, shift);
+
+ for (i = 0; i < cycles; i++) {
+ memcpy(&desc, macb_tx_desc(queue, i), desc_size);
+ memcpy(&tx_skb, macb_tx_skb(queue, i),
+ sizeof(struct macb_tx_skb));
+
+ curr = i;
+ next = (curr + shift) % ring_size;
+
+ while (next != i) {
+ desc_curr = macb_tx_desc(queue, curr);
+ desc_next = macb_tx_desc(queue, next);
+
+ memcpy(desc_curr, desc_next, desc_size);
+
+ if (next == ring_size - 1)
+ desc_curr->ctrl &= ~MACB_BIT(TX_WRAP);
+ if (curr == ring_size - 1)
+ desc_curr->ctrl |= MACB_BIT(TX_WRAP);
+
+ skb_curr = macb_tx_skb(queue, curr);
+ skb_next = macb_tx_skb(queue, next);
+ memcpy(skb_curr, skb_next, sizeof(struct macb_tx_skb));
+
+ curr = next;
+ next = (curr + shift) % ring_size;
+ }
+
+ desc_curr = macb_tx_desc(queue, curr);
+ memcpy(desc_curr, &desc, desc_size);
+ if (i == ring_size - 1)
+ desc_curr->ctrl &= ~MACB_BIT(TX_WRAP);
+ if (curr == ring_size - 1)
+ desc_curr->ctrl |= MACB_BIT(TX_WRAP);
+ memcpy(macb_tx_skb(queue, curr), &tx_skb,
+ sizeof(struct macb_tx_skb));
+ }
+
+ queue->tx_head = count;
+ queue->tx_tail = 0;
+
+ /* Make descriptor updates visible to hardware */
+ wmb();
+
+unlock:
+ spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);
+}
+
+/* Rotate the queue so that the tail is at index 0 */
+static void gem_shuffle_tx_rings(struct macb *bp)
+{
+ struct macb_queue *queue;
+ int q;
+
+ for (q = 0, queue = bp->queues; q < bp->num_queues; q++, queue++)
+ gem_shuffle_tx_one_ring(queue);
+}
+
static void macb_mac_link_up(struct phylink_config *config,
struct phy_device *phy,
unsigned int mode, phy_interface_t interface,
@@ -706,8 +798,6 @@ static void macb_mac_link_up(struct phylink_config *config,
ctrl |= MACB_BIT(PAE);
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
- queue->tx_head = 0;
- queue->tx_tail = 0;
queue_writel(queue, IER,
bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
}
@@ -721,8 +811,10 @@ static void macb_mac_link_up(struct phylink_config *config,
spin_unlock_irqrestore(&bp->lock, flags);
- if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
+ if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
macb_set_tx_clk(bp, speed);
+ gem_shuffle_tx_rings(bp);
+ }
/* Enable Rx and Tx; Enable PTP unicast */
ctrl = macb_readl(bp, NCR);
@@ -979,7 +1071,7 @@ static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budge
}
if (tx_skb->skb) {
- napi_consume_skb(tx_skb->skb, budget);
+ dev_consume_skb_any(tx_skb->skb);
tx_skb->skb = NULL;
}
}
@@ -2577,6 +2669,14 @@ static void macb_init_tieoff(struct macb *bp)
desc->ctrl = 0;
}
+static void gem_init_rx_ring(struct macb_queue *queue)
+{
+ queue->rx_tail = 0;
+ queue->rx_prepared_head = 0;
+
+ gem_rx_refill(queue);
+}
+
static void gem_init_rings(struct macb *bp)
{
struct macb_queue *queue;
@@ -2594,10 +2694,7 @@ static void gem_init_rings(struct macb *bp)
queue->tx_head = 0;
queue->tx_tail = 0;
- queue->rx_tail = 0;
- queue->rx_prepared_head = 0;
-
- gem_rx_refill(queue);
+ gem_init_rx_ring(queue);
}
macb_init_tieoff(bp);
@@ -3127,7 +3224,7 @@ static void gem_get_ethtool_stats(struct net_device *dev,
spin_lock_irq(&bp->stats_lock);
gem_update_stats(bp);
memcpy(data, &bp->ethtool_stats, sizeof(u64)
- * (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES));
+ * (GEM_STATS_LEN + QUEUE_STATS_LEN * bp->num_queues));
spin_unlock_irq(&bp->stats_lock);
}
@@ -3886,6 +3983,9 @@ static int gem_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
struct macb *bp = netdev_priv(netdev);
int ret;
+ if (!(netdev->hw_features & NETIF_F_NTUPLE))
+ return -EOPNOTSUPP;
+
switch (cmd->cmd) {
case ETHTOOL_SRXCLSRLINS:
if ((cmd->fs.location >= bp->max_tuples)
@@ -5676,9 +5776,9 @@ static int __maybe_unused macb_suspend(struct device *dev)
struct macb_queue *queue;
struct in_device *idev;
unsigned long flags;
+ u32 tmp, ifa_local;
unsigned int q;
int err;
- u32 tmp;
if (!device_may_wakeup(&bp->dev->dev))
phy_exit(bp->phy);
@@ -5687,14 +5787,21 @@ static int __maybe_unused macb_suspend(struct device *dev)
return 0;
if (bp->wol & MACB_WOL_ENABLED) {
- /* Check for IP address in WOL ARP mode */
- idev = __in_dev_get_rcu(bp->dev);
- if (idev)
- ifa = rcu_dereference(idev->ifa_list);
- if ((bp->wolopts & WAKE_ARP) && !ifa) {
- netdev_err(netdev, "IP address not assigned as required by WoL walk ARP\n");
- return -EOPNOTSUPP;
+ if (bp->wolopts & WAKE_ARP) {
+ /* Check for IP address in WOL ARP mode */
+ rcu_read_lock();
+ idev = __in_dev_get_rcu(bp->dev);
+ if (idev)
+ ifa = rcu_dereference(idev->ifa_list);
+ if (!ifa) {
+ rcu_read_unlock();
+ netdev_err(netdev, "IP address not assigned as required by WoL walk ARP\n");
+ return -EOPNOTSUPP;
+ }
+ ifa_local = be32_to_cpu(ifa->ifa_local);
+ rcu_read_unlock();
}
+
spin_lock_irqsave(&bp->lock, flags);
/* Disable Tx and Rx engines before disabling the queues,
@@ -5733,8 +5840,9 @@ static int __maybe_unused macb_suspend(struct device *dev)
if (bp->wolopts & WAKE_ARP) {
tmp |= MACB_BIT(ARP);
/* write IP address into register */
- tmp |= MACB_BFEXT(IP, be32_to_cpu(ifa->ifa_local));
+ tmp |= MACB_BFEXT(IP, ifa_local);
}
+ spin_unlock_irqrestore(&bp->lock, flags);
/* Change interrupt handler and
* Enable WoL IRQ on queue 0
@@ -5747,11 +5855,12 @@ static int __maybe_unused macb_suspend(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
+ spin_lock_irqsave(&bp->lock, flags);
queue_writel(bp->queues, IER, GEM_BIT(WOL));
gem_writel(bp, WOL, tmp);
+ spin_unlock_irqrestore(&bp->lock, flags);
} else {
err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt,
IRQF_SHARED, netdev->name, bp->queues);
@@ -5759,13 +5868,13 @@ static int __maybe_unused macb_suspend(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
+ spin_lock_irqsave(&bp->lock, flags);
queue_writel(bp->queues, IER, MACB_BIT(WOL));
macb_writel(bp, WOL, tmp);
+ spin_unlock_irqrestore(&bp->lock, flags);
}
- spin_unlock_irqrestore(&bp->lock, flags);
enable_irq_wake(bp->queues[0].irq);
}
@@ -5832,6 +5941,8 @@ static int __maybe_unused macb_resume(struct device *dev)
queue_readl(bp->queues, ISR);
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
queue_writel(bp->queues, ISR, -1);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
/* Replace interrupt handler on queue 0 */
devm_free_irq(dev, bp->queues[0].irq, bp->queues);
err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt,
@@ -5840,10 +5951,8 @@ static int __maybe_unused macb_resume(struct device *dev)
dev_err(dev,
"Unable to request IRQ %d (error %d)\n",
bp->queues[0].irq, err);
- spin_unlock_irqrestore(&bp->lock, flags);
return err;
}
- spin_unlock_irqrestore(&bp->lock, flags);
disable_irq_wake(bp->queues[0].irq);
@@ -5855,8 +5964,18 @@ static int __maybe_unused macb_resume(struct device *dev)
rtnl_unlock();
}
+ if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC))
+ macb_init_buffers(bp);
+
for (q = 0, queue = bp->queues; q < bp->num_queues;
++q, ++queue) {
+ if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) {
+ if (macb_is_gem(bp))
+ gem_init_rx_ring(queue);
+ else
+ macb_init_rx_ring(queue);
+ }
+
napi_enable(&queue->napi_rx);
napi_enable(&queue->napi_tx);
}
diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c
index fc4f5aee6ab3..b79dec17e6b0 100644
--- a/drivers/net/ethernet/cadence/macb_pci.c
+++ b/drivers/net/ethernet/cadence/macb_pci.c
@@ -96,10 +96,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
err_plat_dev_register:
- clk_unregister(plat_data.hclk);
+ clk_unregister_fixed_rate(plat_data.hclk);
err_hclk_register:
- clk_unregister(plat_data.pclk);
+ clk_unregister_fixed_rate(plat_data.pclk);
err_pclk_register:
return err;
@@ -109,10 +109,12 @@ static void macb_remove(struct pci_dev *pdev)
{
struct platform_device *plat_dev = pci_get_drvdata(pdev);
struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev);
+ struct clk *pclk = plat_data->pclk;
+ struct clk *hclk = plat_data->hclk;
- clk_unregister(plat_data->pclk);
- clk_unregister(plat_data->hclk);
platform_device_unregister(plat_dev);
+ clk_unregister_fixed_rate(pclk);
+ clk_unregister_fixed_rate(hclk);
}
static const struct pci_device_id dev_id_table[] = {
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index c9e77819196e..d91f7b1aa39c 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -357,8 +357,10 @@ void gem_ptp_remove(struct net_device *ndev)
{
struct macb *bp = netdev_priv(ndev);
- if (bp->ptp_clock)
+ if (bp->ptp_clock) {
ptp_clock_unregister(bp->ptp_clock);
+ bp->ptp_clock = NULL;
+ }
gem_ptp_clear_timer(bp);
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 1e91e79c8134..6d2fe5c2f390 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -977,19 +977,19 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
GFP_KERNEL);
if (!priv->tx_skbs)
- return -ENOMEM;
+ goto err_free_rx_skbs;
/* Allocate descriptors */
priv->rxdes = dma_alloc_coherent(priv->dev,
MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes),
&priv->rxdes_dma, GFP_KERNEL);
if (!priv->rxdes)
- return -ENOMEM;
+ goto err_free_tx_skbs;
priv->txdes = dma_alloc_coherent(priv->dev,
MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes),
&priv->txdes_dma, GFP_KERNEL);
if (!priv->txdes)
- return -ENOMEM;
+ goto err_free_rxdes;
/* Allocate scratch packet buffer */
priv->rx_scratch = dma_alloc_coherent(priv->dev,
@@ -997,9 +997,29 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
&priv->rx_scratch_dma,
GFP_KERNEL);
if (!priv->rx_scratch)
- return -ENOMEM;
+ goto err_free_txdes;
return 0;
+
+err_free_txdes:
+ dma_free_coherent(priv->dev,
+ MAX_TX_QUEUE_ENTRIES *
+ sizeof(struct ftgmac100_txdes),
+ priv->txdes, priv->txdes_dma);
+ priv->txdes = NULL;
+err_free_rxdes:
+ dma_free_coherent(priv->dev,
+ MAX_RX_QUEUE_ENTRIES *
+ sizeof(struct ftgmac100_rxdes),
+ priv->rxdes, priv->rxdes_dma);
+ priv->rxdes = NULL;
+err_free_tx_skbs:
+ kfree(priv->tx_skbs);
+ priv->tx_skbs = NULL;
+err_free_rx_skbs:
+ kfree(priv->rx_skbs);
+ priv->rx_skbs = NULL;
+ return -ENOMEM;
}
static void ftgmac100_init_rings(struct ftgmac100 *priv)
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index e2a591cf9601..11edbb46a118 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -28,7 +28,7 @@ config FEC
depends on PTP_1588_CLOCK_OPTIONAL
select CRC32
select PHYLIB
- select FIXED_PHY if M5272
+ select FIXED_PHY
select PAGE_POOL
imply PAGE_POOL_STATS
imply NET_SELFTESTS
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index def2dd231d1f..52c1cb9cb7e0 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -1533,7 +1533,7 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
if_id = (status & 0xFFFF0000) >> 16;
if (if_id >= ethsw->sw_attr.num_ifs) {
dev_err(dev, "Invalid if_id %d in IRQ status\n", if_id);
- goto out;
+ goto out_clear;
}
port_priv = ethsw->ports[if_id];
@@ -1553,6 +1553,7 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
dpaa2_switch_port_connect_mac(port_priv);
}
+out_clear:
err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, status);
if (err)
@@ -3034,6 +3035,13 @@ static int dpaa2_switch_init(struct fsl_mc_device *sw_dev)
goto err_close;
}
+ if (ethsw->sw_attr.num_ifs >= DPSW_MAX_IF) {
+ dev_err(dev, "DPSW num_ifs %u exceeds max %u\n",
+ ethsw->sw_attr.num_ifs, DPSW_MAX_IF);
+ err = -EINVAL;
+ goto err_close;
+ }
+
err = dpsw_get_api_version(ethsw->mc_io, 0,
&ethsw->major,
&ethsw->minor);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 70768392912c..aa8a87124b10 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2578,6 +2578,7 @@ EXPORT_SYMBOL_GPL(enetc_free_si_resources);
static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
{
+ struct enetc_si *si = container_of(hw, struct enetc_si, hw);
int idx = tx_ring->index;
u32 tbmr;
@@ -2591,10 +2592,20 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
enetc_txbdr_wr(hw, idx, ENETC_TBLENR,
ENETC_RTBLENR_LEN(tx_ring->bd_count));
- /* clearing PI/CI registers for Tx not supported, adjust sw indexes */
+ /* For ENETC v1, clearing PI/CI registers for Tx not supported,
+ * adjust sw indexes
+ */
tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR);
tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR);
+ if (tx_ring->next_to_use != tx_ring->next_to_clean &&
+ !is_enetc_rev1(si)) {
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+ enetc_txbdr_wr(hw, idx, ENETC_TBPIR, 0);
+ enetc_txbdr_wr(hw, idx, ENETC_TBCIR, 0);
+ }
+
/* enable Tx ints by setting pkt thr to 1 */
enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1);
@@ -3467,7 +3478,7 @@ static int enetc_int_vector_init(struct enetc_ndev_priv *priv, int i,
priv->rx_ring[i] = bdr;
err = __xdp_rxq_info_reg(&bdr->xdp.rxq, priv->ndev, i, 0,
- ENETC_RXB_DMA_SIZE_XDP);
+ ENETC_RXB_TRUESIZE);
if (err)
goto free_vector;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index 3ed0f7a02767..719c88ceb801 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -134,6 +134,12 @@
/* Port operational register */
#define ENETC4_POR 0x4100
+#define POR_TXDIS BIT(0)
+#define POR_RXDIS BIT(1)
+
+/* Port status register */
+#define ENETC4_PSR 0x4104
+#define PSR_RX_BUSY BIT(1)
/* Port traffic class a transmit maximum SDU register */
#define ENETC4_PTCTMSDUR(a) ((a) * 0x20 + 0x4208)
@@ -173,6 +179,11 @@
/* Port internal MDIO base address, use to access PCS */
#define ENETC4_PM_IMDIO_BASE 0x5030
+/* Port MAC 0/1 Interrupt Event Register */
+#define ENETC4_PM_IEVENT(mac) (0x5040 + (mac) * 0x400)
+#define PM_IEVENT_TX_EMPTY BIT(5)
+#define PM_IEVENT_RX_EMPTY BIT(6)
+
/* Port MAC 0/1 Pause Quanta Register */
#define ENETC4_PM_PAUSE_QUANTA(mac) (0x5054 + (mac) * 0x400)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 689b9f13c5eb..56899f2254aa 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -444,20 +444,11 @@ static void enetc4_set_trx_frame_size(struct enetc_pf *pf)
enetc4_pf_reset_tc_msdu(&si->hw);
}
-static void enetc4_enable_trx(struct enetc_pf *pf)
-{
- struct enetc_hw *hw = &pf->si->hw;
-
- /* Enable port transmit/receive */
- enetc_port_wr(hw, ENETC4_POR, 0);
-}
-
static void enetc4_configure_port(struct enetc_pf *pf)
{
enetc4_configure_port_si(pf);
enetc4_set_trx_frame_size(pf);
enetc_set_default_rss_key(pf);
- enetc4_enable_trx(pf);
}
static int enetc4_init_ntmp_user(struct enetc_si *si)
@@ -801,15 +792,112 @@ static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_paus
enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh);
}
-static void enetc4_enable_mac(struct enetc_pf *pf, bool en)
+static void enetc4_mac_wait_tx_empty(struct enetc_si *si, int mac)
+{
+ u32 val;
+
+ if (read_poll_timeout(enetc_port_rd, val,
+ val & PM_IEVENT_TX_EMPTY,
+ 100, 10000, false, &si->hw,
+ ENETC4_PM_IEVENT(mac)))
+ dev_warn(&si->pdev->dev,
+ "MAC %d TX is not empty\n", mac);
+}
+
+static void enetc4_mac_tx_graceful_stop(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ val = enetc_port_rd(hw, ENETC4_POR);
+ val |= POR_TXDIS;
+ enetc_port_wr(hw, ENETC4_POR, val);
+
+ if (enetc_is_pseudo_mac(si))
+ return;
+
+ enetc4_mac_wait_tx_empty(si, 0);
+ if (si->hw_features & ENETC_SI_F_QBU)
+ enetc4_mac_wait_tx_empty(si, 1);
+
+ val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+ val &= ~PM_CMD_CFG_TX_EN;
+ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+}
+
+static void enetc4_mac_tx_enable(struct enetc_pf *pf)
{
+ struct enetc_hw *hw = &pf->si->hw;
struct enetc_si *si = pf->si;
u32 val;
val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
- val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN);
- val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0;
+ val |= PM_CMD_CFG_TX_EN;
+ enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+ val = enetc_port_rd(hw, ENETC4_POR);
+ val &= ~POR_TXDIS;
+ enetc_port_wr(hw, ENETC4_POR, val);
+}
+
+static void enetc4_mac_wait_rx_empty(struct enetc_si *si, int mac)
+{
+ u32 val;
+
+ if (read_poll_timeout(enetc_port_rd, val,
+ val & PM_IEVENT_RX_EMPTY,
+ 100, 10000, false, &si->hw,
+ ENETC4_PM_IEVENT(mac)))
+ dev_warn(&si->pdev->dev,
+ "MAC %d RX is not empty\n", mac);
+}
+
+static void enetc4_mac_rx_graceful_stop(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ if (enetc_is_pseudo_mac(si))
+ goto check_rx_busy;
+
+ if (si->hw_features & ENETC_SI_F_QBU) {
+ val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(1));
+ val &= ~PM_CMD_CFG_RX_EN;
+ enetc_port_wr(hw, ENETC4_PM_CMD_CFG(1), val);
+ enetc4_mac_wait_rx_empty(si, 1);
+ }
+
+ val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(0));
+ val &= ~PM_CMD_CFG_RX_EN;
+ enetc_port_wr(hw, ENETC4_PM_CMD_CFG(0), val);
+ enetc4_mac_wait_rx_empty(si, 0);
+
+check_rx_busy:
+ if (read_poll_timeout(enetc_port_rd, val,
+ !(val & PSR_RX_BUSY),
+ 100, 10000, false, hw,
+ ENETC4_PSR))
+ dev_warn(&si->pdev->dev, "Port RX busy\n");
+
+ val = enetc_port_rd(hw, ENETC4_POR);
+ val |= POR_RXDIS;
+ enetc_port_wr(hw, ENETC4_POR, val);
+}
+
+static void enetc4_mac_rx_enable(struct enetc_pf *pf)
+{
+ struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
+ u32 val;
+
+ val = enetc_port_rd(hw, ENETC4_POR);
+ val &= ~POR_RXDIS;
+ enetc_port_wr(hw, ENETC4_POR, val);
+
+ val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+ val |= PM_CMD_CFG_RX_EN;
enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
}
@@ -853,7 +941,8 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config,
enetc4_set_hd_flow_control(pf, hd_fc);
enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause);
enetc4_set_rx_pause(pf, rx_pause);
- enetc4_enable_mac(pf, true);
+ enetc4_mac_tx_enable(pf);
+ enetc4_mac_rx_enable(pf);
}
static void enetc4_pl_mac_link_down(struct phylink_config *config,
@@ -862,7 +951,8 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config,
{
struct enetc_pf *pf = phylink_to_enetc_pf(config);
- enetc4_enable_mac(pf, false);
+ enetc4_mac_rx_graceful_stop(pf);
+ enetc4_mac_tx_graceful_stop(pf);
}
static const struct phylink_mac_ops enetc_pl_mac_ops = {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index fed89d4f1e1d..7c17acaf7a38 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -795,9 +795,17 @@ static int enetc_set_rxfh(struct net_device *ndev,
struct enetc_si *si = priv->si;
int err = 0;
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
/* set hash key, if PF */
- if (rxfh->key && enetc_si_is_pf(si))
+ if (rxfh->key) {
+ if (!enetc_si_is_pf(si))
+ return -EOPNOTSUPP;
+
enetc_set_rss_key(si, rxfh->key);
+ }
/* set RSS table */
if (rxfh->indir)
@@ -813,6 +821,8 @@ static void enetc_get_ringparam(struct net_device *ndev,
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ ring->rx_max_pending = priv->rx_bd_count;
+ ring->tx_max_pending = priv->tx_bd_count;
ring->rx_pending = priv->rx_bd_count;
ring->tx_pending = priv->tx_bd_count;
diff --git a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
index 7fd39f895290..92a0f824dae7 100644
--- a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
+++ b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c
@@ -333,11 +333,13 @@ static int netc_get_phy_addr(struct device_node *np)
mdio_node = of_get_child_by_name(np, "mdio");
if (!mdio_node)
- return 0;
+ return -ENODEV;
phy_node = of_get_next_child(mdio_node, NULL);
- if (!phy_node)
+ if (!phy_node) {
+ err = -ENODEV;
goto of_put_mdio_node;
+ }
err = of_property_read_u32(phy_node, "reg", &addr);
if (err)
@@ -423,6 +425,9 @@ static int imx95_enetc_mdio_phyaddr_config(struct platform_device *pdev)
addr = netc_get_phy_addr(gchild);
if (addr < 0) {
+ if (addr == -ENODEV)
+ continue;
+
dev_err(dev, "Failed to get PHY address\n");
return addr;
}
@@ -433,12 +438,6 @@ static int imx95_enetc_mdio_phyaddr_config(struct platform_device *pdev)
return -EINVAL;
}
- /* The default value of LaBCR[MDIO_PHYAD_PRTAD ] is
- * 0, so no need to set the register.
- */
- if (!addr)
- continue;
-
switch (bus_devfn) {
case IMX95_ENETC0_BUS_DEVFN:
netc_reg_write(priv->ierb, IERB_LBCR(0),
@@ -578,16 +577,13 @@ static int imx94_enetc_mdio_phyaddr_config(struct netc_blk_ctrl *priv,
addr = netc_get_phy_addr(np);
if (addr < 0) {
+ if (addr == -ENODEV)
+ return 0;
+
dev_err(dev, "Failed to get PHY address\n");
return addr;
}
- /* The default value of LaBCR[MDIO_PHYAD_PRTAD] is 0,
- * so no need to set the register.
- */
- if (!addr)
- return 0;
-
if (phy_mask & BIT(addr)) {
dev_err(dev,
"Find same PHY address in EMDIO and ENETC node\n");
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 4b7bad9a485d..56801c2009d5 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -545,9 +545,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
if (rq->perout.flags)
return -EOPNOTSUPP;
- if (rq->perout.index != fep->pps_channel)
- return -EOPNOTSUPP;
-
period.tv_sec = rq->perout.period.sec;
period.tv_nsec = rq->perout.period.nsec;
period_ns = timespec64_to_ns(&period);
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
index 9031dd619f68..4db9d4f9ed6f 100644
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -167,6 +167,25 @@ gve_free_pending_packet(struct gve_tx_ring *tx,
}
}
+static void gve_unmap_packet(struct device *dev,
+ struct gve_tx_pending_packet_dqo *pkt)
+{
+ int i;
+
+ if (!pkt->num_bufs)
+ return;
+
+ /* SKB linear portion is guaranteed to be mapped */
+ dma_unmap_single(dev, dma_unmap_addr(pkt, dma[0]),
+ dma_unmap_len(pkt, len[0]), DMA_TO_DEVICE);
+ for (i = 1; i < pkt->num_bufs; i++) {
+ netmem_dma_unmap_page_attrs(dev, dma_unmap_addr(pkt, dma[i]),
+ dma_unmap_len(pkt, len[i]),
+ DMA_TO_DEVICE, 0);
+ }
+ pkt->num_bufs = 0;
+}
+
/* gve_tx_free_desc - Cleans up all pending tx requests and buffers.
*/
static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx)
@@ -176,21 +195,12 @@ static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx)
for (i = 0; i < tx->dqo.num_pending_packets; i++) {
struct gve_tx_pending_packet_dqo *cur_state =
&tx->dqo.pending_packets[i];
- int j;
-
- for (j = 0; j < cur_state->num_bufs; j++) {
- if (j == 0) {
- dma_unmap_single(tx->dev,
- dma_unmap_addr(cur_state, dma[j]),
- dma_unmap_len(cur_state, len[j]),
- DMA_TO_DEVICE);
- } else {
- dma_unmap_page(tx->dev,
- dma_unmap_addr(cur_state, dma[j]),
- dma_unmap_len(cur_state, len[j]),
- DMA_TO_DEVICE);
- }
- }
+
+ if (tx->dqo.qpl)
+ gve_free_tx_qpl_bufs(tx, cur_state);
+ else
+ gve_unmap_packet(tx->dev, cur_state);
+
if (cur_state->skb) {
dev_consume_skb_any(cur_state->skb);
cur_state->skb = NULL;
@@ -1154,22 +1164,6 @@ static void remove_from_list(struct gve_tx_ring *tx,
}
}
-static void gve_unmap_packet(struct device *dev,
- struct gve_tx_pending_packet_dqo *pkt)
-{
- int i;
-
- /* SKB linear portion is guaranteed to be mapped */
- dma_unmap_single(dev, dma_unmap_addr(pkt, dma[0]),
- dma_unmap_len(pkt, len[0]), DMA_TO_DEVICE);
- for (i = 1; i < pkt->num_bufs; i++) {
- netmem_dma_unmap_page_attrs(dev, dma_unmap_addr(pkt, dma[i]),
- dma_unmap_len(pkt, len[i]),
- DMA_TO_DEVICE, 0);
- }
- pkt->num_bufs = 0;
-}
-
/* Completion types and expected behavior:
* No Miss compl + Packet compl = Packet completed normally.
* Miss compl + Re-inject compl = Packet completed normally.
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index ab232b3fbbd0..4dcbeabb3ad2 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -496,14 +496,19 @@ static int e1000_set_eeprom(struct net_device *netdev,
*/
ret_val = e1000_read_eeprom(hw, first_word, 1,
&eeprom_buff[0]);
+ if (ret_val)
+ goto out;
+
ptr++;
}
- if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
+ if ((eeprom->offset + eeprom->len) & 1) {
/* need read/modify/write of last changed EEPROM word
* only the first byte of the word is being modified
*/
ret_val = e1000_read_eeprom(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
+ if (ret_val)
+ goto out;
}
/* Device's eeprom is always little-endian, word addressable */
@@ -522,6 +527,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
if ((ret_val == 0) && (first_word <= EEPROM_CHECKSUM_REG))
e1000_update_eeprom_checksum(hw);
+out:
kfree(eeprom_buff);
return ret_val;
}
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 3d7648a119e5..9b09eb144b81 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -2952,8 +2952,6 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
dma_error:
dev_err(&pdev->dev, "TX DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index ba331899d186..d4a1041e456d 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -33,6 +33,7 @@
/* Extended Device Control */
#define E1000_CTRL_EXT_LPCD 0x00000004 /* LCD Power Cycle Done */
+#define E1000_CTRL_EXT_DPG_EN 0x00000008 /* Dynamic Power Gating Enable */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000800 /* Force SMBus mode */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index aa08f397988e..63ebe00376f5 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -117,7 +117,8 @@ enum e1000_boards {
board_pch_cnp,
board_pch_tgp,
board_pch_adp,
- board_pch_mtp
+ board_pch_mtp,
+ board_pch_ptp
};
struct e1000_ps_page {
@@ -527,6 +528,7 @@ extern const struct e1000_info e1000_pch_cnp_info;
extern const struct e1000_info e1000_pch_tgp_info;
extern const struct e1000_info e1000_pch_adp_info;
extern const struct e1000_info e1000_pch_mtp_info;
+extern const struct e1000_info e1000_pch_ptp_info;
extern const struct e1000_info e1000_es2_info;
void e1000e_ptp_init(struct e1000_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index fc8ed38aa095..c7ac599e5a7a 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -118,8 +118,6 @@ struct e1000_hw;
#define E1000_DEV_ID_PCH_ARL_I219_V24 0x57A1
#define E1000_DEV_ID_PCH_PTP_I219_LM25 0x57B3
#define E1000_DEV_ID_PCH_PTP_I219_V25 0x57B4
-#define E1000_DEV_ID_PCH_PTP_I219_LM26 0x57B5
-#define E1000_DEV_ID_PCH_PTP_I219_V26 0x57B6
#define E1000_DEV_ID_PCH_PTP_I219_LM27 0x57B7
#define E1000_DEV_ID_PCH_PTP_I219_V27 0x57B8
#define E1000_DEV_ID_PCH_NVL_I219_LM29 0x57B9
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 0ff8688ac3b8..dea208db1be5 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -528,7 +528,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->id = e1000_phy_unknown;
- if (hw->mac.type == e1000_pch_mtp) {
+ if (hw->mac.type == e1000_pch_mtp || hw->mac.type == e1000_pch_ptp) {
phy->retry_count = 2;
e1000e_enable_phy_retry(hw);
}
@@ -4932,6 +4932,15 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
reg |= E1000_KABGTXD_BGSQLBIAS;
ew32(KABGTXD, reg);
+ /* The hardware reset value of the DPG_EN bit is 1.
+ * Clear DPG_EN to prevent unexpected autonomous power gating.
+ */
+ if (hw->mac.type >= e1000_pch_ptp) {
+ reg = er32(CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_DPG_EN;
+ ew32(CTRL_EXT, reg);
+ }
+
return 0;
}
@@ -6208,3 +6217,23 @@ const struct e1000_info e1000_pch_mtp_info = {
.phy_ops = &ich8_phy_ops,
.nvm_ops = &spt_nvm_ops,
};
+
+const struct e1000_info e1000_pch_ptp_info = {
+ .mac = e1000_pch_ptp,
+ .flags = FLAG_IS_ICH
+ | FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_FLASH
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_APME_IN_WUC,
+ .flags2 = FLAG2_HAS_PHY_STATS
+ | FLAG2_HAS_EEE,
+ .pba = 26,
+ .max_hw_frame_size = 9022,
+ .get_variants = e1000_get_variants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &spt_nvm_ops,
+};
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index fd4b117ed20f..9befdacd6730 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -55,6 +55,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
[board_pch_tgp] = &e1000_pch_tgp_info,
[board_pch_adp] = &e1000_pch_adp_info,
[board_pch_mtp] = &e1000_pch_mtp_info,
+ [board_pch_ptp] = &e1000_pch_ptp_info,
};
struct e1000_reg_info {
@@ -5651,8 +5652,6 @@ static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
dma_error:
dev_err(&pdev->dev, "Tx DMA map failed\n");
buffer_info->dma = 0;
- if (count)
- count--;
while (count--) {
if (i == 0)
@@ -7922,14 +7921,12 @@ static const struct pci_device_id e1000_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_LM24), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_V24), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM25), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V25), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM26), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V26), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_mtp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM25), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V25), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_ptp },
{ 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
};
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 7b9e147d7365..926d001b2150 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3569,6 +3569,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
u16 pf_q = vsi->base_queue + ring->queue_index;
struct i40e_hw *hw = &vsi->back->hw;
struct i40e_hmc_obj_rxq rx_ctx;
+ u32 xdp_frame_sz;
int err = 0;
bool ok;
@@ -3578,49 +3579,47 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
memset(&rx_ctx, 0, sizeof(rx_ctx));
ring->rx_buf_len = vsi->rx_buf_len;
+ xdp_frame_sz = i40e_rx_pg_size(ring) / 2;
/* XDP RX-queue info only needed for RX rings exposed to XDP */
if (ring->vsi->type != I40E_VSI_MAIN)
goto skip;
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->queue_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- return err;
- }
-
ring->xsk_pool = i40e_xsk_pool(ring);
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
+ xdp_frame_sz = xsk_pool_get_rx_frag_step(ring->xsk_pool);
ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->queue_index,
ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
+ xdp_frame_sz);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL);
if (err)
- return err;
+ goto unreg_xdp;
dev_info(&vsi->back->pdev->dev,
"Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
ring->queue_index);
} else {
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->queue_index,
+ ring->q_vector->napi.napi_id,
+ xdp_frame_sz);
+ if (err)
+ return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED,
NULL);
if (err)
- return err;
+ goto unreg_xdp;
}
skip:
- xdp_init_buff(&ring->xdp, i40e_rx_pg_size(ring) / 2, &ring->xdp_rxq);
+ xdp_init_buff(&ring->xdp, xdp_frame_sz, &ring->xdp_rxq);
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
@@ -3654,7 +3653,8 @@ skip:
dev_info(&vsi->back->pdev->dev,
"Failed to clear LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unreg_xdp;
}
/* set the context in the HMC */
@@ -3663,7 +3663,8 @@ skip:
dev_info(&vsi->back->pdev->dev,
"Failed to set LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unreg_xdp;
}
/* configure Rx buffer alignment */
@@ -3671,7 +3672,8 @@ skip:
if (I40E_2K_TOO_SMALL_WITH_PADDING) {
dev_info(&vsi->back->pdev->dev,
"2k Rx buffer is too small to fit standard MTU and skb_shared_info\n");
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto unreg_xdp;
}
clear_ring_build_skb_enabled(ring);
} else {
@@ -3701,6 +3703,11 @@ skip:
}
return 0;
+unreg_xdp:
+ if (ring->vsi->type == I40E_VSI_MAIN)
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
+
+ return err;
}
/**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_trace.h b/drivers/net/ethernet/intel/i40e/i40e_trace.h
index 759f3d1c4c8f..dde0ccd789ed 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_trace.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_trace.h
@@ -88,7 +88,7 @@ TRACE_EVENT(i40e_napi_poll,
__entry->rx_clean_complete = rx_clean_complete;
__entry->tx_clean_complete = tx_clean_complete;
__entry->irq_num = q->irq_num;
- __entry->curr_cpu = get_cpu();
+ __entry->curr_cpu = smp_processor_id();
__assign_str(qname);
__assign_str(dev_name);
__assign_bitmask(irq_affinity, cpumask_bits(&q->affinity_mask),
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 34db7d8866b0..894f2d06d39d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1470,6 +1470,9 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
if (!rx_ring->rx_bi)
return;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
if (rx_ring->xsk_pool) {
i40e_xsk_clean_rx_ring(rx_ring);
goto skip_free;
@@ -1527,8 +1530,6 @@ skip_free:
void i40e_free_rx_resources(struct i40e_ring *rx_ring)
{
i40e_clean_rx_ring(rx_ring);
- if (rx_ring->vsi->type == I40E_VSI_MAIN)
- xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
rx_ring->xdp_prog = NULL;
kfree(rx_ring->rx_bi);
rx_ring->rx_bi = NULL;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index fdf40f8fb239..a26c3d47ec15 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -3833,10 +3833,10 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter.n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter.ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter.ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter.ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter.ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter.n_proto = ETH_P_IPV6;
@@ -3891,7 +3891,7 @@ static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
/* for ipv6, mask is set for all sixteen bytes (4 words) */
if (cfilter.n_proto == ETH_P_IPV6 && mask.dst_ip[3])
if (memcmp(&cfilter.ip.v6.dst_ip6, &cf->ip.v6.dst_ip6,
- sizeof(cfilter.ip.v6.src_ip6)))
+ sizeof(cfilter.ip.v6.dst_ip6)))
continue;
if (mask.vlan_id)
if (cfilter.vlan_id != cf->vlan_id)
@@ -3979,10 +3979,10 @@ static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
cfilter->n_proto = ETH_P_IP;
if (mask.dst_ip[0] & tcf.dst_ip[0])
memcpy(&cfilter->ip.v4.dst_ip, tcf.dst_ip,
- ARRAY_SIZE(tcf.dst_ip));
- else if (mask.src_ip[0] & tcf.dst_ip[0])
+ sizeof(cfilter->ip.v4.dst_ip));
+ else if (mask.src_ip[0] & tcf.src_ip[0])
memcpy(&cfilter->ip.v4.src_ip, tcf.src_ip,
- ARRAY_SIZE(tcf.dst_ip));
+ sizeof(cfilter->ip.v4.src_ip));
break;
case VIRTCHNL_TCP_V6_FLOW:
cfilter->n_proto = ETH_P_IPV6;
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index a87e0c6d4017..e9fb0a0919e3 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -260,7 +260,6 @@ struct iavf_adapter {
struct work_struct adminq_task;
struct work_struct finish_config;
wait_queue_head_t down_waitqueue;
- wait_queue_head_t reset_waitqueue;
wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list;
@@ -626,5 +625,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
const u8 *macaddr);
-int iavf_wait_for_reset(struct iavf_adapter *adapter);
+void iavf_reset_step(struct iavf_adapter *adapter);
#endif /* _IAVF_H_ */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index f3a1b2fb9bf8..1cd1f3f2930a 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -313,14 +313,13 @@ static int iavf_get_sset_count(struct net_device *netdev, int sset)
{
/* Report the maximum number queues, even if not every queue is
* currently configured. Since allocation of queues is in pairs,
- * use netdev->real_num_tx_queues * 2. The real_num_tx_queues is set
- * at device creation and never changes.
+ * use netdev->num_tx_queues * 2. The num_tx_queues is set at
+ * device creation and never changes.
*/
if (sset == ETH_SS_STATS)
return IAVF_STATS_LEN +
- (IAVF_QUEUE_STATS_LEN * 2 *
- netdev->real_num_tx_queues);
+ (IAVF_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues);
else
return -EINVAL;
}
@@ -345,19 +344,19 @@ static void iavf_get_ethtool_stats(struct net_device *netdev,
iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
rcu_read_lock();
- /* As num_active_queues describe both tx and rx queues, we can use
- * it to iterate over rings' stats.
+ /* Use num_tx_queues to report stats for the maximum number of queues.
+ * Queues beyond num_active_queues will report zero.
*/
- for (i = 0; i < adapter->num_active_queues; i++) {
- struct iavf_ring *ring;
+ for (i = 0; i < netdev->num_tx_queues; i++) {
+ struct iavf_ring *tx_ring = NULL, *rx_ring = NULL;
- /* Tx rings stats */
- ring = &adapter->tx_rings[i];
- iavf_add_queue_stats(&data, ring);
+ if (i < adapter->num_active_queues) {
+ tx_ring = &adapter->tx_rings[i];
+ rx_ring = &adapter->rx_rings[i];
+ }
- /* Rx rings stats */
- ring = &adapter->rx_rings[i];
- iavf_add_queue_stats(&data, ring);
+ iavf_add_queue_stats(&data, tx_ring);
+ iavf_add_queue_stats(&data, rx_ring);
}
rcu_read_unlock();
}
@@ -376,9 +375,9 @@ static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
iavf_add_stat_strings(&data, iavf_gstrings_stats);
/* Queues are always allocated in pairs, so we just use
- * real_num_tx_queues for both Tx and Rx queues.
+ * num_tx_queues for both Tx and Rx queues.
*/
- for (i = 0; i < netdev->real_num_tx_queues; i++) {
+ for (i = 0; i < netdev->num_tx_queues; i++) {
iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
"tx", i);
iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
@@ -492,7 +491,6 @@ static int iavf_set_ringparam(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u32 new_rx_count, new_tx_count;
- int ret = 0;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
@@ -537,13 +535,11 @@ static int iavf_set_ringparam(struct net_device *netdev,
}
if (netif_running(netdev)) {
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
- ret = iavf_wait_for_reset(adapter);
- if (ret)
- netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
}
- return ret;
+ return 0;
}
/**
@@ -1723,7 +1719,6 @@ static int iavf_set_channels(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u32 num_req = ch->combined_count;
- int ret = 0;
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
adapter->num_tc) {
@@ -1745,13 +1740,10 @@ static int iavf_set_channels(struct net_device *netdev,
adapter->num_req_queues = num_req;
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
-
- ret = iavf_wait_for_reset(adapter);
- if (ret)
- netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
- return ret;
+ return 0;
}
/**
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index bceaf4b1b85d..dad001abc908 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -186,31 +186,6 @@ static bool iavf_is_reset_in_progress(struct iavf_adapter *adapter)
}
/**
- * iavf_wait_for_reset - Wait for reset to finish.
- * @adapter: board private structure
- *
- * Returns 0 if reset finished successfully, negative on timeout or interrupt.
- */
-int iavf_wait_for_reset(struct iavf_adapter *adapter)
-{
- int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue,
- !iavf_is_reset_in_progress(adapter),
- msecs_to_jiffies(5000));
-
- /* If ret < 0 then it means wait was interrupted.
- * If ret == 0 then it means we got a timeout while waiting
- * for reset to finish.
- * If ret > 0 it means reset has finished.
- */
- if (ret > 0)
- return 0;
- else if (ret < 0)
- return -EINTR;
- else
- return -EBUSY;
-}
-
-/**
* iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure
* @mem: ptr to mem struct to fill out
@@ -782,10 +757,13 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
adapter->num_vlan_filters++;
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER);
} else if (f->state == IAVF_VLAN_REMOVE) {
- /* IAVF_VLAN_REMOVE means that VLAN wasn't yet removed.
- * We can safely only change the state here.
+ /* Re-add the filter since we cannot tell whether the
+ * pending delete has already been processed by the PF.
+ * A duplicate add is harmless.
*/
- f->state = IAVF_VLAN_ACTIVE;
+ f->state = IAVF_VLAN_ADD;
+ iavf_schedule_aq_request(adapter,
+ IAVF_FLAG_AQ_ADD_VLAN_FILTER);
}
clearout:
@@ -2793,7 +2771,22 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
netdev->watchdog_timeo = 5 * HZ;
netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = LIBIE_MAX_MTU;
+
+ /* PF/VF API: vf_res->max_mtu is max frame size (not MTU).
+ * Convert to MTU.
+ */
+ if (!adapter->vf_res->max_mtu) {
+ netdev->max_mtu = LIBIE_MAX_MTU;
+ } else if (adapter->vf_res->max_mtu < LIBETH_RX_LL_LEN + ETH_MIN_MTU ||
+ adapter->vf_res->max_mtu >
+ LIBETH_RX_LL_LEN + LIBIE_MAX_MTU) {
+ netdev_warn_once(adapter->netdev,
+ "invalid max frame size %d from PF, using default MTU %d",
+ adapter->vf_res->max_mtu, LIBIE_MAX_MTU);
+ netdev->max_mtu = LIBIE_MAX_MTU;
+ } else {
+ netdev->max_mtu = adapter->vf_res->max_mtu - LIBETH_RX_LL_LEN;
+ }
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
@@ -3021,6 +3014,8 @@ static void iavf_disable_vf(struct iavf_adapter *adapter)
adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
+ iavf_ptp_release(adapter);
+
/* We don't use netif_running() because it may be true prior to
* ndo_open() returning, so we can't assume it means all our open
* tasks have finished, since we're not holding the rtnl_lock here.
@@ -3096,18 +3091,16 @@ static void iavf_reconfig_qs_bw(struct iavf_adapter *adapter)
}
/**
- * iavf_reset_task - Call-back task to handle hardware reset
- * @work: pointer to work_struct
+ * iavf_reset_step - Perform the VF reset sequence
+ * @adapter: board private structure
*
- * During reset we need to shut down and reinitialize the admin queue
- * before we can use it to communicate with the PF again. We also clear
- * and reinit the rings because that context is lost as well.
- **/
-static void iavf_reset_task(struct work_struct *work)
+ * Requests a reset from PF, polls for completion, and reconfigures
+ * the driver. Caller must hold the netdev instance lock.
+ *
+ * This can sleep for several seconds while polling HW registers.
+ */
+void iavf_reset_step(struct iavf_adapter *adapter)
{
- struct iavf_adapter *adapter = container_of(work,
- struct iavf_adapter,
- reset_task);
struct virtchnl_vf_resource *vfres = adapter->vf_res;
struct net_device *netdev = adapter->netdev;
struct iavf_hw *hw = &adapter->hw;
@@ -3118,7 +3111,7 @@ static void iavf_reset_task(struct work_struct *work)
int i = 0, err;
bool running;
- netdev_lock(netdev);
+ netdev_assert_locked(netdev);
iavf_misc_irq_disable(adapter);
if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
@@ -3163,7 +3156,6 @@ static void iavf_reset_task(struct work_struct *work)
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
reg_val);
iavf_disable_vf(adapter);
- netdev_unlock(netdev);
return; /* Do not attempt to reinit. It's dead, Jim. */
}
@@ -3175,7 +3167,6 @@ continue_reset:
iavf_startup(adapter);
queue_delayed_work(adapter->wq, &adapter->watchdog_task,
msecs_to_jiffies(30));
- netdev_unlock(netdev);
return;
}
@@ -3196,6 +3187,8 @@ continue_reset:
iavf_change_state(adapter, __IAVF_RESETTING);
adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
+ iavf_ptp_release(adapter);
+
/* free the Tx/Rx rings and descriptors, might be better to just
* re-use them sometime in the future
*/
@@ -3316,9 +3309,6 @@ continue_reset:
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
- wake_up(&adapter->reset_waitqueue);
- netdev_unlock(netdev);
-
return;
reset_err:
if (running) {
@@ -3327,10 +3317,21 @@ reset_err:
}
iavf_disable_vf(adapter);
- netdev_unlock(netdev);
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
}
+static void iavf_reset_task(struct work_struct *work)
+{
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
+ reset_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netdev_lock(netdev);
+ iavf_reset_step(adapter);
+ netdev_unlock(netdev);
+}
+
/**
* iavf_adminq_task - worker thread to clean the admin queue
* @work: pointer to work_struct containing our data
@@ -4596,22 +4597,17 @@ static int iavf_close(struct net_device *netdev)
static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
- int ret = 0;
netdev_dbg(netdev, "changing MTU from %d to %d\n",
netdev->mtu, new_mtu);
WRITE_ONCE(netdev->mtu, new_mtu);
if (netif_running(netdev)) {
- iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
- ret = iavf_wait_for_reset(adapter);
- if (ret < 0)
- netdev_warn(netdev, "MTU change interrupted waiting for reset");
- else if (ret)
- netdev_warn(netdev, "MTU change timed out waiting for reset");
+ adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+ iavf_reset_step(adapter);
}
- return ret;
+ return 0;
}
/**
@@ -5416,9 +5412,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue);
- /* Setup the wait queue for indicating transition to running state */
- init_waitqueue_head(&adapter->reset_waitqueue);
-
/* Setup the wait queue for indicating virtchannel events */
init_waitqueue_head(&adapter->vc_waitqueue);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 88156082a41d..a52c100dcbc5 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -2736,7 +2736,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ENABLE_QUEUES:
/* enable transmits */
iavf_irq_enable(adapter, true);
- wake_up(&adapter->reset_waitqueue);
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c
index 6c72bd15db6d..6144cee8034d 100644
--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c
@@ -1360,7 +1360,7 @@ ice_devlink_enable_roce_get(struct devlink *devlink, u32 id,
cdev = pf->cdev_info;
if (!cdev)
- return -ENODEV;
+ return -EOPNOTSUPP;
ctx->val.vbool = !!(cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_ROCEV2);
@@ -1427,7 +1427,7 @@ ice_devlink_enable_iw_get(struct devlink *devlink, u32 id,
cdev = pf->cdev_info;
if (!cdev)
- return -ENODEV;
+ return -EOPNOTSUPP;
ctx->val.vbool = !!(cdev->rdma_protocol & IIDC_RDMA_PROTOCOL_IWARP);
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index def7efa15447..eb3a48330cc1 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -840,6 +840,28 @@ static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid)
}
/**
+ * ice_get_max_txq - return the maximum number of Tx queues for in a PF
+ * @pf: PF structure
+ *
+ * Return: maximum number of Tx queues
+ */
+static inline int ice_get_max_txq(struct ice_pf *pf)
+{
+ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
+}
+
+/**
+ * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
+ * @pf: PF structure
+ *
+ * Return: maximum number of Rx queues
+ */
+static inline int ice_get_max_rxq(struct ice_pf *pf)
+{
+ return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
+}
+
+/**
* ice_get_main_vsi - Get the PF VSI
* @pf: PF instance
*
@@ -987,6 +1009,7 @@ int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
int ice_plug_aux_dev(struct ice_pf *pf);
void ice_unplug_aux_dev(struct ice_pf *pf);
+void ice_rdma_finalize_setup(struct ice_pf *pf);
int ice_init_rdma(struct ice_pf *pf);
void ice_deinit_rdma(struct ice_pf *pf);
bool ice_is_wol_supported(struct ice_hw *hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index eb77dfa934aa..1667f686ff75 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -124,6 +124,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx)
if (vsi->type == ICE_VSI_VF) {
ice_calc_vf_reg_idx(vsi->vf, q_vector);
goto out;
+ } else if (vsi->type == ICE_VSI_LB) {
+ goto skip_alloc;
} else if (vsi->type == ICE_VSI_CTRL && vsi->vf) {
struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi);
@@ -659,33 +661,22 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
{
struct device *dev = ice_pf_to_dev(ring->vsi->back);
u32 num_bufs = ICE_DESC_UNUSED(ring);
- u32 rx_buf_len;
int err;
- if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- return err;
- }
-
+ if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF ||
+ ring->vsi->type == ICE_VSI_LB) {
ice_rx_xsk_pool(ring);
err = ice_realloc_rx_xdp_bufs(ring, ring->xsk_pool);
if (err)
return err;
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
-
- rx_buf_len =
- xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ u32 frag_size =
+ xsk_pool_get_rx_frag_step(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- rx_buf_len);
+ frag_size);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -702,14 +693,13 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
if (err)
return err;
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- goto err_destroy_fq;
- }
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ring->truesize);
+ if (err)
+ goto err_destroy_fq;
+
xdp_rxq_info_attach_page_pool(&ring->xdp_rxq,
ring->pp);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 6cd63190f55d..ce11fea122d0 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1816,6 +1816,7 @@ static bool ice_should_retry_sq_send_cmd(u16 opcode)
case ice_aqc_opc_lldp_stop:
case ice_aqc_opc_lldp_start:
case ice_aqc_opc_lldp_filter_ctrl:
+ case ice_aqc_opc_sff_eeprom:
return true;
}
@@ -1841,6 +1842,7 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
{
struct libie_aq_desc desc_cpy;
bool is_cmd_for_retry;
+ u8 *buf_cpy = NULL;
u8 idx = 0;
u16 opcode;
int status;
@@ -1850,8 +1852,11 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
memset(&desc_cpy, 0, sizeof(desc_cpy));
if (is_cmd_for_retry) {
- /* All retryable cmds are direct, without buf. */
- WARN_ON(buf);
+ if (buf) {
+ buf_cpy = kmemdup(buf, buf_size, GFP_KERNEL);
+ if (!buf_cpy)
+ return -ENOMEM;
+ }
memcpy(&desc_cpy, desc, sizeof(desc_cpy));
}
@@ -1863,12 +1868,14 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
break;
+ if (buf_cpy)
+ memcpy(buf, buf_cpy, buf_size);
memcpy(desc, &desc_cpy, sizeof(desc_cpy));
-
msleep(ICE_SQ_SEND_DELAY_TIME_MS);
} while (++idx < ICE_SQ_SEND_MAX_EXECUTE);
+ kfree(buf_cpy);
return status;
}
@@ -6391,7 +6398,7 @@ int ice_lldp_fltr_add_remove(struct ice_hw *hw, struct ice_vsi *vsi, bool add)
struct ice_aqc_lldp_filter_ctrl *cmd;
struct libie_aq_desc desc;
- if (vsi->type != ICE_VSI_PF || !ice_fw_supports_lldp_fltr_ctrl(hw))
+ if (!ice_fw_supports_lldp_fltr_ctrl(hw))
return -EOPNOTSUPP;
cmd = libie_aq_raw(&desc);
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 0ea64b330614..e6a20af6f63d 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1289,6 +1289,10 @@ static u64 ice_loopback_test(struct net_device *netdev)
test_vsi->netdev = netdev;
tx_ring = test_vsi->tx_rings[0];
rx_ring = test_vsi->rx_rings[0];
+ /* Dummy q_vector and napi. Fill the minimum required for
+ * ice_rxq_pp_create().
+ */
+ rx_ring->q_vector->napi.dev = netdev;
if (ice_lbtest_prepare_rings(test_vsi)) {
ret = 2;
@@ -1926,6 +1930,17 @@ __ice_get_ethtool_stats(struct net_device *netdev,
int i = 0;
char *p;
+ if (ice_is_port_repr_netdev(netdev)) {
+ ice_update_eth_stats(vsi);
+
+ for (j = 0; j < ICE_VSI_STATS_LEN; j++) {
+ p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset;
+ data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ return;
+ }
+
ice_update_pf_stats(pf);
ice_update_vsi_stats(vsi);
@@ -1935,9 +1950,6 @@ __ice_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
- if (ice_is_port_repr_netdev(netdev))
- return;
-
/* populate per queue stats */
rcu_read_lock();
@@ -3328,7 +3340,7 @@ process_rx:
rx_rings = kzalloc_objs(*rx_rings, vsi->num_rxq);
if (!rx_rings) {
err = -ENOMEM;
- goto done;
+ goto free_xdp;
}
ice_for_each_rxq(vsi, i) {
@@ -3338,6 +3350,7 @@ process_rx:
rx_rings[i].cached_phctime = pf->ptp.cached_phc_time;
rx_rings[i].desc = NULL;
rx_rings[i].xdp_buf = NULL;
+ rx_rings[i].xdp_rxq = (struct xdp_rxq_info){ };
/* this is to allow wr32 to have something to write to
* during early allocation of Rx buffers
@@ -3355,7 +3368,7 @@ rx_unwind:
}
kfree(rx_rings);
err = -ENOMEM;
- goto free_tx;
+ goto free_xdp;
}
}
@@ -3407,6 +3420,13 @@ process_link:
}
goto done;
+free_xdp:
+ if (xdp_rings) {
+ ice_for_each_xdp_txq(vsi, i)
+ ice_free_tx_ring(&xdp_rings[i]);
+ kfree(xdp_rings);
+ }
+
free_tx:
/* error cleanup if the Rx allocations failed after getting Tx */
if (tx_rings) {
@@ -3762,24 +3782,6 @@ ice_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
}
/**
- * ice_get_max_txq - return the maximum number of Tx queues for in a PF
- * @pf: PF structure
- */
-static int ice_get_max_txq(struct ice_pf *pf)
-{
- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq);
-}
-
-/**
- * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
- * @pf: PF structure
- */
-static int ice_get_max_rxq(struct ice_pf *pf)
-{
- return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq);
-}
-
-/**
* ice_get_combined_cnt - return the current number of combined channels
* @vsi: PF VSI pointer
*
@@ -4505,7 +4507,7 @@ ice_get_module_eeprom(struct net_device *netdev,
u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
struct ice_hw *hw = &pf->hw;
bool is_sfp = false;
- unsigned int i, j;
+ unsigned int i;
u16 offset = 0;
u8 page = 0;
int status;
@@ -4547,26 +4549,19 @@ ice_get_module_eeprom(struct net_device *netdev,
if (page == 0 || !(data[0x2] & 0x4)) {
u32 copy_len;
- /* If i2c bus is busy due to slow page change or
- * link management access, call can fail. This is normal.
- * So we retry this a few times.
- */
- for (j = 0; j < 4; j++) {
- status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
- !is_sfp, value,
- SFF_READ_BLOCK_SIZE,
- 0, NULL);
- netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
- addr, offset, page, is_sfp,
- value[0], value[1], value[2], value[3],
- value[4], value[5], value[6], value[7],
- status);
- if (status) {
- usleep_range(1500, 2500);
- memset(value, 0, SFF_READ_BLOCK_SIZE);
- continue;
- }
- break;
+ status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
+ !is_sfp, value,
+ SFF_READ_BLOCK_SIZE,
+ 0, NULL);
+ netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%pe)\n",
+ addr, offset, page, is_sfp,
+ value[0], value[1], value[2], value[3],
+ value[4], value[5], value[6], value[7],
+ ERR_PTR(status));
+ if (status) {
+ netdev_err(netdev, "%s: error reading module EEPROM: status %pe\n",
+ __func__, ERR_PTR(status));
+ return status;
}
/* Make sure we have enough room for the new block */
diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c
index 3572b0e1d49f..102d63c3018b 100644
--- a/drivers/net/ethernet/intel/ice/ice_idc.c
+++ b/drivers/net/ethernet/intel/ice/ice_idc.c
@@ -361,6 +361,39 @@ void ice_unplug_aux_dev(struct ice_pf *pf)
}
/**
+ * ice_rdma_finalize_setup - Complete RDMA setup after VSI is ready
+ * @pf: ptr to ice_pf
+ *
+ * Sets VSI-dependent information and plugs aux device.
+ * Must be called after ice_init_rdma(), ice_vsi_rebuild(), and
+ * ice_dcb_rebuild() complete.
+ */
+void ice_rdma_finalize_setup(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct iidc_rdma_priv_dev_info *privd;
+ int ret;
+
+ if (!ice_is_rdma_ena(pf) || !pf->cdev_info)
+ return;
+
+ privd = pf->cdev_info->iidc_priv;
+ if (!privd || !pf->vsi || !pf->vsi[0] || !pf->vsi[0]->netdev)
+ return;
+
+ /* Assign VSI info now that VSI is valid */
+ privd->netdev = pf->vsi[0]->netdev;
+ privd->vport_id = pf->vsi[0]->vsi_num;
+
+ /* Update QoS info after DCB has been rebuilt */
+ ice_setup_dcb_qos_info(pf, &privd->qos_info);
+
+ ret = ice_plug_aux_dev(pf);
+ if (ret)
+ dev_warn(dev, "Failed to plug RDMA aux device: %d\n", ret);
+}
+
+/**
* ice_init_rdma - initializes PF for RDMA use
* @pf: ptr to ice_pf
*/
@@ -398,22 +431,14 @@ int ice_init_rdma(struct ice_pf *pf)
}
cdev->iidc_priv = privd;
- privd->netdev = pf->vsi[0]->netdev;
privd->hw_addr = (u8 __iomem *)pf->hw.hw_addr;
cdev->pdev = pf->pdev;
- privd->vport_id = pf->vsi[0]->vsi_num;
pf->cdev_info->rdma_protocol |= IIDC_RDMA_PROTOCOL_ROCEV2;
- ice_setup_dcb_qos_info(pf, &privd->qos_info);
- ret = ice_plug_aux_dev(pf);
- if (ret)
- goto err_plug_aux_dev;
+
return 0;
-err_plug_aux_dev:
- pf->cdev_info->adev = NULL;
- xa_erase(&ice_aux_id, pf->aux_idx);
err_alloc_xa:
kfree(privd);
err_privd_alloc:
@@ -432,7 +457,6 @@ void ice_deinit_rdma(struct ice_pf *pf)
if (!ice_is_rdma_ena(pf))
return;
- ice_unplug_aux_dev(pf);
xa_erase(&ice_aux_id, pf->aux_idx);
kfree(pf->cdev_info->iidc_priv);
kfree(pf->cdev_info);
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index f91f8b672b02..689c6025ea82 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -107,10 +107,6 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
if (!vsi->rxq_map)
goto err_rxq_map;
- /* There is no need to allocate q_vectors for a loopback VSI. */
- if (vsi->type == ICE_VSI_LB)
- return 0;
-
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors,
sizeof(*vsi->q_vectors), GFP_KERNEL);
@@ -241,6 +237,8 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
case ICE_VSI_LB:
vsi->alloc_txq = 1;
vsi->alloc_rxq = 1;
+ /* A dummy q_vector, no actual IRQ. */
+ vsi->num_q_vectors = 1;
break;
default:
dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi_type);
@@ -2426,14 +2424,21 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
}
break;
case ICE_VSI_LB:
- ret = ice_vsi_alloc_rings(vsi);
+ ret = ice_vsi_alloc_q_vectors(vsi);
if (ret)
goto unroll_vsi_init;
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_alloc_q_vector;
+
ret = ice_vsi_alloc_ring_stats(vsi);
if (ret)
goto unroll_vector_base;
+ /* Simply map the dummy q_vector to the only rx_ring */
+ vsi->rx_rings[0]->q_vector = vsi->q_vectors[0];
+
break;
default:
/* clean up the resources and exit */
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index ebf48feffb30..3c36e3641b9e 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -4699,8 +4699,8 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
- netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
- vsi->alloc_rxq);
+ netdev = alloc_etherdev_mqs(sizeof(*np), ice_get_max_txq(vsi->back),
+ ice_get_max_rxq(vsi->back));
if (!netdev)
return -ENOMEM;
@@ -5138,6 +5138,9 @@ int ice_load(struct ice_pf *pf)
if (err)
goto err_init_rdma;
+ /* Finalize RDMA: VSI already created, assign info and plug device */
+ ice_rdma_finalize_setup(pf);
+
ice_service_task_restart(pf);
clear_bit(ICE_DOWN, pf->state);
@@ -5169,6 +5172,7 @@ void ice_unload(struct ice_pf *pf)
devl_assert_locked(priv_to_devlink(pf));
+ ice_unplug_aux_dev(pf);
ice_deinit_rdma(pf);
ice_deinit_features(pf);
ice_tc_indir_block_unregister(vsi);
@@ -5595,6 +5599,7 @@ static int ice_suspend(struct device *dev)
*/
disabled = ice_service_task_stop(pf);
+ ice_unplug_aux_dev(pf);
ice_deinit_rdma(pf);
/* Already suspended?, then there is nothing to do */
@@ -7859,7 +7864,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
ice_health_clear(pf);
- ice_plug_aux_dev(pf);
+ ice_rdma_finalize_setup(pf);
if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG))
ice_lag_rebuild(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 094e96219f45..6cb0cf7a9891 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -1296,12 +1296,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
if (pf->hw.reset_ongoing)
return;
- if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) {
+ if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 &&
+ test_bit(ICE_FLAG_DPLL, pf->flags)) {
int pin, err;
- if (!test_bit(ICE_FLAG_DPLL, pf->flags))
- return;
-
mutex_lock(&pf->dplls.lock);
for (pin = 0; pin < ICE_SYNCE_CLK_NUM; pin++) {
enum ice_synce_clk clk_pin;
@@ -1314,15 +1312,19 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
port_num,
&active,
clk_pin);
- if (WARN_ON_ONCE(err)) {
- mutex_unlock(&pf->dplls.lock);
- return;
+ if (err) {
+ dev_err_once(ice_pf_to_dev(pf),
+ "Failed to read SyncE bypass mux for pin %d, err %d\n",
+ pin, err);
+ break;
}
err = ice_tspll_cfg_synce_ethdiv_e825c(hw, clk_pin);
- if (active && WARN_ON_ONCE(err)) {
- mutex_unlock(&pf->dplls.lock);
- return;
+ if (active && err) {
+ dev_err_once(ice_pf_to_dev(pf),
+ "Failed to configure SyncE ETH divider for pin %d, err %d\n",
+ pin, err);
+ break;
}
}
mutex_unlock(&pf->dplls.lock);
@@ -3080,7 +3082,13 @@ static int ice_ptp_setup_pf(struct ice_pf *pf)
struct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf);
struct ice_ptp *ptp = &pf->ptp;
- if (WARN_ON(!ctrl_ptp) || pf->hw.mac_type == ICE_MAC_UNKNOWN)
+ if (!ctrl_ptp) {
+ dev_info(ice_pf_to_dev(pf),
+ "PTP unavailable: no controlling PF\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pf->hw.mac_type == ICE_MAC_UNKNOWN)
return -ENODEV;
INIT_LIST_HEAD(&ptp->port.list_node);
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c
index 90f99443a922..096566c697f4 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.c
+++ b/drivers/net/ethernet/intel/ice/ice_repr.c
@@ -2,6 +2,7 @@
/* Copyright (C) 2019-2021, Intel Corporation. */
#include "ice.h"
+#include "ice_lib.h"
#include "ice_eswitch.h"
#include "devlink/devlink.h"
#include "devlink/port.h"
@@ -67,7 +68,7 @@ ice_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
return;
vsi = repr->src_vsi;
- ice_update_vsi_stats(vsi);
+ ice_update_eth_stats(vsi);
eth_stats = &vsi->eth_stats;
stats->tx_packets = eth_stats->tx_unicast + eth_stats->tx_broadcast +
@@ -315,7 +316,7 @@ ice_repr_reg_netdev(struct net_device *netdev, const struct net_device_ops *ops)
static int ice_repr_ready_vf(struct ice_repr *repr)
{
- return !ice_check_vf_ready_for_cfg(repr->vf);
+ return ice_check_vf_ready_for_cfg(repr->vf);
}
static int ice_repr_ready_sf(struct ice_repr *repr)
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index a5bbce68f76c..a2cd4cf37734 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -560,7 +560,9 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
i = 0;
}
- if (rx_ring->vsi->type == ICE_VSI_PF &&
+ if ((rx_ring->vsi->type == ICE_VSI_PF ||
+ rx_ring->vsi->type == ICE_VSI_SF ||
+ rx_ring->vsi->type == ICE_VSI_LB) &&
xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) {
xdp_rxq_info_detach_mem_model(&rx_ring->xdp_rxq);
xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index c673094663a3..0643017541c3 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -899,6 +899,9 @@ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring)
u16 ntc = rx_ring->next_to_clean;
u16 ntu = rx_ring->next_to_use;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
while (ntc != ntu) {
struct xdp_buff *xdp = *ice_xdp_buf(rx_ring, ntc);
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index b206fba092c8..ec1b75f039bb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -1066,7 +1066,7 @@ bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val);
int idpf_idc_init(struct idpf_adapter *adapter);
int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter,
enum iidc_function_type ftype);
-void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info);
+void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter);
void idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info *vdev_info);
void idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info *cdev_info);
void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index 40e08a71d2d3..bb99d9e7c65d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -307,9 +307,6 @@ static int idpf_del_flow_steer(struct net_device *netdev,
vport_config = vport->adapter->vport_config[np->vport_idx];
user_config = &vport_config->user_config;
- if (!idpf_sideband_action_ena(vport, fsp))
- return -EOPNOTSUPP;
-
rule = kzalloc_flex(*rule, rule_info, 1);
if (!rule)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index bd4785fb8d3e..7e4f4ac92653 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -470,10 +470,11 @@ err_privd_alloc:
/**
* idpf_idc_deinit_core_aux_device - de-initialize Auxiliary Device(s)
- * @cdev_info: IDC core device info pointer
+ * @adapter: driver private data structure
*/
-void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
+void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter)
{
+ struct iidc_rdma_core_dev_info *cdev_info = adapter->cdev_info;
struct iidc_rdma_priv_dev_info *privd;
if (!cdev_info)
@@ -485,6 +486,7 @@ void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info)
kfree(privd->mapped_mem_regions);
kfree(privd);
kfree(cdev_info);
+ adapter->cdev_info = NULL;
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index de3df705a7e6..cf966fe6c759 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1318,6 +1318,7 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
free_rss_key:
kfree(rss_data->rss_key);
+ rss_data->rss_key = NULL;
free_qreg_chunks:
idpf_vport_deinit_queue_reg_chunks(adapter->vport_config[idx]);
free_vector_idxs:
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 05a162094d10..f6b3b15364ff 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1314,6 +1314,9 @@ static void idpf_txq_group_rel(struct idpf_q_vec_rsrc *rsrc)
struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
for (unsigned int j = 0; j < txq_grp->num_txq; j++) {
+ if (!txq_grp->txqs[j])
+ continue;
+
if (idpf_queue_has(FLOW_SCH_EN, txq_grp->txqs[j])) {
kfree(txq_grp->txqs[j]->refillq);
txq_grp->txqs[j]->refillq = NULL;
@@ -1339,6 +1342,9 @@ static void idpf_txq_group_rel(struct idpf_q_vec_rsrc *rsrc)
*/
static void idpf_rxq_sw_queue_rel(struct idpf_rxq_group *rx_qgrp)
{
+ if (!rx_qgrp->splitq.bufq_sets)
+ return;
+
for (unsigned int i = 0; i < rx_qgrp->splitq.num_bufq_sets; i++) {
struct idpf_bufq_set *bufq_set = &rx_qgrp->splitq.bufq_sets[i];
@@ -1854,13 +1860,13 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport,
idpf_queue_assign(HSPLIT_EN, q, hs);
idpf_queue_assign(RSC_EN, q, rsc);
- bufq_set->num_refillqs = num_rxq;
bufq_set->refillqs = kcalloc(num_rxq, swq_size,
GFP_KERNEL);
if (!bufq_set->refillqs) {
err = -ENOMEM;
goto err_alloc;
}
+ bufq_set->num_refillqs = num_rxq;
for (unsigned int k = 0; k < bufq_set->num_refillqs; k++) {
struct idpf_sw_queue *refillq =
&bufq_set->refillqs[k];
@@ -2336,7 +2342,7 @@ void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq)
do {
struct idpf_splitq_4b_tx_compl_desc *tx_desc;
- struct idpf_tx_queue *target;
+ struct idpf_tx_queue *target = NULL;
u32 ctype_gen, id;
tx_desc = flow ? &complq->comp[ntc].common :
@@ -2356,14 +2362,14 @@ void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq)
target = complq->txq_grp->txqs[id];
idpf_queue_clear(SW_MARKER, target);
- if (target == txq)
- break;
next:
if (unlikely(++ntc == complq->desc_count)) {
ntc = 0;
gen_flag = !gen_flag;
}
+ if (target == txq)
+ break;
} while (time_before(jiffies, timeout));
idpf_queue_assign(GEN_CHK, complq, gen_flag);
@@ -4059,7 +4065,7 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
continue;
name = kasprintf(GFP_KERNEL, "%s-%s-%s-%d", drv_name, if_name,
- vec_name, vidx);
+ vec_name, vector);
err = request_irq(irq_num, idpf_vport_intr_clean_queues, 0,
name, q_vector);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index d5a877e1fef8..be66f9b2e101 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -287,26 +287,21 @@ dma_mem_error:
return err;
}
-/* API for virtchnl "transaction" support ("xn" for short).
- *
- * We are reusing the completion lock to serialize the accesses to the
- * transaction state for simplicity, but it could be its own separate synchro
- * as well. For now, this API is only used from within a workqueue context;
- * raw_spin_lock() is enough.
- */
+/* API for virtchnl "transaction" support ("xn" for short). */
+
/**
* idpf_vc_xn_lock - Request exclusive access to vc transaction
* @xn: struct idpf_vc_xn* to access
*/
#define idpf_vc_xn_lock(xn) \
- raw_spin_lock(&(xn)->completed.wait.lock)
+ spin_lock(&(xn)->lock)
/**
* idpf_vc_xn_unlock - Release exclusive access to vc transaction
* @xn: struct idpf_vc_xn* to access
*/
#define idpf_vc_xn_unlock(xn) \
- raw_spin_unlock(&(xn)->completed.wait.lock)
+ spin_unlock(&(xn)->lock)
/**
* idpf_vc_xn_release_bufs - Release reference to reply buffer(s) and
@@ -338,6 +333,7 @@ static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
xn->state = IDPF_VC_XN_IDLE;
xn->idx = i;
idpf_vc_xn_release_bufs(xn);
+ spin_lock_init(&xn->lock);
init_completion(&xn->completed);
}
@@ -406,7 +402,9 @@ static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr,
struct idpf_vc_xn *xn)
{
idpf_vc_xn_release_bufs(xn);
+ spin_lock_bh(&vcxn_mngr->xn_bm_lock);
set_bit(xn->idx, vcxn_mngr->free_xn_bm);
+ spin_unlock_bh(&vcxn_mngr->xn_bm_lock);
}
/**
@@ -617,6 +615,10 @@ idpf_vc_xn_forward_reply(struct idpf_adapter *adapter,
err = -ENXIO;
goto out_unlock;
case IDPF_VC_XN_ASYNC:
+ /* Set reply_sz from the actual payload so that async_handler
+ * can evaluate the response.
+ */
+ xn->reply_sz = ctlq_msg->data_len;
err = idpf_vc_xn_forward_async(adapter, xn, ctlq_msg);
idpf_vc_xn_unlock(xn);
return err;
@@ -3668,7 +3670,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter)
idpf_ptp_release(adapter);
idpf_deinit_task(adapter);
- idpf_idc_deinit_core_aux_device(adapter->cdev_info);
+ idpf_idc_deinit_core_aux_device(adapter);
idpf_rel_rx_pt_lkup(adapter);
idpf_intr_rel(adapter);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index fe065911ad5a..6876e3ed9d1b 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -42,8 +42,8 @@ typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
* struct idpf_vc_xn - Data structure representing virtchnl transactions
* @completed: virtchnl event loop uses that to signal when a reply is
* available, uses kernel completion API
- * @state: virtchnl event loop stores the data below, protected by the
- * completion's lock.
+ * @lock: protects the transaction state fields below
+ * @state: virtchnl event loop stores the data below, protected by @lock
* @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be
* truncated on its way to the receiver thread according to
* reply_buf.iov_len.
@@ -58,6 +58,7 @@ typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *,
*/
struct idpf_vc_xn {
struct completion completed;
+ spinlock_t lock;
enum idpf_vc_xn_state state;
size_t reply_sz;
struct kvec reply;
diff --git a/drivers/net/ethernet/intel/idpf/xdp.c b/drivers/net/ethernet/intel/idpf/xdp.c
index 6ac9c6624c2a..cbccd4546768 100644
--- a/drivers/net/ethernet/intel/idpf/xdp.c
+++ b/drivers/net/ethernet/intel/idpf/xdp.c
@@ -47,12 +47,16 @@ static int __idpf_xdp_rxq_info_init(struct idpf_rx_queue *rxq, void *arg)
{
const struct idpf_vport *vport = rxq->q_vector->vport;
const struct idpf_q_vec_rsrc *rsrc;
+ u32 frag_size = 0;
bool split;
int err;
+ if (idpf_queue_has(XSK, rxq))
+ frag_size = rxq->bufq_sets[0].bufq.truesize;
+
err = __xdp_rxq_info_reg(&rxq->xdp_rxq, vport->netdev, rxq->idx,
rxq->q_vector->napi.napi_id,
- rxq->rx_buf_size);
+ frag_size);
if (err)
return err;
diff --git a/drivers/net/ethernet/intel/idpf/xsk.c b/drivers/net/ethernet/intel/idpf/xsk.c
index 676cbd80774d..d95d3efdfd36 100644
--- a/drivers/net/ethernet/intel/idpf/xsk.c
+++ b/drivers/net/ethernet/intel/idpf/xsk.c
@@ -403,6 +403,7 @@ int idpf_xskfq_init(struct idpf_buf_queue *bufq)
bufq->pending = fq.pending;
bufq->thresh = fq.thresh;
bufq->rx_buf_size = fq.buf_len;
+ bufq->truesize = fq.truesize;
if (!idpf_xskfq_refill(bufq))
netdev_err(bufq->pool->netdev,
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ee99fd8fd513..ce91dda00ec0 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2203,9 +2203,8 @@ void igb_down(struct igb_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
- napi_synchronize(&adapter->q_vector[i]->napi);
- igb_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
+ igb_set_queue_napi(adapter, i, NULL);
}
}
diff --git a/drivers/net/ethernet/intel/igb/igb_xsk.c b/drivers/net/ethernet/intel/igb/igb_xsk.c
index 30ce5fbb5b77..ce4a7b58cad2 100644
--- a/drivers/net/ethernet/intel/igb/igb_xsk.c
+++ b/drivers/net/ethernet/intel/igb/igb_xsk.c
@@ -524,6 +524,16 @@ bool igb_xmit_zc(struct igb_ring *tx_ring, struct xsk_buff_pool *xsk_pool)
return nb_pkts < budget;
}
+static u32 igb_sw_irq_prep(struct igb_q_vector *q_vector)
+{
+ u32 eics = 0;
+
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ eics = q_vector->eims_value;
+
+ return eics;
+}
+
int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
{
struct igb_adapter *adapter = netdev_priv(dev);
@@ -542,20 +552,32 @@ int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
ring = adapter->tx_ring[qid];
- if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
- return -ENETDOWN;
-
if (!READ_ONCE(ring->xsk_pool))
return -EINVAL;
- if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
+ if (flags & XDP_WAKEUP_TX) {
+ if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
+ return -ENETDOWN;
+
+ eics |= igb_sw_irq_prep(ring->q_vector);
+ }
+
+ if (flags & XDP_WAKEUP_RX) {
+ /* If IGB_FLAG_QUEUE_PAIRS is active, the q_vector
+ * and NAPI is shared between RX and TX.
+ * If NAPI is already running it would be marked as missed
+ * from the TX path, making this RX call a NOP
+ */
+ ring = adapter->rx_ring[qid];
+ eics |= igb_sw_irq_prep(ring->q_vector);
+ }
+
+ if (eics) {
/* Cause software interrupt */
- if (adapter->flags & IGB_FLAG_HAS_MSIX) {
- eics |= ring->q_vector->eims_value;
+ if (adapter->flags & IGB_FLAG_HAS_MSIX)
wr32(E1000_EICS, eics);
- } else {
+ else
wr32(E1000_ICS, E1000_ICS_RXDMT0);
- }
}
return 0;
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index a427f05814c1..17236813965d 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -781,6 +781,8 @@ int igc_ptp_hwtstamp_set(struct net_device *netdev,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
void igc_ptp_tx_hang(struct igc_adapter *adapter);
+void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter,
+ u16 queue_id);
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 27e5c2109138..72bc5128d8b8 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -264,6 +264,13 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
/* reset next_to_use and next_to_clean */
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
+
+ /* Clear any lingering XSK TX timestamp requests */
+ if (test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags)) {
+ struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
+
+ igc_ptp_clear_xsk_tx_tstamp_queue(adapter, tx_ring->queue_index);
+ }
}
/**
@@ -1730,11 +1737,8 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
- if (skb->len < 17) {
- if (skb_padto(skb, 17))
- return NETDEV_TX_OK;
- skb->len = 17;
- }
+ if (skb_put_padto(skb, 17))
+ return NETDEV_TX_OK;
return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));
}
@@ -6906,28 +6910,29 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
return nxmit;
}
-static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
- struct igc_q_vector *q_vector)
+static u32 igc_sw_irq_prep(struct igc_q_vector *q_vector)
{
- struct igc_hw *hw = &adapter->hw;
u32 eics = 0;
- eics |= q_vector->eims_value;
- wr32(IGC_EICS, eics);
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ eics = q_vector->eims_value;
+
+ return eics;
}
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
{
struct igc_adapter *adapter = netdev_priv(dev);
- struct igc_q_vector *q_vector;
+ struct igc_hw *hw = &adapter->hw;
struct igc_ring *ring;
+ u32 eics = 0;
if (test_bit(__IGC_DOWN, &adapter->state))
return -ENETDOWN;
if (!igc_xdp_is_enabled(adapter))
return -ENXIO;
-
+ /* Check if queue_id is valid. Tx and Rx queue numbers are always same */
if (queue_id >= adapter->num_rx_queues)
return -EINVAL;
@@ -6936,9 +6941,22 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
if (!ring->xsk_pool)
return -ENXIO;
- q_vector = adapter->q_vector[queue_id];
- if (!napi_if_scheduled_mark_missed(&q_vector->napi))
- igc_trigger_rxtxq_interrupt(adapter, q_vector);
+ if (flags & XDP_WAKEUP_RX)
+ eics |= igc_sw_irq_prep(ring->q_vector);
+
+ if (flags & XDP_WAKEUP_TX) {
+ /* If IGC_FLAG_QUEUE_PAIRS is active, the q_vector
+ * and NAPI is shared between RX and TX.
+ * If NAPI is already running it would be marked as missed
+ * from the RX path, making this TX call a NOP
+ */
+ ring = adapter->tx_ring[queue_id];
+ eics |= igc_sw_irq_prep(ring->q_vector);
+ }
+
+ if (eics)
+ /* Cause software interrupt */
+ wr32(IGC_EICS, eics);
return 0;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 7aae83c108fd..3d6b2264164a 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -550,7 +550,8 @@ static void igc_ptp_free_tx_buffer(struct igc_adapter *adapter,
tstamp->buffer_type = 0;
/* Trigger txrx interrupt for transmit completion */
- igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index, 0);
+ igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index,
+ XDP_WAKEUP_TX);
return;
}
@@ -576,6 +577,39 @@ static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
}
+/**
+ * igc_ptp_clear_xsk_tx_tstamp_queue - Clear pending XSK TX timestamps for a queue
+ * @adapter: Board private structure
+ * @queue_id: TX queue index to clear timestamps for
+ *
+ * Iterates over all TX timestamp registers and releases any pending
+ * timestamp requests associated with the given TX queue. This is
+ * called when an XDP pool is being disabled to ensure no stale
+ * timestamp references remain.
+ */
+void igc_ptp_clear_xsk_tx_tstamp_queue(struct igc_adapter *adapter, u16 queue_id)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
+
+ for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+ struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+ if (tstamp->buffer_type != IGC_TX_BUFFER_TYPE_XSK)
+ continue;
+ if (tstamp->xsk_queue_index != queue_id)
+ continue;
+ if (!tstamp->xsk_tx_buffer)
+ continue;
+
+ igc_ptp_free_tx_buffer(adapter, tstamp);
+ }
+
+ spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
+}
+
static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c
index b0404f37271a..cf8908b82f8a 100644
--- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c
+++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c
@@ -474,7 +474,7 @@ static int ixgbe_devlink_reload_empr_finish(struct devlink *devlink,
adapter->flags2 &= ~(IXGBE_FLAG2_API_MISMATCH |
IXGBE_FLAG2_FW_ROLLBACK);
- return 0;
+ return ixgbe_refresh_fw_version(adapter);
}
static const struct devlink_ops ixgbe_devlink_ops = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index dce4936708eb..047f04045585 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -973,7 +973,7 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
bool ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
u16 subdevice_id);
void ixgbe_set_fw_version_e610(struct ixgbe_adapter *adapter);
-void ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter);
+int ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter);
#ifdef CONFIG_PCI_IOV
void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter);
#endif
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 56aabaa5caec..ba049b3a9609 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1155,12 +1155,17 @@ err:
return ret_val;
}
-void ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter)
+int ixgbe_refresh_fw_version(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
+ int err;
+
+ err = ixgbe_get_flash_data(hw);
+ if (err)
+ return err;
- ixgbe_get_flash_data(hw);
ixgbe_set_fw_version_e610(adapter);
+ return 0;
}
static void ixgbe_get_drvinfo(struct net_device *netdev,
@@ -1168,10 +1173,6 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
{
struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev);
- /* need to refresh info for e610 in case fw reloads in runtime */
- if (adapter->hw.mac.type == ixgbe_mac_e610)
- ixgbe_refresh_fw_version(adapter);
-
strscpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
strscpy(drvinfo->fw_version, adapter->eeprom_id,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index e4101c59074d..59801187a839 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6289,6 +6289,16 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
msleep(2000);
ixgbe_up(adapter);
+
+ /* E610 has no FW event to notify all PFs of an EMPR reset, so
+ * refresh the FW version here to pick up any new FW version after
+ * a hardware reset (e.g. EMPR triggered by another PF's devlink
+ * reload). ixgbe_refresh_fw_version() updates both hw->flash and
+ * adapter->eeprom_id so ethtool -i reports the correct string.
+ */
+ if (adapter->hw.mac.type == ixgbe_mac_e610)
+ (void)ixgbe_refresh_fw_version(adapter);
+
clear_bit(__IXGBE_RESETTING, &adapter->state);
}
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index 74d320879513..f6df86d124b9 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -709,6 +709,12 @@ static int ixgbevf_negotiate_features_vf(struct ixgbe_hw *hw, u32 *pf_features)
return err;
}
+static int ixgbevf_hv_negotiate_features_vf(struct ixgbe_hw *hw,
+ u32 *pf_features)
+{
+ return -EOPNOTSUPP;
+}
+
/**
* ixgbevf_set_vfta_vf - Set/Unset VLAN filter table address
* @hw: pointer to the HW structure
@@ -852,7 +858,8 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
if (!mac->get_link_status)
goto out;
- if (hw->mac.type == ixgbe_mac_e610_vf) {
+ if (hw->mac.type == ixgbe_mac_e610_vf &&
+ hw->api_version >= ixgbe_mbox_api_16) {
ret_val = ixgbevf_get_pf_link_state(hw, speed, link_up);
if (ret_val)
goto out;
@@ -1141,6 +1148,7 @@ static const struct ixgbe_mac_operations ixgbevf_hv_mac_ops = {
.setup_link = ixgbevf_setup_mac_link_vf,
.check_link = ixgbevf_hv_check_mac_link_vf,
.negotiate_api_version = ixgbevf_hv_negotiate_api_version_vf,
+ .negotiate_features = ixgbevf_hv_negotiate_features_vf,
.set_rar = ixgbevf_hv_set_rar_vf,
.update_mc_addr_list = ixgbevf_hv_update_mc_addr_list_vf,
.update_xcast_mode = ixgbevf_hv_update_xcast_mode,
diff --git a/drivers/net/ethernet/intel/libeth/xsk.c b/drivers/net/ethernet/intel/libeth/xsk.c
index 846e902e31b6..4882951d5c9c 100644
--- a/drivers/net/ethernet/intel/libeth/xsk.c
+++ b/drivers/net/ethernet/intel/libeth/xsk.c
@@ -167,6 +167,7 @@ int libeth_xskfq_create(struct libeth_xskfq *fq)
fq->pending = fq->count;
fq->thresh = libeth_xdp_queue_threshold(fq->count);
fq->buf_len = xsk_pool_get_rx_frame_size(fq->pool);
+ fq->truesize = xsk_pool_get_rx_frag_step(fq->pool);
return 0;
}
diff --git a/drivers/net/ethernet/intel/libie/fwlog.c b/drivers/net/ethernet/intel/libie/fwlog.c
index 79020d990859..96bba57c8a5b 100644
--- a/drivers/net/ethernet/intel/libie/fwlog.c
+++ b/drivers/net/ethernet/intel/libie/fwlog.c
@@ -433,17 +433,21 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
module = libie_find_module_by_dentry(fwlog->debugfs_modules, dentry);
if (module < 0) {
dev_info(dev, "unknown module\n");
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
cnt = sscanf(cmd_buf, "%s", user_val);
- if (cnt != 1)
- return -EINVAL;
+ if (cnt != 1) {
+ count = -EINVAL;
+ goto free_cmd_buf;
+ }
log_level = sysfs_match_string(libie_fwlog_level_string, user_val);
if (log_level < 0) {
dev_info(dev, "unknown log level '%s'\n", user_val);
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
if (module != LIBIE_AQC_FW_LOG_ID_MAX) {
@@ -458,6 +462,9 @@ libie_debugfs_module_write(struct file *filp, const char __user *buf,
fwlog->cfg.module_entries[i].log_level = log_level;
}
+free_cmd_buf:
+ kfree(cmd_buf);
+
return count;
}
@@ -515,23 +522,31 @@ libie_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ count = -EINVAL;
+ goto free_cmd_buf;
+ }
ret = kstrtos16(user_val, 0, &nr_messages);
- if (ret)
- return ret;
+ if (ret) {
+ count = ret;
+ goto free_cmd_buf;
+ }
if (nr_messages < LIBIE_AQC_FW_LOG_MIN_RESOLUTION ||
nr_messages > LIBIE_AQC_FW_LOG_MAX_RESOLUTION) {
dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
nr_messages, LIBIE_AQC_FW_LOG_MIN_RESOLUTION,
LIBIE_AQC_FW_LOG_MAX_RESOLUTION);
- return -EINVAL;
+ count = -EINVAL;
+ goto free_cmd_buf;
}
fwlog->cfg.log_resolution = nr_messages;
+free_cmd_buf:
+ kfree(cmd_buf);
+
return count;
}
@@ -588,8 +603,10 @@ libie_debugfs_enable_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto free_cmd_buf;
+ }
ret = kstrtobool(user_val, &enable);
if (ret)
@@ -624,6 +641,8 @@ enable_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
+free_cmd_buf:
+ kfree(cmd_buf);
return ret;
}
@@ -682,8 +701,10 @@ libie_debugfs_log_size_write(struct file *filp, const char __user *buf,
return PTR_ERR(cmd_buf);
ret = sscanf(cmd_buf, "%s", user_val);
- if (ret != 1)
- return -EINVAL;
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto free_cmd_buf;
+ }
index = sysfs_match_string(libie_fwlog_log_size, user_val);
if (index < 0) {
@@ -712,6 +733,8 @@ log_size_write_error:
*/
if (WARN_ON(ret != (ssize_t)count && ret >= 0))
ret = -EIO;
+free_cmd_buf:
+ kfree(cmd_buf);
return ret;
}
@@ -1049,6 +1072,10 @@ void libie_fwlog_deinit(struct libie_fwlog *fwlog)
{
int status;
+ /* if FW logging isn't supported it means no configuration was done */
+ if (!libie_fwlog_supported(fwlog))
+ return;
+
/* make sure FW logging is disabled to not put the FW in a weird state
* for the next driver load
*/
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index d1b8650cb4b4..f442b874bb59 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -5016,7 +5016,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
if (priv->percpu_pools)
numbufs = port->nrxqs * 2;
- if (change_percpu)
+ if (change_percpu && priv->global_tx_fc)
mvpp2_bm_pool_update_priv_fc(priv, false);
for (i = 0; i < numbufs; i++)
@@ -5041,7 +5041,7 @@ static int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
mvpp2_open(port->dev);
}
- if (change_percpu)
+ if (change_percpu && priv->global_tx_fc)
mvpp2_bm_pool_update_priv_fc(priv, true);
return 0;
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
index ec55eb2a6c04..028dd55604ea 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
@@ -554,28 +554,43 @@ static void octep_clean_irqs(struct octep_device *oct)
}
/**
- * octep_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ * octep_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
-static void octep_enable_ioq_irq(struct octep_iq *iq, struct octep_oq *oq)
+static void octep_update_pkt(struct octep_iq *iq, struct octep_oq *oq)
{
- u32 pkts_pend = oq->pkts_pending;
+ u32 pkts_pend = READ_ONCE(oq->pkts_pending);
+ u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ u32 pkts_processed = READ_ONCE(iq->pkts_processed);
+ u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
- if (iq->pkts_processed) {
- writel(iq->pkts_processed, iq->inst_cnt_reg);
- iq->pkt_in_done -= iq->pkts_processed;
- iq->pkts_processed = 0;
+ if (pkts_processed) {
+ writel(pkts_processed, iq->inst_cnt_reg);
+ readl(iq->inst_cnt_reg);
+ WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
+ WRITE_ONCE(iq->pkts_processed, 0);
}
- if (oq->last_pkt_count - pkts_pend) {
- writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
- oq->last_pkt_count = pkts_pend;
+ if (last_pkt_count - pkts_pend) {
+ writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
+ readl(oq->pkts_sent_reg);
+ WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
- wmb();
+ smp_wmb();
+}
+
+/**
+ * octep_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ *
+ * @iq: Octeon Tx queue data structure.
+ * @oq: Octeon Rx queue data structure.
+ */
+static void octep_enable_ioq_irq(struct octep_iq *iq, struct octep_oq *oq)
+{
writeq(1UL << OCTEP_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@@ -601,7 +616,8 @@ static int octep_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
- napi_complete(napi);
+ octep_update_pkt(ioq_vector->iq, ioq_vector->oq);
+ napi_complete_done(napi, rx_done);
octep_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
return rx_done;
}
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
index f2a7c6a76c74..74de19166488 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
@@ -324,10 +324,16 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
struct octep_oq *oq)
{
u32 pkt_count, new_pkts;
+ u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
- new_pkts = pkt_count - oq->last_pkt_count;
+ last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ new_pkts = pkt_count - last_pkt_count;
+ if (pkt_count < last_pkt_count) {
+ dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
+ oq->q_no, pkt_count, last_pkt_count);
+ }
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
* reached half its max value.
@@ -338,8 +344,9 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
- oq->last_pkt_count = pkt_count;
- oq->pkts_pending += new_pkts;
+ WRITE_ONCE(oq->last_pkt_count, pkt_count);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
@@ -414,7 +421,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
u16 rx_ol_flags;
u32 read_idx;
- read_idx = oq->host_read_idx;
+ read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@@ -499,7 +506,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
napi_gro_receive(oq->napi, skb);
}
- oq->host_read_idx = read_idx;
+ WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@@ -522,22 +529,26 @@ int octep_oq_process_rx(struct octep_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_device *oct = oq->octep_dev;
+ u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
- if (oq->pkts_pending == 0)
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ if (pkts_pending == 0)
octep_oq_check_hw_for_pkts(oct, oq);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
- oq->pkts_pending);
+ pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_oq_process_rx(oct, oq,
pkts_available);
- oq->pkts_pending -= pkts_processed;
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
index 562fe945b422..7f1b93cffb98 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
@@ -286,28 +286,45 @@ static void octep_vf_clean_irqs(struct octep_vf_device *oct)
}
/**
- * octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ * octep_vf_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
-static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
+
+static void octep_vf_update_pkt(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
{
- u32 pkts_pend = oq->pkts_pending;
+ u32 pkts_pend = READ_ONCE(oq->pkts_pending);
+ u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ u32 pkts_processed = READ_ONCE(iq->pkts_processed);
+ u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
- if (iq->pkts_processed) {
- writel(iq->pkts_processed, iq->inst_cnt_reg);
- iq->pkt_in_done -= iq->pkts_processed;
- iq->pkts_processed = 0;
+ if (pkts_processed) {
+ writel(pkts_processed, iq->inst_cnt_reg);
+ readl(iq->inst_cnt_reg);
+ WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
+ WRITE_ONCE(iq->pkts_processed, 0);
}
- if (oq->last_pkt_count - pkts_pend) {
- writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
- oq->last_pkt_count = pkts_pend;
+ if (last_pkt_count - pkts_pend) {
+ writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
+ readl(oq->pkts_sent_reg);
+ WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
+}
+
+/**
+ * octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ *
+ * @iq: Octeon Tx queue data structure.
+ * @oq: Octeon Rx queue data structure.
+ */
+static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq,
+ struct octep_vf_oq *oq)
+{
writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@@ -333,6 +350,7 @@ static int octep_vf_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
+ octep_vf_update_pkt(ioq_vector->iq, ioq_vector->oq);
if (likely(napi_complete_done(napi, rx_done)))
octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
index 6f865dbbba6c..b579d5b545c4 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
@@ -325,9 +325,16 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
struct octep_vf_oq *oq)
{
u32 pkt_count, new_pkts;
+ u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
- new_pkts = pkt_count - oq->last_pkt_count;
+ last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ new_pkts = pkt_count - last_pkt_count;
+
+ if (pkt_count < last_pkt_count) {
+ dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
+ oq->q_no, pkt_count, last_pkt_count);
+ }
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
@@ -339,8 +346,9 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
- oq->last_pkt_count = pkt_count;
- oq->pkts_pending += new_pkts;
+ WRITE_ONCE(oq->last_pkt_count, pkt_count);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
@@ -369,7 +377,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
struct sk_buff *skb;
u32 read_idx;
- read_idx = oq->host_read_idx;
+ read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@@ -463,7 +471,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
napi_gro_receive(oq->napi, skb);
}
- oq->host_read_idx = read_idx;
+ WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@@ -486,22 +494,26 @@ int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_vf_device *oct = oq->octep_vf_dev;
+ u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
- if (oq->pkts_pending == 0)
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ if (pkts_pending == 0)
octep_vf_oq_check_hw_for_pkts(oct, oq);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
- oq->pkts_pending);
+ pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_vf_oq_process_rx(oct, oq,
pkts_available);
- oq->pkts_pending -= pkts_processed;
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index fb15c794efc9..a29f1ea04c7d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -327,10 +327,10 @@ static int rvu_nix_report_show(struct devlink_fmsg *fmsg, void *ctx,
rvu_report_pair_end(fmsg);
break;
case NIX_AF_RVU_RAS:
- intr_val = nix_event_context->nix_af_rvu_err;
+ intr_val = nix_event_context->nix_af_rvu_ras;
rvu_report_pair_start(fmsg, "NIX_AF_RAS");
devlink_fmsg_u64_pair_put(fmsg, "\tNIX RAS Interrupt Reg ",
- nix_event_context->nix_af_rvu_err);
+ nix_event_context->nix_af_rvu_ras);
devlink_fmsg_string_put(fmsg, "\n\tPoison Data on:");
if (intr_val & BIT_ULL(34))
devlink_fmsg_string_put(fmsg, "\n\tNIX_AQ_INST_S");
@@ -475,7 +475,7 @@ static int rvu_hw_nix_ras_recover(struct devlink_health_reporter *reporter,
if (blkaddr < 0)
return blkaddr;
- if (nix_event_ctx->nix_af_rvu_int)
+ if (nix_event_ctx->nix_af_rvu_ras)
rvu_write64(rvu, blkaddr, NIX_AF_RAS_ENA_W1S, ~0ULL);
return 0;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e5e2ffa9c542..ddc321a02fda 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3748,12 +3748,21 @@ static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog,
mtk_stop(dev);
old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held());
+
+ if (netif_running(dev) && need_update) {
+ int err;
+
+ err = mtk_open(dev);
+ if (err) {
+ rcu_assign_pointer(eth->prog, old_prog);
+
+ return err;
+ }
+ }
+
if (old_prog)
bpf_prog_put(old_prog);
- if (netif_running(dev) && need_update)
- return mtk_open(dev);
-
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index cb30108f2bf6..cc8c4ef8038f 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -244,6 +244,25 @@ out:
return 0;
}
+static bool
+mtk_flow_is_valid_idev(const struct mtk_eth *eth, const struct net_device *idev)
+{
+ size_t i;
+
+ if (!idev)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(eth->netdev); i++) {
+ if (!eth->netdev[i])
+ continue;
+
+ if (idev->netdev_ops == eth->netdev[i]->netdev_ops)
+ return true;
+ }
+
+ return false;
+}
+
static int
mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
int ppe_index)
@@ -270,7 +289,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
flow_rule_match_meta(rule, &match);
if (mtk_is_netsys_v2_or_greater(eth)) {
idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
- if (idev && idev->netdev_ops == eth->netdev[0]->netdev_ops) {
+ if (mtk_flow_is_valid_idev(eth, idev)) {
struct mtk_mac *mac = netdev_priv(idev);
if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 6698ac55a4bf..73cf0321bb86 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -107,9 +107,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
if (err)
return err;
- err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
- if (err)
- return err;
+ mlx5_fw_version_query(dev, &running_fw, &stored_fw);
snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
index 60ba840e00fa..afdeb1b3d425 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
@@ -47,7 +47,6 @@ static void mlx5e_reset_txqsq_cc_pc(struct mlx5e_txqsq *sq)
"SQ 0x%x: cc (0x%x) != pc (0x%x)\n",
sq->sqn, sq->cc, sq->pc);
sq->cc = 0;
- sq->dma_fifo_cc = 0;
sq->pc = 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 415208abf10e..64e13747084e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -259,7 +259,6 @@ static void mlx5e_ipsec_init_limits(struct mlx5e_ipsec_sa_entry *sa_entry,
static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_accel_esp_xfrm_attrs *attrs)
{
- struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
struct mlx5e_ipsec_addr *addrs = &attrs->addrs;
struct net_device *netdev = sa_entry->dev;
struct xfrm_state *x = sa_entry->x;
@@ -276,7 +275,7 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
attrs->type != XFRM_DEV_OFFLOAD_PACKET)
return;
- mlx5_query_mac_address(mdev, addr);
+ ether_addr_copy(addr, netdev->dev_addr);
switch (attrs->dir) {
case XFRM_DEV_OFFLOAD_IN:
src = attrs->dmac;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
index f8eaaf37963b..abcbd38db9db 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
@@ -287,6 +287,7 @@ struct mlx5e_ipsec_sa_entry {
struct mlx5e_ipsec_dwork *dwork;
struct mlx5e_ipsec_limits limits;
u32 rx_mapped_id;
+ u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
};
struct mlx5_accel_pol_xfrm_attrs {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
index 197a1c6930c0..329608c59313 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
@@ -2912,7 +2912,7 @@ void mlx5e_ipsec_disable_events(struct mlx5e_priv *priv)
goto out;
peer_priv = mlx5_devcom_get_next_peer_data(priv->devcom, &tmp);
- if (peer_priv)
+ if (peer_priv && peer_priv->ipsec)
complete_all(&peer_priv->ipsec->comp);
mlx5_devcom_for_each_peer_end(priv->devcom);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
index 33344e00719b..05faad5083d9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
@@ -310,10 +310,11 @@ static void mlx5e_ipsec_aso_update(struct mlx5e_ipsec_sa_entry *sa_entry,
mlx5e_ipsec_aso_query(sa_entry, data);
}
-static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
- u32 mode_param)
+static void
+mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
+ u32 mode_param,
+ struct mlx5_accel_esp_xfrm_attrs *attrs)
{
- struct mlx5_accel_esp_xfrm_attrs attrs = {};
struct mlx5_wqe_aso_ctrl_seg data = {};
if (mode_param < MLX5E_IPSEC_ESN_SCOPE_MID) {
@@ -323,18 +324,7 @@ static void mlx5e_ipsec_update_esn_state(struct mlx5e_ipsec_sa_entry *sa_entry,
sa_entry->esn_state.overlap = 1;
}
- mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &attrs);
-
- /* It is safe to execute the modify below unlocked since the only flows
- * that could affect this HW object, are create, destroy and this work.
- *
- * Creation flow can't co-exist with this modify work, the destruction
- * flow would cancel this work, and this work is a single entity that
- * can't conflict with it self.
- */
- spin_unlock_bh(&sa_entry->x->lock);
- mlx5_accel_esp_modify_xfrm(sa_entry, &attrs);
- spin_lock_bh(&sa_entry->x->lock);
+ mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, attrs);
data.data_offset_condition_operand =
MLX5_IPSEC_ASO_REMOVE_FLOW_PKT_CNT_OFFSET;
@@ -370,20 +360,18 @@ static void mlx5e_ipsec_aso_update_soft(struct mlx5e_ipsec_sa_entry *sa_entry,
static void mlx5e_ipsec_handle_limits(struct mlx5e_ipsec_sa_entry *sa_entry)
{
struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
- struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
- struct mlx5e_ipsec_aso *aso = ipsec->aso;
bool soft_arm, hard_arm;
u64 hard_cnt;
lockdep_assert_held(&sa_entry->x->lock);
- soft_arm = !MLX5_GET(ipsec_aso, aso->ctx, soft_lft_arm);
- hard_arm = !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm);
+ soft_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, soft_lft_arm);
+ hard_arm = !MLX5_GET(ipsec_aso, sa_entry->ctx, hard_lft_arm);
if (!soft_arm && !hard_arm)
/* It is not lifetime event */
return;
- hard_cnt = MLX5_GET(ipsec_aso, aso->ctx, remove_flow_pkt_cnt);
+ hard_cnt = MLX5_GET(ipsec_aso, sa_entry->ctx, remove_flow_pkt_cnt);
if (!hard_cnt || hard_arm) {
/* It is possible to see packet counter equal to zero without
* hard limit event armed. Such situation can be if packet
@@ -453,11 +441,11 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
struct mlx5e_ipsec_work *work =
container_of(_work, struct mlx5e_ipsec_work, work);
struct mlx5e_ipsec_sa_entry *sa_entry = work->data;
+ struct mlx5_accel_esp_xfrm_attrs tmp = {};
struct mlx5_accel_esp_xfrm_attrs *attrs;
- struct mlx5e_ipsec_aso *aso;
+ bool need_modify = false;
int ret;
- aso = sa_entry->ipsec->aso;
attrs = &sa_entry->attrs;
spin_lock_bh(&sa_entry->x->lock);
@@ -465,18 +453,22 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
if (ret)
goto unlock;
+ if (attrs->lft.soft_packet_limit != XFRM_INF)
+ mlx5e_ipsec_handle_limits(sa_entry);
+
if (attrs->replay_esn.trigger &&
- !MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) {
- u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter);
+ !MLX5_GET(ipsec_aso, sa_entry->ctx, esn_event_arm)) {
+ u32 mode_param = MLX5_GET(ipsec_aso, sa_entry->ctx,
+ mode_parameter);
- mlx5e_ipsec_update_esn_state(sa_entry, mode_param);
+ mlx5e_ipsec_update_esn_state(sa_entry, mode_param, &tmp);
+ need_modify = true;
}
- if (attrs->lft.soft_packet_limit != XFRM_INF)
- mlx5e_ipsec_handle_limits(sa_entry);
-
unlock:
spin_unlock_bh(&sa_entry->x->lock);
+ if (need_modify)
+ mlx5_accel_esp_modify_xfrm(sa_entry, &tmp);
kfree(work);
}
@@ -629,6 +621,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
/* We are in atomic context */
udelay(10);
} while (ret && time_is_after_jiffies(expires));
+ if (!ret)
+ memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso));
spin_unlock_bh(&aso->lock);
return ret;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index efcfcddab376..268e20884757 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -1589,6 +1589,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
struct skb_shared_info *sinfo;
u32 frag_consumed_bytes;
struct bpf_prog *prog;
+ u8 nr_frags_free = 0;
struct sk_buff *skb;
dma_addr_t addr;
u32 truesize;
@@ -1631,15 +1632,13 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
prog = rcu_dereference(rq->xdp_prog);
if (prog) {
- u8 nr_frags_free, old_nr_frags = sinfo->nr_frags;
+ u8 old_nr_frags = sinfo->nr_frags;
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT,
rq->flags)) {
struct mlx5e_wqe_frag_info *pwi;
- wi -= old_nr_frags - sinfo->nr_frags;
-
for (pwi = head_wi; pwi < wi; pwi++)
pwi->frag_page->frags++;
}
@@ -1647,10 +1646,8 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
}
nr_frags_free = old_nr_frags - sinfo->nr_frags;
- if (unlikely(nr_frags_free)) {
- wi -= nr_frags_free;
+ if (unlikely(nr_frags_free))
truesize -= nr_frags_free * frag_info->frag_stride;
- }
}
skb = mlx5e_build_linear_skb(
@@ -1666,7 +1663,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
if (xdp_buff_has_frags(&mxbuf->xdp)) {
/* sinfo->nr_frags is reset by build_skb, calculate again. */
- xdp_update_skb_frags_info(skb, wi - head_wi - 1,
+ xdp_update_skb_frags_info(skb, wi - head_wi - nr_frags_free - 1,
sinfo->xdp_frags_size, truesize,
xdp_buff_get_skb_flags(&mxbuf->xdp));
@@ -1957,14 +1954,13 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
if (prog) {
u8 nr_frags_free, old_nr_frags = sinfo->nr_frags;
+ u8 new_nr_frags;
u32 len;
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
struct mlx5e_frag_page *pfp;
- frag_page -= old_nr_frags - sinfo->nr_frags;
-
for (pfp = head_page; pfp < frag_page; pfp++)
pfp->frags++;
@@ -1975,13 +1971,12 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
return NULL; /* page/packet was consumed by XDP */
}
- nr_frags_free = old_nr_frags - sinfo->nr_frags;
- if (unlikely(nr_frags_free)) {
- frag_page -= nr_frags_free;
+ new_nr_frags = sinfo->nr_frags;
+ nr_frags_free = old_nr_frags - new_nr_frags;
+ if (unlikely(nr_frags_free))
truesize -= (nr_frags_free - 1) * PAGE_SIZE +
ALIGN(pg_consumed_bytes,
BIT(rq->mpwqe.log_stride_sz));
- }
len = mxbuf->xdp.data_end - mxbuf->xdp.data;
@@ -2003,7 +1998,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
struct mlx5e_frag_page *pagep;
/* sinfo->nr_frags is reset by build_skb, calculate again. */
- xdp_update_skb_frags_info(skb, frag_page - head_page,
+ xdp_update_skb_frags_info(skb, new_nr_frags,
sinfo->xdp_frags_size,
truesize,
xdp_buff_get_skb_flags(&mxbuf->xdp));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
index 26178d0bac92..faccc60fc93a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
@@ -1489,24 +1489,24 @@ out:
return err;
}
-static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
+static u32 mlx5_esw_qos_lag_link_speed_get(struct mlx5_core_dev *mdev,
+ bool take_rtnl)
{
struct ethtool_link_ksettings lksettings;
struct net_device *slave, *master;
u32 speed = SPEED_UNKNOWN;
- /* Lock ensures a stable reference to master and slave netdevice
- * while port speed of master is queried.
- */
- ASSERT_RTNL();
-
slave = mlx5_uplink_netdev_get(mdev);
if (!slave)
goto out;
+ if (take_rtnl)
+ rtnl_lock();
master = netdev_master_upper_dev_get(slave);
if (master && !__ethtool_get_link_ksettings(master, &lksettings))
speed = lksettings.base.speed;
+ if (take_rtnl)
+ rtnl_unlock();
out:
mlx5_uplink_netdev_put(mdev, slave);
@@ -1514,20 +1514,15 @@ out:
}
static int mlx5_esw_qos_max_link_speed_get(struct mlx5_core_dev *mdev, u32 *link_speed_max,
- bool hold_rtnl_lock, struct netlink_ext_ack *extack)
+ bool take_rtnl,
+ struct netlink_ext_ack *extack)
{
int err;
if (!mlx5_lag_is_active(mdev))
goto skip_lag;
- if (hold_rtnl_lock)
- rtnl_lock();
-
- *link_speed_max = mlx5_esw_qos_lag_link_speed_get_locked(mdev);
-
- if (hold_rtnl_lock)
- rtnl_unlock();
+ *link_speed_max = mlx5_esw_qos_lag_link_speed_get(mdev, take_rtnl);
if (*link_speed_max != (u32)SPEED_UNKNOWN)
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index d3af87a94a18..123c96716a54 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1072,10 +1072,11 @@ static void mlx5_eswitch_event_handler_register(struct mlx5_eswitch *esw)
static void mlx5_eswitch_event_handler_unregister(struct mlx5_eswitch *esw)
{
- if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
+ if (esw->mode == MLX5_ESWITCH_OFFLOADS &&
+ mlx5_eswitch_is_funcs_handler(esw->dev)) {
mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
-
- flush_workqueue(esw->work_queue);
+ atomic_inc(&esw->esw_funcs.generation);
+ }
}
static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 6841caef02d1..c2563bee74df 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -335,10 +335,12 @@ struct esw_mc_addr { /* SRIOV only */
struct mlx5_host_work {
struct work_struct work;
struct mlx5_eswitch *esw;
+ int work_gen;
};
struct mlx5_esw_functions {
struct mlx5_nb nb;
+ atomic_t generation;
bool host_funcs_disabled;
u16 num_vfs;
u16 num_ec_vfs;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 82d4c14fdca0..01f6aecc4fcc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -1241,21 +1241,17 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
flows[peer_vport->index] = flow;
}
- if (mlx5_esw_host_functions_enabled(esw->dev)) {
- mlx5_esw_for_each_vf_vport(peer_esw, i, peer_vport,
- mlx5_core_max_vfs(peer_dev)) {
- esw_set_peer_miss_rule_source_port(esw, peer_esw,
- spec,
- peer_vport->vport);
-
- flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
- spec, &flow_act, &dest, 1);
- if (IS_ERR(flow)) {
- err = PTR_ERR(flow);
- goto add_vf_flow_err;
- }
- flows[peer_vport->index] = flow;
+ mlx5_esw_for_each_vf_vport(peer_esw, i, peer_vport,
+ mlx5_core_max_vfs(peer_dev)) {
+ esw_set_peer_miss_rule_source_port(esw, peer_esw, spec,
+ peer_vport->vport);
+ flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
+ spec, &flow_act, &dest, 1);
+ if (IS_ERR(flow)) {
+ err = PTR_ERR(flow);
+ goto add_vf_flow_err;
}
+ flows[peer_vport->index] = flow;
}
if (mlx5_core_ec_sriov_enabled(peer_dev)) {
@@ -1347,7 +1343,8 @@ static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
mlx5_del_flow_rules(flows[peer_vport->index]);
}
- if (mlx5_core_is_ecpf_esw_manager(peer_dev)) {
+ if (mlx5_core_is_ecpf_esw_manager(peer_dev) &&
+ mlx5_esw_host_functions_enabled(peer_dev)) {
peer_vport = mlx5_eswitch_get_vport(peer_esw, MLX5_VPORT_PF);
mlx5_del_flow_rules(flows[peer_vport->index]);
}
@@ -3582,22 +3579,28 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
}
static void
-esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
+esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, int work_gen,
+ const u32 *out)
{
struct devlink *devlink;
bool host_pf_disabled;
u16 new_num_vfs;
+ devlink = priv_to_devlink(esw->dev);
+ devl_lock(devlink);
+
+ /* Stale work from one or more mode changes ago. Bail out. */
+ if (work_gen != atomic_read(&esw->esw_funcs.generation))
+ goto unlock;
+
new_num_vfs = MLX5_GET(query_esw_functions_out, out,
host_params_context.host_num_of_vfs);
host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
host_params_context.host_pf_disabled);
if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
- return;
+ goto unlock;
- devlink = priv_to_devlink(esw->dev);
- devl_lock(devlink);
/* Number of VFs can only change from "0 to x" or "x to 0". */
if (esw->esw_funcs.num_vfs > 0) {
mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
@@ -3612,6 +3615,7 @@ esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
}
}
esw->esw_funcs.num_vfs = new_num_vfs;
+unlock:
devl_unlock(devlink);
}
@@ -3628,7 +3632,7 @@ static void esw_functions_changed_event_handler(struct work_struct *work)
if (IS_ERR(out))
goto out;
- esw_vfs_changed_event_handler(esw, out);
+ esw_vfs_changed_event_handler(esw, host_work->work_gen, out);
kvfree(out);
out:
kfree(host_work);
@@ -3648,6 +3652,7 @@ int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type
esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
host_work->esw = esw;
+ host_work->work_gen = atomic_read(&esw_funcs->generation);
INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
queue_work(esw->work_queue, &host_work->work);
@@ -3756,6 +3761,8 @@ int esw_offloads_enable(struct mlx5_eswitch *esw)
return 0;
err_vports:
+ /* rollback to legacy, indicates don't unregister the uplink netdev */
+ esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY;
mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK);
err_uplink:
esw_offloads_steering_cleanup(esw);
@@ -4068,6 +4075,8 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
if (mlx5_mode == MLX5_ESWITCH_LEGACY)
esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY;
+ if (mlx5_mode == MLX5_ESWITCH_OFFLOADS)
+ esw->dev->priv.flags &= ~MLX5_PRIV_FLAGS_SWITCH_LEGACY;
mlx5_eswitch_disable_locked(esw);
if (mlx5_mode == MLX5_ESWITCH_OFFLOADS) {
if (mlx5_devlink_trap_get_num_active(esw->dev)) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index eeb4437975f2..c1f220e5fe18 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -822,48 +822,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev,
return 0;
}
-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
- u32 *running_ver, u32 *pending_ver)
+void mlx5_fw_version_query(struct mlx5_core_dev *dev,
+ u32 *running_ver, u32 *pending_ver)
{
u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
bool pending_version_exists;
int component_index;
int err;
+ *running_ver = 0;
+ *pending_ver = 0;
+
if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
!MLX5_CAP_MCAM_REG(dev, mcqs)) {
mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
- return -EOPNOTSUPP;
+ return;
}
component_index = mlx5_get_boot_img_component_index(dev);
- if (component_index < 0)
- return component_index;
+ if (component_index < 0) {
+ mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n",
+ component_index);
+ return;
+ }
+ *running_ver = U32_MAX; /* indicate failure */
err = mlx5_reg_mcqi_version_query(dev, component_index,
MCQI_FW_RUNNING_VERSION,
reg_mcqi_version);
- if (err)
- return err;
-
- *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
-
+ if (!err)
+ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
+ version);
+ else
+ mlx5_core_warn(dev, "failed to query running version, err %d\n",
+ err);
+
+ *pending_ver = U32_MAX; /* indicate failure */
err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
- if (err)
- return err;
+ if (err) {
+ mlx5_core_warn(dev, "failed to query pending image, err %d\n",
+ err);
+ return;
+ }
if (!pending_version_exists) {
*pending_ver = 0;
- return 0;
+ return;
}
err = mlx5_reg_mcqi_version_query(dev, component_index,
MCQI_FW_STORED_VERSION,
reg_mcqi_version);
- if (err)
- return err;
-
- *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
-
- return 0;
+ if (!err)
+ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version,
+ version);
+ else
+ mlx5_core_warn(dev, "failed to query pending version, err %d\n",
+ err);
+
+ return;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
index 62b6faa4276a..b8d5f6a44d26 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
@@ -160,8 +160,11 @@ DEFINE_SHOW_ATTRIBUTE(members);
void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
{
+ struct mlx5_lag *ldev = mlx5_lag_dev(dev);
struct dentry *dbg;
+ if (!ldev)
+ return;
dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
dev->priv.dbg.lag_debugfs = dbg;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index c326adb0c789..044adfdf9aa2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -1869,8 +1869,12 @@ void mlx5_lag_disable_change(struct mlx5_core_dev *dev)
mutex_lock(&ldev->lock);
ldev->mode_changes_in_progress++;
- if (__mlx5_lag_is_active(ldev))
- mlx5_disable_lag(ldev);
+ if (__mlx5_lag_is_active(ldev)) {
+ if (ldev->mode == MLX5_LAG_MODE_MPESW)
+ mlx5_lag_disable_mpesw(ldev);
+ else
+ mlx5_disable_lag(ldev);
+ }
mutex_unlock(&ldev->lock);
mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
index 24a91e7a20e2..74d5c2ed14ff 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
@@ -65,7 +65,7 @@ err_metadata:
return err;
}
-static int enable_mpesw(struct mlx5_lag *ldev)
+static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
{
struct mlx5_core_dev *dev0;
int err;
@@ -126,7 +126,7 @@ err_add_devices:
return err;
}
-static void disable_mpesw(struct mlx5_lag *ldev)
+void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev)
{
if (ldev->mode == MLX5_LAG_MODE_MPESW) {
mlx5_mpesw_metadata_cleanup(ldev);
@@ -152,9 +152,9 @@ static void mlx5_mpesw_work(struct work_struct *work)
}
if (mpesww->op == MLX5_MPESW_OP_ENABLE)
- mpesww->result = enable_mpesw(ldev);
+ mpesww->result = mlx5_lag_enable_mpesw(ldev);
else if (mpesww->op == MLX5_MPESW_OP_DISABLE)
- disable_mpesw(ldev);
+ mlx5_lag_disable_mpesw(ldev);
unlock:
mutex_unlock(&ldev->lock);
mlx5_devcom_comp_unlock(devcom);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
index f5d9b5c97b0d..b767dbb4f457 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
@@ -31,6 +31,11 @@ int mlx5_lag_mpesw_do_mirred(struct mlx5_core_dev *mdev,
bool mlx5_lag_is_mpesw(struct mlx5_core_dev *dev);
void mlx5_lag_mpesw_disable(struct mlx5_core_dev *dev);
int mlx5_lag_mpesw_enable(struct mlx5_core_dev *dev);
+#ifdef CONFIG_MLX5_ESWITCH
+void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev);
+#else
+static inline void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev) {}
+#endif /* CONFIG_MLX5_ESWITCH */
#ifdef CONFIG_MLX5_ESWITCH
void mlx5_mpesw_speed_update_work(struct work_struct *work);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index fdc3ba20912e..3f73d9b1115d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -2267,6 +2267,7 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x1023) }, /* ConnectX-8 */
{ PCI_VDEVICE(MELLANOX, 0x1025) }, /* ConnectX-9 */
{ PCI_VDEVICE(MELLANOX, 0x1027) }, /* ConnectX-10 */
+ { PCI_VDEVICE(MELLANOX, 0x2101) }, /* ConnectX-10 NVLink-C2C */
{ PCI_VDEVICE(MELLANOX, 0xa2d2) }, /* BlueField integrated ConnectX-5 network controller */
{ PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF}, /* BlueField integrated ConnectX-5 network controller VF */
{ PCI_VDEVICE(MELLANOX, 0xa2d6) }, /* BlueField-2 integrated ConnectX-6 Dx network controller */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index b635b423d972..1507e881d962 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -393,8 +393,8 @@ int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed);
int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
struct netlink_ext_ack *extack);
-int mlx5_fw_version_query(struct mlx5_core_dev *dev,
- u32 *running_ver, u32 *stored_ver);
+void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver,
+ u32 *stored_ver);
#ifdef CONFIG_MLX5_CORE_EN
int mlx5e_init(void);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
index 4af82675ffe1..bf6f631cf2ce 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -193,7 +193,9 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs)
err = pci_enable_sriov(pdev, num_vfs);
if (err) {
mlx5_core_warn(dev, "pci_enable_sriov failed : %d\n", err);
+ devl_lock(devlink);
mlx5_device_disable_sriov(dev, num_vfs, true, true);
+ devl_unlock(devlink);
}
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c
index 1b08bbb7ad99..0ed81353f2e3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c
@@ -1051,8 +1051,8 @@ static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn)
struct mlx5dr_table *tbl;
int ret;
- mutex_lock(&dmn->dump_info.dbg_mutex);
mlx5dr_domain_lock(dmn);
+ mutex_lock(&dmn->dump_info.dbg_mutex);
ret = dr_dump_domain(file, dmn);
if (ret < 0)
@@ -1065,8 +1065,8 @@ static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn)
}
unlock_mutex:
- mlx5dr_domain_unlock(dmn);
mutex_unlock(&dmn->dump_info.dbg_mutex);
+ mlx5dr_domain_unlock(dmn);
return ret;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
index 08270db2dee8..3c4563c8f403 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
@@ -197,7 +197,7 @@ static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v)
return 0;
}
- for (i = 0; i <= ring->size_mask; i++) {
+ for (i = 0; i < (ring->size_mask + 1) * FBNIC_BD_FRAG_COUNT; i++) {
u64 bd = le64_to_cpu(ring->desc[i]);
seq_printf(s, "%04x %#04llx %#014llx\n", i,
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
index 9fb91d4f3971..9cd85a0d0c3a 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
@@ -927,7 +927,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq)
/* Force DMA writes to flush before writing to tail */
dma_wmb();
- writel(i, bdq->doorbell);
+ writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell);
}
}
@@ -2564,7 +2564,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
hpq->tail = 0;
hpq->head = 0;
- log_size = fls(hpq->size_mask);
+ log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
/* Store descriptor ring address and size */
fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma));
@@ -2576,7 +2576,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
if (!ppq->size_mask)
goto write_ctl;
- log_size = fls(ppq->size_mask);
+ log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT);
/* Add enabling of PPQ to BDQ control */
bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
index 980965274079..e03c9d2c38dc 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
@@ -38,7 +38,7 @@ struct fbnic_net;
#define FBNIC_MAX_XDPQS 128u
/* These apply to TWQs, TCQ, RCQ */
-#define FBNIC_QUEUE_SIZE_MIN 16u
+#define FBNIC_QUEUE_SIZE_MIN 64u
#define FBNIC_QUEUE_SIZE_MAX SZ_64K
#define FBNIC_TXQ_SIZE_DEFAULT 1024
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index a3845edf0e48..f0b5dd752f08 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -3053,6 +3053,11 @@ static void lan743x_phylink_mac_link_up(struct phylink_config *config,
else if (speed == SPEED_100)
mac_cr |= MAC_CR_CFG_L_;
+ if (duplex == DUPLEX_FULL)
+ mac_cr |= MAC_CR_DPX_;
+ else
+ mac_cr &= ~MAC_CR_DPX_;
+
lan743x_csr_write(adapter, MAC_CR, mac_cr);
lan743x_ptp_update_latency(adapter, speed);
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
index 7b6369e43451..f8ce735a7fc0 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
@@ -91,6 +91,8 @@ static int lan966x_fdma_rx_alloc_page_pool(struct lan966x_rx *rx)
pp_params.dma_dir = DMA_BIDIRECTIONAL;
rx->page_pool = page_pool_create(&pp_params);
+ if (unlikely(IS_ERR(rx->page_pool)))
+ return PTR_ERR(rx->page_pool);
for (int i = 0; i < lan966x->num_phys_ports; ++i) {
struct lan966x_port *port;
@@ -117,8 +119,10 @@ static int lan966x_fdma_rx_alloc(struct lan966x_rx *rx)
return PTR_ERR(rx->page_pool);
err = fdma_alloc_coherent(lan966x->dev, fdma);
- if (err)
+ if (err) {
+ page_pool_destroy(rx->page_pool);
return err;
+ }
fdma_dcbs_init(fdma, FDMA_DCB_INFO_DATAL(fdma->db_size),
FDMA_DCB_STATUS_INTR);
@@ -808,9 +812,15 @@ static int lan966x_qsys_sw_status(struct lan966x *lan966x)
static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
{
+ struct page *(*old_pages)[FDMA_RX_DCB_MAX_DBS];
struct page_pool *page_pool;
struct fdma fdma_rx_old;
- int err;
+ int err, i, j;
+
+ old_pages = kmemdup(lan966x->rx.page, sizeof(lan966x->rx.page),
+ GFP_KERNEL);
+ if (!old_pages)
+ return -ENOMEM;
/* Store these for later to free them */
memcpy(&fdma_rx_old, &lan966x->rx.fdma, sizeof(struct fdma));
@@ -821,7 +831,6 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
lan966x_fdma_stop_netdev(lan966x);
lan966x_fdma_rx_disable(&lan966x->rx);
- lan966x_fdma_rx_free_pages(&lan966x->rx);
lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
lan966x->rx.max_mtu = new_mtu;
err = lan966x_fdma_rx_alloc(&lan966x->rx);
@@ -829,6 +838,11 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
goto restore;
lan966x_fdma_rx_start(&lan966x->rx);
+ for (i = 0; i < fdma_rx_old.n_dcbs; ++i)
+ for (j = 0; j < fdma_rx_old.n_dbs; ++j)
+ page_pool_put_full_page(page_pool,
+ old_pages[i][j], false);
+
fdma_free_coherent(lan966x->dev, &fdma_rx_old);
page_pool_destroy(page_pool);
@@ -836,12 +850,17 @@ static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu)
lan966x_fdma_wakeup_netdev(lan966x);
napi_enable(&lan966x->napi);
- return err;
+ kfree(old_pages);
+ return 0;
restore:
lan966x->rx.page_pool = page_pool;
memcpy(&lan966x->rx.fdma, &fdma_rx_old, sizeof(struct fdma));
lan966x_fdma_rx_start(&lan966x->rx);
+ lan966x_fdma_wakeup_netdev(lan966x);
+ napi_enable(&lan966x->napi);
+
+ kfree(old_pages);
return err;
}
@@ -955,6 +974,7 @@ int lan966x_fdma_init(struct lan966x *lan966x)
err = lan966x_fdma_tx_alloc(&lan966x->tx);
if (err) {
fdma_free_coherent(lan966x->dev, &lan966x->rx.fdma);
+ page_pool_destroy(lan966x->rx.page_pool);
return err;
}
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index f5deed37567b..786186c9a115 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -1934,6 +1934,7 @@ remove_irq:
mana_gd_remove_irqs(pdev);
free_workqueue:
destroy_workqueue(gc->service_wq);
+ gc->service_wq = NULL;
dev_err(&pdev->dev, "%s failed (error %d)\n", __func__, err);
return err;
}
@@ -1946,7 +1947,10 @@ static void mana_gd_cleanup(struct pci_dev *pdev)
mana_gd_remove_irqs(pdev);
- destroy_workqueue(gc->service_wq);
+ if (gc->service_wq) {
+ destroy_workqueue(gc->service_wq);
+ gc->service_wq = NULL;
+ }
dev_dbg(&pdev->dev, "mana gdma cleanup successful\n");
}
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index ba3467f1e2ea..48a9acea4ab6 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -814,9 +814,6 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
gc->max_num_cqs = 0;
}
- kfree(hwc->caller_ctx);
- hwc->caller_ctx = NULL;
-
if (hwc->txq)
mana_hwc_destroy_wq(hwc, hwc->txq);
@@ -826,6 +823,9 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
if (hwc->cq)
mana_hwc_destroy_cq(hwc->gdma_dev->gdma_context, hwc->cq);
+ kfree(hwc->caller_ctx);
+ hwc->caller_ctx = NULL;
+
mana_gd_free_res_map(&hwc->inflight_msg_res);
hwc->num_inflight_msg = 0;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 9919183ad39e..09a53c977545 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -766,6 +766,13 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
}
*frag_count = 1;
+
+ /* In the single-buffer path, napi_build_skb() must see the
+ * actual backing allocation size so skb->truesize reflects
+ * the full page (or higher-order page), not just the usable
+ * packet area.
+ */
+ *alloc_size = PAGE_SIZE << get_order(*alloc_size);
return;
}
@@ -1770,8 +1777,14 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
ndev = txq->ndev;
apc = netdev_priv(ndev);
+ /* Limit CQEs polled to 4 wraparounds of the CQ to ensure the
+ * doorbell can be rung in time for the hardware's requirement
+ * of at least one doorbell ring every 8 wraparounds.
+ */
comp_read = mana_gd_poll_cq(cq->gdma_cq, completions,
- CQE_POLLING_BUFFER);
+ min((cq->gdma_cq->queue_size /
+ COMP_ENTRY_SIZE) * 4,
+ CQE_POLLING_BUFFER));
if (comp_read < 1)
return;
@@ -2156,7 +2169,14 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
struct mana_rxq *rxq = cq->rxq;
int comp_read, i;
- comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER);
+ /* Limit CQEs polled to 4 wraparounds of the CQ to ensure the
+ * doorbell can be rung in time for the hardware's requirement
+ * of at least one doorbell ring every 8 wraparounds.
+ */
+ comp_read = mana_gd_poll_cq(cq->gdma_cq, comp,
+ min((cq->gdma_cq->queue_size /
+ COMP_ENTRY_SIZE) * 4,
+ CQE_POLLING_BUFFER));
WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER);
rxq->xdp_flush = false;
@@ -2201,11 +2221,11 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
cq->work_done_since_doorbell = 0;
napi_complete_done(&cq->napi, w);
- } else if (cq->work_done_since_doorbell >
- cq->gdma_cq->queue_size / COMP_ENTRY_SIZE * 4) {
+ } else if (cq->work_done_since_doorbell >=
+ (cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) {
/* MANA hardware requires at least one doorbell ring every 8
* wraparounds of CQ even if there is no need to arm the CQ.
- * This driver rings the doorbell as soon as we have exceeded
+ * This driver rings the doorbell as soon as it has processed
* 4 wraparounds.
*/
mana_gd_ring_cq(gdma_queue, 0);
@@ -3412,6 +3432,7 @@ static int add_adev(struct gdma_dev *gd, const char *name)
struct auxiliary_device *adev;
struct mana_adev *madev;
int ret;
+ int id;
madev = kzalloc_obj(*madev);
if (!madev)
@@ -3421,7 +3442,8 @@ static int add_adev(struct gdma_dev *gd, const char *name)
ret = mana_adev_idx_alloc();
if (ret < 0)
goto idx_fail;
- adev->id = ret;
+ id = ret;
+ adev->id = id;
adev->name = name;
adev->dev.parent = gd->gdma_context->dev;
@@ -3447,7 +3469,7 @@ add_fail:
auxiliary_device_uninit(adev);
init_fail:
- mana_adev_idx_free(adev->id);
+ mana_adev_idx_free(id);
idx_fail:
kfree(madev);
@@ -3757,7 +3779,9 @@ void mana_rdma_remove(struct gdma_dev *gd)
}
WRITE_ONCE(gd->rdma_teardown, true);
- flush_workqueue(gc->service_wq);
+
+ if (gc->service_wq)
+ flush_workqueue(gc->service_wq);
if (gd->adev)
remove_adev(gd);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 8d040e611d5a..637e635bbf03 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1719,13 +1719,18 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
if (ether_addr_equal(netdev->dev_addr, mac))
return 0;
- err = ionic_program_mac(lif, mac);
- if (err < 0)
- return err;
+ /* Only program macs for virtual functions to avoid losing the permanent
+ * Mac across warm reset/reboot.
+ */
+ if (lif->ionic->pdev->is_virtfn) {
+ err = ionic_program_mac(lif, mac);
+ if (err < 0)
+ return err;
- if (err > 0)
- netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
- __func__);
+ if (err > 0)
+ netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
+ __func__);
+ }
err = eth_prepare_mac_addr_change(netdev, addr);
if (err)
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
index 37efb1ea9fcd..847a5f928e41 100644
--- a/drivers/net/ethernet/qualcomm/qca_uart.c
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -100,7 +100,7 @@ qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
if (!qca->rx_skb) {
netdev_dbg(netdev, "recv: out of RX resources\n");
n_stats->rx_errors++;
- return i;
+ return i + 1;
}
}
}
diff --git a/drivers/net/ethernet/spacemit/k1_emac.c b/drivers/net/ethernet/spacemit/k1_emac.c
index 338a2637b1da..15d43e4a748b 100644
--- a/drivers/net/ethernet/spacemit/k1_emac.c
+++ b/drivers/net/ethernet/spacemit/k1_emac.c
@@ -565,7 +565,9 @@ static void emac_alloc_rx_desc_buffers(struct emac_priv *priv)
DMA_FROM_DEVICE);
if (dma_mapping_error(&priv->pdev->dev, rx_buf->dma_addr)) {
dev_err_ratelimited(&ndev->dev, "Mapping skb failed\n");
- goto err_free_skb;
+ dev_kfree_skb_any(skb);
+ rx_buf->skb = NULL;
+ break;
}
rx_desc_addr = &((struct emac_desc *)rx_ring->desc_addr)[i];
@@ -590,10 +592,6 @@ static void emac_alloc_rx_desc_buffers(struct emac_priv *priv)
rx_ring->head = i;
return;
-
-err_free_skb:
- dev_kfree_skb_any(skb);
- rx_buf->skb = NULL;
}
/* Returns number of packets received */
@@ -735,7 +733,7 @@ static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
struct emac_desc tx_desc, *tx_desc_addr;
struct device *dev = &priv->pdev->dev;
struct emac_tx_desc_buffer *tx_buf;
- u32 head, old_head, frag_num, f;
+ u32 head, old_head, frag_num, f, i;
bool buf_idx;
frag_num = skb_shinfo(skb)->nr_frags;
@@ -803,6 +801,15 @@ static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
err_free_skb:
dev_dstats_tx_dropped(priv->ndev);
+
+ i = old_head;
+ while (i != head) {
+ emac_free_tx_buf(priv, i);
+
+ if (++i == tx_ring->total_cnt)
+ i = 0;
+ }
+
dev_kfree_skb_any(skb);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 120a009c9992..37f9417c7c0e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -20,7 +20,7 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
unsigned int nopaged_len = skb_headlen(skb);
struct stmmac_priv *priv = tx_q->priv_data;
unsigned int entry = tx_q->cur_tx;
- unsigned int bmax, des2;
+ unsigned int bmax, buf_len, des2;
unsigned int i = 1, len;
struct dma_desc *desc;
@@ -31,17 +31,18 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
else
bmax = BUF_SIZE_2KiB;
- len = nopaged_len - bmax;
+ buf_len = min_t(unsigned int, nopaged_len, bmax);
+ len = nopaged_len - buf_len;
des2 = dma_map_single(priv->device, skb->data,
- bmax, DMA_TO_DEVICE);
+ buf_len, DMA_TO_DEVICE);
desc->des2 = cpu_to_le32(des2);
if (dma_mapping_error(priv->device, des2))
return -1;
tx_q->tx_skbuff_dma[entry].buf = des2;
- tx_q->tx_skbuff_dma[entry].len = bmax;
+ tx_q->tx_skbuff_dma[entry].len = buf_len;
/* do not close the descriptor and do not set own bit */
- stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
+ stmmac_prepare_tx_desc(priv, desc, 1, buf_len, csum, STMMAC_CHAIN_MODE,
0, false, skb->len);
while (len != 0) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
index 8b45b9cf7202..663d87ccfa0f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
@@ -6,6 +6,7 @@
*/
#include <linux/bits.h>
+#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -334,6 +335,13 @@ static int motorcomm_probe(struct pci_dev *pdev, const struct pci_device_id *id)
motorcomm_reset(priv);
+ /*
+ * After system reset, the eFuse controller needs time to load
+ * its internal data. Without this delay, eFuse reads return
+ * all zeros, causing MAC address detection to fail.
+ */
+ usleep_range(2000, 5000);
+
ret = motorcomm_efuse_read_mac(&pdev->dev, priv, res.mac);
if (ret == -ENOENT) {
dev_warn(&pdev->dev, "eFuse contains no valid MAC address\n");
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
index d765acbe3754..21a0a11fc011 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c
@@ -9,7 +9,7 @@
#include "stmmac_platform.h"
static const char *const mgbe_clks[] = {
- "rx-pcs", "tx", "tx-pcs", "mac-divider", "mac", "mgbe", "ptp-ref", "mac"
+ "rx-pcs", "tx", "tx-pcs", "mac-divider", "mac", "mgbe", "ptp_ref", "mac"
};
struct tegra_mgbe {
@@ -215,6 +215,7 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat;
struct stmmac_resources res;
+ bool use_legacy_ptp = false;
struct tegra_mgbe *mgbe;
int irq, err, i;
u32 value;
@@ -257,9 +258,23 @@ static int tegra_mgbe_probe(struct platform_device *pdev)
if (!mgbe->clks)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(mgbe_clks); i++)
+ /* Older device-trees use 'ptp-ref' rather than 'ptp_ref'.
+ * Fall back when the legacy name is present.
+ */
+ if (of_property_match_string(pdev->dev.of_node, "clock-names",
+ "ptp-ref") >= 0)
+ use_legacy_ptp = true;
+
+ for (i = 0; i < ARRAY_SIZE(mgbe_clks); i++) {
mgbe->clks[i].id = mgbe_clks[i];
+ if (use_legacy_ptp && !strcmp(mgbe_clks[i], "ptp_ref")) {
+ dev_warn(mgbe->dev,
+ "Device-tree update needed for PTP clock!\n");
+ mgbe->clks[i].id = "ptp-ref";
+ }
+ }
+
err = devm_clk_bulk_get(mgbe->dev, ARRAY_SIZE(mgbe_clks), mgbe->clks);
if (err < 0)
return err;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 51c96a738151..33667a26708c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -323,6 +323,7 @@ struct stmmac_priv {
void __iomem *ptpaddr;
void __iomem *estaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ unsigned int num_double_vlans;
int sfty_irq;
int sfty_ce_irq;
int sfty_ue_irq;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index edf0799b7236..13d3cac056be 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -156,6 +156,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
u32 rxmode, u32 chan);
+static void stmmac_vlan_restore(struct stmmac_priv *priv);
#ifdef CONFIG_DEBUG_FS
static const struct net_device_ops stmmac_netdev_ops;
@@ -853,6 +854,7 @@ static int stmmac_init_timestamping(struct stmmac_priv *priv)
netdev_info(priv->dev,
"IEEE 1588-2008 Advanced Timestamp supported\n");
+ memset(&priv->tstamp_config, 0, sizeof(priv->tstamp_config));
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
@@ -4106,6 +4108,8 @@ static int __stmmac_open(struct net_device *dev,
phylink_start(priv->phylink);
+ stmmac_vlan_restore(priv);
+
ret = stmmac_request_irq(dev);
if (ret)
goto irq_error;
@@ -6765,6 +6769,9 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
hash = 0;
}
+ if (!netif_running(priv->dev))
+ return 0;
+
return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double);
}
@@ -6774,6 +6781,7 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned int num_double_vlans;
bool is_double = false;
int ret;
@@ -6785,7 +6793,8 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
is_double = true;
set_bit(vid, priv->active_vlans);
- ret = stmmac_vlan_update(priv, is_double);
+ num_double_vlans = priv->num_double_vlans + is_double;
+ ret = stmmac_vlan_update(priv, num_double_vlans);
if (ret) {
clear_bit(vid, priv->active_vlans);
goto err_pm_put;
@@ -6793,9 +6802,15 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
if (priv->hw->num_vlan) {
ret = stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
- if (ret)
+ if (ret) {
+ clear_bit(vid, priv->active_vlans);
+ stmmac_vlan_update(priv, priv->num_double_vlans);
goto err_pm_put;
+ }
}
+
+ priv->num_double_vlans = num_double_vlans;
+
err_pm_put:
pm_runtime_put(priv->device);
@@ -6808,6 +6823,7 @@ err_pm_put:
static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned int num_double_vlans;
bool is_double = false;
int ret;
@@ -6819,14 +6835,23 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
is_double = true;
clear_bit(vid, priv->active_vlans);
+ num_double_vlans = priv->num_double_vlans - is_double;
+ ret = stmmac_vlan_update(priv, num_double_vlans);
+ if (ret) {
+ set_bit(vid, priv->active_vlans);
+ goto del_vlan_error;
+ }
if (priv->hw->num_vlan) {
ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
- if (ret)
+ if (ret) {
+ set_bit(vid, priv->active_vlans);
+ stmmac_vlan_update(priv, priv->num_double_vlans);
goto del_vlan_error;
+ }
}
- ret = stmmac_vlan_update(priv, is_double);
+ priv->num_double_vlans = num_double_vlans;
del_vlan_error:
pm_runtime_put(priv->device);
@@ -6834,6 +6859,17 @@ del_vlan_error:
return ret;
}
+static void stmmac_vlan_restore(struct stmmac_priv *priv)
+{
+ if (!(priv->dev->features & NETIF_F_VLAN_FEATURES))
+ return;
+
+ if (priv->hw->num_vlan)
+ stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw);
+
+ stmmac_vlan_update(priv, priv->num_double_vlans);
+}
+
static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -8258,10 +8294,10 @@ int stmmac_resume(struct device *dev)
stmmac_init_coalesce(priv);
phylink_rx_clk_stop_block(priv->phylink);
stmmac_set_rx_mode(ndev);
-
- stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw);
phylink_rx_clk_stop_unblock(priv->phylink);
+ stmmac_vlan_restore(priv);
+
stmmac_enable_all_queues(priv);
stmmac_enable_all_dma_irq(priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index b18404dd5a8b..e24efe3bfedb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -76,7 +76,9 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev,
}
hw->vlan_filter[0] = vid;
- vlan_write_single(dev, vid);
+
+ if (netif_running(dev))
+ vlan_write_single(dev, vid);
return 0;
}
@@ -97,12 +99,15 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev,
return -EPERM;
}
- ret = vlan_write_filter(dev, hw, index, val);
+ if (netif_running(dev)) {
+ ret = vlan_write_filter(dev, hw, index, val);
+ if (ret)
+ return ret;
+ }
- if (!ret)
- hw->vlan_filter[index] = val;
+ hw->vlan_filter[index] = val;
- return ret;
+ return 0;
}
static int vlan_del_hw_rx_fltr(struct net_device *dev,
@@ -115,7 +120,9 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev,
if (hw->num_vlan == 1) {
if ((hw->vlan_filter[0] & VLAN_TAG_VID) == vid) {
hw->vlan_filter[0] = 0;
- vlan_write_single(dev, 0);
+
+ if (netif_running(dev))
+ vlan_write_single(dev, 0);
}
return 0;
}
@@ -124,25 +131,23 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev,
for (i = 0; i < hw->num_vlan; i++) {
if ((hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) &&
((hw->vlan_filter[i] & VLAN_TAG_DATA_VID) == vid)) {
- ret = vlan_write_filter(dev, hw, i, 0);
- if (!ret)
- hw->vlan_filter[i] = 0;
- else
- return ret;
+ if (netif_running(dev)) {
+ ret = vlan_write_filter(dev, hw, i, 0);
+ if (ret)
+ return ret;
+ }
+
+ hw->vlan_filter[i] = 0;
}
}
- return ret;
+ return 0;
}
static void vlan_restore_hw_rx_fltr(struct net_device *dev,
struct mac_device_info *hw)
{
- void __iomem *ioaddr = hw->pcsr;
- u32 value;
- u32 hash;
- u32 val;
int i;
/* Single Rx VLAN Filter */
@@ -152,19 +157,8 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
}
/* Extended Rx VLAN Filter Enable */
- for (i = 0; i < hw->num_vlan; i++) {
- if (hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) {
- val = hw->vlan_filter[i];
- vlan_write_filter(dev, hw, i, val);
- }
- }
-
- hash = readl(ioaddr + VLAN_HASH_TABLE);
- if (hash & VLAN_VLHT) {
- value = readl(ioaddr + VLAN_TAG);
- value |= VLAN_VTHM;
- writel(value, ioaddr + VLAN_TAG);
- }
+ for (i = 0; i < hw->num_vlan; i++)
+ vlan_write_filter(dev, hw, i, hw->vlan_filter[i]);
}
static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
@@ -183,6 +177,10 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
value |= VLAN_EDVLP;
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
+ } else {
+ value &= ~VLAN_EDVLP;
+ value &= ~VLAN_ESVL;
+ value &= ~VLAN_DOVLTC;
}
writel(value, ioaddr + VLAN_TAG);
@@ -193,6 +191,10 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
value |= VLAN_EDVLP;
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
+ } else {
+ value &= ~VLAN_EDVLP;
+ value &= ~VLAN_ESVL;
+ value &= ~VLAN_DOVLTC;
}
writel(value | perfect_match, ioaddr + VLAN_TAG);
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 5924db6be3fe..265ce5479915 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -391,7 +391,7 @@ static void am65_cpsw_nuss_ndo_slave_set_rx_mode(struct net_device *ndev)
cpsw_ale_set_allmulti(common->ale,
ndev->flags & IFF_ALLMULTI, port->port_id);
- port_mask = ALE_PORT_HOST;
+ port_mask = BIT(port->port_id) | ALE_PORT_HOST;
/* Clear all mcast from ALE */
cpsw_ale_flush_multicast(common->ale, port_mask, -1);
@@ -1351,7 +1351,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
ndev_priv = netdev_priv(ndev);
am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark);
skb_put(skb, pkt_len);
- if (port->rx_ts_enabled)
+ if (port->rx_ts_filter)
am65_cpts_rx_timestamp(common->cpts, skb);
skb_mark_for_recycle(skb);
skb->protocol = eth_type_trans(skb, ndev);
@@ -1811,11 +1811,14 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
- port->rx_ts_enabled = false;
+ port->rx_ts_filter = HWTSTAMP_FILTER_NONE;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ port->rx_ts_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
@@ -1825,8 +1828,8 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- port->rx_ts_enabled = true;
- cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT | HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ port->rx_ts_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
@@ -1863,7 +1866,7 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN |
AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN;
- if (port->rx_ts_enabled)
+ if (port->rx_ts_filter)
ts_ctrl |= AM65_CPSW_TS_RX_ANX_ALL_EN |
AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN;
@@ -1888,8 +1891,7 @@ static int am65_cpsw_nuss_hwtstamp_get(struct net_device *ndev,
cfg->flags = 0;
cfg->tx_type = port->tx_ts_enabled ?
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
- cfg->rx_filter = port->rx_ts_enabled ? HWTSTAMP_FILTER_PTP_V2_EVENT |
- HWTSTAMP_FILTER_PTP_V1_L4_EVENT : HWTSTAMP_FILTER_NONE;
+ cfg->rx_filter = port->rx_ts_filter;
return 0;
}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
index 917c37e4e89b..7750448e4746 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
@@ -52,7 +52,7 @@ struct am65_cpsw_port {
bool disabled;
struct am65_cpsw_slave_data slave;
bool tx_ts_enabled;
- bool rx_ts_enabled;
+ enum hwtstamp_rx_filters rx_ts_filter;
struct am65_cpsw_qos qos;
struct devlink_port devlink_port;
struct bpf_prog *xdp_prog;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index bb969dd435b4..be7b69319221 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -450,14 +450,13 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
ale->port_mask_bits);
if ((mask & port_mask) == 0)
return; /* ports dont intersect, not interested */
- mask &= ~port_mask;
+ mask &= (~port_mask | ALE_PORT_HOST);
- /* free if only remaining port is host port */
- if (mask)
+ if (mask == 0x0 || mask == ALE_PORT_HOST)
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+ else
cpsw_ale_set_port_mask(ale_entry, mask,
ale->port_mask_bits);
- else
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
}
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index 0cf9dfe0fa36..a28a608f9bf4 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -902,6 +902,7 @@ static void emac_dispatch_skb_zc(struct prueth_emac *emac, struct xdp_buff *xdp,
skb_reserve(skb, headroom);
skb_put(skb, pkt_len);
+ skb_copy_to_linear_data(skb, xdp->data, pkt_len);
skb->dev = ndev;
/* RX HW timestamp */
@@ -912,7 +913,6 @@ static void emac_dispatch_skb_zc(struct prueth_emac *emac, struct xdp_buff *xdp,
skb->offload_fwd_mark = emac->offload_fwd_mark;
skb->protocol = eth_type_trans(skb, ndev);
- skb_mark_for_recycle(skb);
napi_gro_receive(&emac->napi_rx, skb);
ndev->stats.rx_bytes += pkt_len;
ndev->stats.rx_packets++;
@@ -962,7 +962,6 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id,
pkt_len -= 4;
cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
psdata = cppi5_hdesc_get_psdata(desc_rx);
- k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
count++;
xsk_buff_set_size(xdp, pkt_len);
xsk_buff_dma_sync_for_cpu(xdp);
@@ -988,6 +987,7 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id,
emac_dispatch_skb_zc(emac, xdp, psdata);
xsk_buff_free(xdp);
}
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
}
if (xdp_status & ICSSG_XDP_REDIR)
@@ -1057,7 +1057,6 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
/* firmware adds 4 CRC bytes, strip them */
pkt_len -= 4;
cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
- k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
/* if allocation fails we drop the packet but push the
* descriptor back to the ring with old page to prevent a stall
@@ -1075,6 +1074,11 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
xdp_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false);
*xdp_state = emac_run_xdp(emac, &xdp, &pkt_len);
+ if (*xdp_state == ICSSG_XDP_CONSUMED) {
+ page_pool_recycle_direct(pool, page);
+ goto requeue;
+ }
+
if (*xdp_state != ICSSG_XDP_PASS)
goto requeue;
headroom = xdp.data - xdp.data_hard_start;
@@ -1110,6 +1114,7 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state)
ndev->stats.rx_packets++;
requeue:
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
/* queue another RX DMA */
ret = prueth_dma_rx_push_mapped(emac, &emac->rx_chns, new_page,
PRUETH_MAX_PKT_SIZE);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 0939994c932f..42a881bee109 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -273,6 +273,14 @@ static int prueth_emac_common_start(struct prueth *prueth)
if (ret)
goto disable_class;
+ /* Reset link state to force reconfiguration in
+ * emac_adjust_link(). Without this, if the link was already up
+ * before restart, emac_adjust_link() won't detect any state
+ * change and will skip critical configuration like writing
+ * speed to firmware.
+ */
+ emac->link = 0;
+
mutex_lock(&emac->ndev->phydev->lock);
emac_adjust_link(emac->ndev);
mutex_unlock(&emac->ndev->phydev->lock);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 82433e9cb0e3..6b05f32b4a01 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -424,10 +424,10 @@ struct txgbe_nodes {
char i2c_name[32];
char sfp_name[32];
char phylink_name[32];
- struct property_entry gpio_props[1];
- struct property_entry i2c_props[3];
- struct property_entry sfp_props[8];
- struct property_entry phylink_props[2];
+ struct property_entry gpio_props[2];
+ struct property_entry i2c_props[4];
+ struct property_entry sfp_props[9];
+ struct property_entry phylink_props[3];
struct software_node_ref_args i2c_ref[1];
struct software_node_ref_args gpio0_ref[1];
struct software_node_ref_args gpio1_ref[1];
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 5ff742103beb..fcd3aaef27fc 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -105,7 +105,7 @@
#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */
#define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */
-#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */
+#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */
#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
@@ -130,7 +130,7 @@
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */
#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */
-#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */
+#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */
#define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */
#define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */
#define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index b06e4c37ff61..263c4b67fd5a 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -770,8 +770,8 @@ static int axienet_device_reset(struct net_device *ndev)
* @first_bd: Index of first descriptor to clean up
* @nr_bds: Max number of descriptors to clean up
* @force: Whether to clean descriptors even if not complete
- * @sizep: Pointer to a u32 filled with the total sum of all bytes
- * in all cleaned-up descriptors. Ignored if NULL.
+ * @sizep: Pointer to a u32 accumulating the total byte count of
+ * completed packets (using skb->len). Ignored if NULL.
* @budget: NAPI budget (use 0 when not called from NAPI poll)
*
* Would either be called after a successful transmit operation, or after
@@ -805,6 +805,8 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
DMA_TO_DEVICE);
if (cur_p->skb && (status & XAXIDMA_BD_STS_COMPLETE_MASK)) {
+ if (sizep)
+ *sizep += cur_p->skb->len;
napi_consume_skb(cur_p->skb, budget);
packets++;
}
@@ -818,9 +820,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd,
wmb();
cur_p->cntrl = 0;
cur_p->status = 0;
-
- if (sizep)
- *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
}
if (!force) {
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index e1e7f65553e7..b0faa0f1780d 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -403,15 +403,12 @@ static int ixp4xx_hwtstamp_set(struct net_device *netdev,
int ret;
int ch;
- if (!cpu_is_ixp46x())
- return -EOPNOTSUPP;
-
if (!netif_running(netdev))
return -EINVAL;
ret = ixp46x_ptp_find(&port->timesync_regs, &port->phc_index);
if (ret)
- return ret;
+ return -EOPNOTSUPP;
ch = PORT2CHANNEL(port);
regs = port->timesync_regs;
diff --git a/drivers/net/ethernet/xscale/ptp_ixp46x.c b/drivers/net/ethernet/xscale/ptp_ixp46x.c
index 94203eb46e6b..93c64db22a69 100644
--- a/drivers/net/ethernet/xscale/ptp_ixp46x.c
+++ b/drivers/net/ethernet/xscale/ptp_ixp46x.c
@@ -232,6 +232,9 @@ static struct ixp_clock ixp_clock;
int ixp46x_ptp_find(struct ixp46x_ts_regs *__iomem *regs, int *phc_index)
{
+ if (!cpu_is_ixp46x())
+ return -ENODEV;
+
*regs = ixp_clock.regs;
*phc_index = ptp_clock_index(ixp_clock.ptp_clock);
diff --git a/drivers/net/ipa/reg/gsi_reg-v5.0.c b/drivers/net/ipa/reg/gsi_reg-v5.0.c
index 36d1e65df71b..6c4a7fbe4de9 100644
--- a/drivers/net/ipa/reg/gsi_reg-v5.0.c
+++ b/drivers/net/ipa/reg/gsi_reg-v5.0.c
@@ -30,7 +30,7 @@ REG_STRIDE_FIELDS(CH_C_CNTXT_0, ch_c_cntxt_0,
static const u32 reg_ch_c_cntxt_1_fmask[] = {
[CH_R_LENGTH] = GENMASK(23, 0),
- [ERINDEX] = GENMASK(31, 24),
+ [CH_ERINDEX] = GENMASK(31, 24),
};
REG_STRIDE_FIELDS(CH_C_CNTXT_1, ch_c_cntxt_1,
@@ -156,9 +156,10 @@ REG_FIELDS(EV_CH_CMD, ev_ch_cmd, 0x00025010 + 0x12000 * GSI_EE_AP);
static const u32 reg_generic_cmd_fmask[] = {
[GENERIC_OPCODE] = GENMASK(4, 0),
- [GENERIC_CHID] = GENMASK(9, 5),
- [GENERIC_EE] = GENMASK(13, 10),
- /* Bits 14-31 reserved */
+ [GENERIC_CHID] = GENMASK(12, 5),
+ [GENERIC_EE] = GENMASK(16, 13),
+ /* Bits 17-23 reserved */
+ [GENERIC_PARAMS] = GENMASK(31, 24),
};
REG_FIELDS(GENERIC_CMD, generic_cmd, 0x00025018 + 0x12000 * GSI_EE_AP);
diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c
index edd13916831a..2d6bbddd1edd 100644
--- a/drivers/net/ipvlan/ipvtap.c
+++ b/drivers/net/ipvlan/ipvtap.c
@@ -30,10 +30,11 @@
static dev_t ipvtap_major;
static struct cdev ipvtap_cdev;
-static const void *ipvtap_net_namespace(const struct device *d)
+static const struct ns_common *ipvtap_net_namespace(const struct device *d)
{
const struct net_device *dev = to_net_dev(d->parent);
- return dev_net(dev);
+
+ return to_ns_common(dev_net(dev));
}
static struct class ipvtap_class = {
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index b391a0f740a3..cc975dfb7380 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -35,10 +35,11 @@ struct macvtap_dev {
*/
static dev_t macvtap_major;
-static const void *macvtap_net_namespace(const struct device *d)
+static const struct ns_common *macvtap_net_namespace(const struct device *d)
{
const struct net_device *dev = to_net_dev(d->parent);
- return dev_net(dev);
+
+ return to_ns_common(dev_net(dev));
}
static struct class macvtap_class = {
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
index de6bc1736734..15fe4d1163c1 100644
--- a/drivers/net/mctp/mctp-i2c.c
+++ b/drivers/net/mctp/mctp-i2c.c
@@ -343,6 +343,7 @@ static int mctp_i2c_recv(struct mctp_i2c_dev *midev)
} else {
status = NET_RX_DROP;
spin_unlock_irqrestore(&midev->lock, flags);
+ kfree_skb(skb);
}
if (status == NET_RX_SUCCESS) {
diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c
index ef860cfc629f..3b5dff144177 100644
--- a/drivers/net/mctp/mctp-usb.c
+++ b/drivers/net/mctp/mctp-usb.c
@@ -329,7 +329,7 @@ static int mctp_usb_probe(struct usb_interface *intf,
SET_NETDEV_DEV(netdev, &intf->dev);
dev = netdev_priv(netdev);
dev->netdev = netdev;
- dev->usbdev = usb_get_dev(interface_to_usbdev(intf));
+ dev->usbdev = interface_to_usbdev(intf);
dev->intf = intf;
usb_set_intfdata(intf, dev);
@@ -365,7 +365,6 @@ static void mctp_usb_disconnect(struct usb_interface *intf)
mctp_unregister_netdev(dev->netdev);
usb_free_urb(dev->tx_urb);
usb_free_urb(dev->rx_urb);
- usb_put_dev(dev->usbdev);
free_netdev(dev->netdev);
}
diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c
index 405a07075dd1..8d5fb014ca06 100644
--- a/drivers/net/mdio/mdio-realtek-rtl9300.c
+++ b/drivers/net/mdio/mdio-realtek-rtl9300.c
@@ -466,7 +466,6 @@ static int rtl9300_mdiobus_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtl9300_mdio_priv *priv;
- struct fwnode_handle *child;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -487,7 +486,7 @@ static int rtl9300_mdiobus_probe(struct platform_device *pdev)
if (err)
return err;
- device_for_each_child_node(dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
err = rtl9300_mdiobus_probe_one(dev, priv, child);
if (err)
return err;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 37415cad69f5..3c9acd6e49e8 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -617,7 +617,7 @@ static ssize_t sysdata_release_enabled_show(struct config_item *item,
bool release_enabled;
dynamic_netconsole_mutex_lock();
- release_enabled = !!(nt->sysdata_fields & SYSDATA_TASKNAME);
+ release_enabled = !!(nt->sysdata_fields & SYSDATA_RELEASE);
dynamic_netconsole_mutex_unlock();
return sysfs_emit(buf, "%d\n", release_enabled);
@@ -1679,7 +1679,8 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt,
if (release_len) {
release = init_utsname()->release;
- scnprintf(nt->buf, MAX_PRINT_CHUNK, "%s,%s", release, msg);
+ scnprintf(nt->buf, MAX_PRINT_CHUNK, "%s,%.*s", release,
+ msg_len, msg);
msg_len += release_len;
} else {
memcpy(nt->buf, msg, msg_len);
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 5ec028a00c62..3645ebde049a 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -109,8 +109,11 @@ static int nsim_forward_skb(struct net_device *tx_dev,
int ret;
ret = __dev_forward_skb(rx_dev, skb);
- if (ret)
+ if (ret) {
+ if (psp_ext)
+ __skb_ext_put(psp_ext);
return ret;
+ }
nsim_psp_handle_ext(skb, psp_ext);
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c
index ec2bbc28c196..5499c1572f3e 100644
--- a/drivers/net/ovpn/tcp.c
+++ b/drivers/net/ovpn/tcp.c
@@ -70,37 +70,56 @@ static void ovpn_tcp_to_userspace(struct ovpn_peer *peer, struct sock *sk,
peer->tcp.sk_cb.sk_data_ready(sk);
}
-static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
+static struct sk_buff *ovpn_tcp_skb_packet(const struct ovpn_peer *peer,
+ struct sk_buff *orig_skb,
+ const int pkt_len, const int pkt_off)
{
- struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp);
- struct strp_msg *msg = strp_msg(skb);
- size_t pkt_len = msg->full_len - 2;
- size_t off = msg->offset + 2;
- u8 opcode;
+ struct sk_buff *ovpn_skb;
+ int err;
- /* ensure skb->data points to the beginning of the openvpn packet */
- if (!pskb_pull(skb, off)) {
- net_warn_ratelimited("%s: packet too small for peer %u\n",
- netdev_name(peer->ovpn->dev), peer->id);
+ /* create a new skb with only the content of the current packet */
+ ovpn_skb = netdev_alloc_skb(peer->ovpn->dev, pkt_len);
+ if (unlikely(!ovpn_skb))
goto err;
- }
- /* strparser does not trim the skb for us, therefore we do it now */
- if (pskb_trim(skb, pkt_len) != 0) {
- net_warn_ratelimited("%s: trimming skb failed for peer %u\n",
+ skb_copy_header(ovpn_skb, orig_skb);
+ err = skb_copy_bits(orig_skb, pkt_off, skb_put(ovpn_skb, pkt_len),
+ pkt_len);
+ if (unlikely(err)) {
+ net_warn_ratelimited("%s: skb_copy_bits failed for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id);
+ kfree_skb(ovpn_skb);
goto err;
}
- /* we need the first 4 bytes of data to be accessible
+ consume_skb(orig_skb);
+ return ovpn_skb;
+err:
+ kfree_skb(orig_skb);
+ return NULL;
+}
+
+static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
+{
+ struct ovpn_peer *peer = container_of(strp, struct ovpn_peer, tcp.strp);
+ struct strp_msg *msg = strp_msg(skb);
+ int pkt_len = msg->full_len - 2;
+ u8 opcode;
+
+ /* we need at least 4 bytes of data in the packet
* to extract the opcode and the key ID later on
*/
- if (!pskb_may_pull(skb, OVPN_OPCODE_SIZE)) {
+ if (unlikely(pkt_len < OVPN_OPCODE_SIZE)) {
net_warn_ratelimited("%s: packet too small to fetch opcode for peer %u\n",
netdev_name(peer->ovpn->dev), peer->id);
goto err;
}
+ /* extract the packet into a new skb */
+ skb = ovpn_tcp_skb_packet(peer, skb, pkt_len, msg->offset + 2);
+ if (unlikely(!skb))
+ goto err;
+
/* DATA_V2 packets are handled in kernel, the rest goes to user space */
opcode = ovpn_opcode_from_skb(skb, 0);
if (unlikely(opcode != OVPN_DATA_V2)) {
@@ -113,7 +132,7 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
/* The packet size header must be there when sending the packet
* to userspace, therefore we put it back
*/
- skb_push(skb, 2);
+ *(__be16 *)__skb_push(skb, sizeof(u16)) = htons(pkt_len);
ovpn_tcp_to_userspace(peer, strp->sk, skb);
return;
}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 02fc0133428d..3bd415710bf3 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1866,8 +1866,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
goto error;
phy_resume(phydev);
- if (!phydev->is_on_sfp_module)
- phy_led_triggers_register(phydev);
/**
* If the external phy used by current mac interface is managed by
@@ -1982,9 +1980,6 @@ void phy_detach(struct phy_device *phydev)
phydev->phy_link_change = NULL;
phydev->phylink = NULL;
- if (!phydev->is_on_sfp_module)
- phy_led_triggers_unregister(phydev);
-
if (phydev->mdio.dev.driver)
module_put(phydev->mdio.dev.driver->owner);
@@ -3778,16 +3773,27 @@ static int phy_probe(struct device *dev)
/* Set the state to READY by default */
phydev->state = PHY_READY;
+ /* Register the PHY LED triggers */
+ if (!phydev->is_on_sfp_module)
+ phy_led_triggers_register(phydev);
+
/* Get the LEDs from the device tree, and instantiate standard
* LEDs for them.
*/
- if (IS_ENABLED(CONFIG_PHYLIB_LEDS) && !phy_driver_is_genphy(phydev))
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS) && !phy_driver_is_genphy(phydev)) {
err = of_phy_leds(phydev);
+ if (err)
+ goto out;
+ }
+
+ return 0;
out:
+ if (!phydev->is_on_sfp_module)
+ phy_led_triggers_unregister(phydev);
+
/* Re-assert the reset signal on error */
- if (err)
- phy_device_reset(phydev, 1);
+ phy_device_reset(phydev, 1);
return err;
}
@@ -3801,6 +3807,9 @@ static int phy_remove(struct device *dev)
if (IS_ENABLED(CONFIG_PHYLIB_LEDS) && !phy_driver_is_genphy(phydev))
phy_leds_unregister(phydev);
+ if (!phydev->is_on_sfp_module)
+ phy_led_triggers_unregister(phydev);
+
phydev->state = PHY_DOWN;
phy_cleanup_ports(phydev);
diff --git a/drivers/net/phy/qcom/qca807x.c b/drivers/net/phy/qcom/qca807x.c
index d8f1ce5a7128..6004da5741af 100644
--- a/drivers/net/phy/qcom/qca807x.c
+++ b/drivers/net/phy/qcom/qca807x.c
@@ -375,7 +375,7 @@ static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset)
reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
- return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
+ return !!FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
}
static int qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index f4bf53da3d4f..6b7b8ae15d10 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -367,6 +367,12 @@ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
sfp->state_ignore_mask |= SFP_F_TX_FAULT;
}
+static void sfp_fixup_ignore_tx_fault_and_los(struct sfp *sfp)
+{
+ sfp_fixup_ignore_tx_fault(sfp);
+ sfp_fixup_ignore_los(sfp);
+}
+
static void sfp_fixup_ignore_hw(struct sfp *sfp, unsigned int mask)
{
sfp->state_hw_mask &= ~mask;
@@ -474,11 +480,16 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
{
/* Ubiquiti U-Fiber Instant module claims that support all transceiver
* types including 10G Ethernet which is not truth. So clear all claimed
- * modes and set only one mode which module supports: 1000baseX_Full.
+ * modes and set only one mode which module supports: 1000baseX_Full,
+ * along with the Autoneg and pause bits.
*/
linkmode_zero(caps->link_modes);
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
caps->link_modes);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, caps->link_modes);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, caps->link_modes);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, caps->link_modes);
+
phy_interface_zero(caps->interfaces);
__set_bit(PHY_INTERFACE_MODE_1000BASEX, caps->interfaces);
}
@@ -530,6 +541,22 @@ static const struct sfp_quirk sfp_quirks[] = {
// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
// their EEPROM
SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex,
+ sfp_fixup_ignore_tx_fault_and_los),
+
+ // Hisense LXT-010S-H is a GPON ONT SFP (sold as LEOX LXT-010S-H) that
+ // can operate at 2500base-X, but reports 1000BASE-LX / 1300MBd in its
+ // EEPROM
+ SFP_QUIRK("Hisense-Leox", "LXT-010S-H", sfp_quirk_2500basex,
+ sfp_fixup_ignore_tx_fault),
+
+ // Hisense ZNID-GPON-2311NA can operate at 2500base-X, but reports
+ // 1000BASE-LX / 1300MBd in its EEPROM
+ SFP_QUIRK("Hisense", "ZNID-GPON-2311NA", sfp_quirk_2500basex,
+ sfp_fixup_ignore_tx_fault),
+
+ // HSGQ HSGQ-XPON-Stick can operate at 2500base-X, but reports
+ // 1000BASE-LX / 1300MBd in its EEPROM
+ SFP_QUIRK("HSGQ", "HSGQ-XPON-Stick", sfp_quirk_2500basex,
sfp_fixup_ignore_tx_fault),
// Lantech 8330-262D-E and 8330-265D can operate at 2500base-X, but
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index 937dd6dc070b..120aeb539d9f 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -1290,7 +1290,7 @@ err_set_mtu:
static void __team_port_change_port_removed(struct team_port *port);
-static int team_port_del(struct team *team, struct net_device *port_dev)
+static int team_port_del(struct team *team, struct net_device *port_dev, bool unregister)
{
struct net_device *dev = team->dev;
struct team_port *port;
@@ -1328,7 +1328,13 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
__team_port_change_port_removed(port);
team_port_set_orig_dev_addr(port);
- dev_set_mtu(port_dev, port->orig.mtu);
+ if (unregister) {
+ netdev_lock_ops(port_dev);
+ __netif_set_mtu(port_dev, port->orig.mtu);
+ netdev_unlock_ops(port_dev);
+ } else {
+ dev_set_mtu(port_dev, port->orig.mtu);
+ }
kfree_rcu(port, rcu);
netdev_info(dev, "Port device %s removed\n", portname);
netdev_compute_master_upper_features(team->dev, true);
@@ -1632,7 +1638,7 @@ static void team_uninit(struct net_device *dev)
ASSERT_RTNL();
list_for_each_entry_safe(port, tmp, &team->port_list, list)
- team_port_del(team, port->dev);
+ team_port_del(team, port->dev, false);
__team_change_mode(team, NULL); /* cleanup */
__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
@@ -1931,7 +1937,16 @@ static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
ASSERT_RTNL();
- return team_port_del(team, port_dev);
+ return team_port_del(team, port_dev, false);
+}
+
+static int team_del_slave_on_unregister(struct net_device *dev, struct net_device *port_dev)
+{
+ struct team *team = netdev_priv(dev);
+
+ ASSERT_RTNL();
+
+ return team_port_del(team, port_dev, true);
}
static netdev_features_t team_fix_features(struct net_device *dev,
@@ -2043,6 +2058,68 @@ static const struct ethtool_ops team_ethtool_ops = {
* rt netlink interface
***********************/
+/* For tx path we need a linkup && enabled port and for parse any port
+ * suffices.
+ */
+static struct team_port *team_header_port_get_rcu(struct team *team,
+ bool txable)
+{
+ struct team_port *port;
+
+ list_for_each_entry_rcu(port, &team->port_list, list) {
+ if (!txable || team_port_txable(port))
+ return port;
+ }
+
+ return NULL;
+}
+
+static int team_header_create(struct sk_buff *skb, struct net_device *team_dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
+{
+ struct team *team = netdev_priv(team_dev);
+ const struct header_ops *port_ops;
+ struct team_port *port;
+ int ret = 0;
+
+ rcu_read_lock();
+ port = team_header_port_get_rcu(team, true);
+ if (port) {
+ port_ops = READ_ONCE(port->dev->header_ops);
+ if (port_ops && port_ops->create)
+ ret = port_ops->create(skb, port->dev,
+ type, daddr, saddr, len);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static int team_header_parse(const struct sk_buff *skb,
+ const struct net_device *team_dev,
+ unsigned char *haddr)
+{
+ struct team *team = netdev_priv(team_dev);
+ const struct header_ops *port_ops;
+ struct team_port *port;
+ int ret = 0;
+
+ rcu_read_lock();
+ port = team_header_port_get_rcu(team, false);
+ if (port) {
+ port_ops = READ_ONCE(port->dev->header_ops);
+ if (port_ops && port_ops->parse)
+ ret = port_ops->parse(skb, port->dev, haddr);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+static const struct header_ops team_header_ops = {
+ .create = team_header_create,
+ .parse = team_header_parse,
+};
+
static void team_setup_by_port(struct net_device *dev,
struct net_device *port_dev)
{
@@ -2051,7 +2128,8 @@ static void team_setup_by_port(struct net_device *dev,
if (port_dev->type == ARPHRD_ETHER)
dev->header_ops = team->header_ops_cache;
else
- dev->header_ops = port_dev->header_ops;
+ dev->header_ops = port_dev->header_ops ?
+ &team_header_ops : NULL;
dev->type = port_dev->type;
dev->hard_header_len = port_dev->hard_header_len;
dev->needed_headroom = port_dev->needed_headroom;
@@ -2924,7 +3002,7 @@ static int team_device_event(struct notifier_block *unused,
!!netif_oper_up(port->dev));
break;
case NETDEV_UNREGISTER:
- team_del_slave(port->team->dev, dev);
+ team_del_slave_on_unregister(port->team->dev, dev);
break;
case NETDEV_FEAT_CHANGE:
if (!port->team->notifier_ctx) {
@@ -2997,3 +3075,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
MODULE_DESCRIPTION("Ethernet team device driver");
MODULE_ALIAS_RTNL_LINK(DRV_NAME);
+MODULE_IMPORT_NS("NETDEV_INTERNAL");
diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h
index a5f93b6c4482..fa5cab9d3e55 100644
--- a/drivers/net/tun_vnet.h
+++ b/drivers/net/tun_vnet.h
@@ -244,7 +244,7 @@ tun_vnet_hdr_tnl_from_skb(unsigned int flags,
if (virtio_net_hdr_tnl_from_skb(skb, tnl_hdr, has_tnl_offload,
tun_vnet_is_little_endian(flags),
- vlan_hlen, true)) {
+ vlan_hlen, true, false)) {
struct virtio_net_hdr_v1 *hdr = &tnl_hdr->hash_hdr.hdr;
struct skb_shared_info *sinfo = skb_shinfo(skb);
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index cbffa9ae1bb6..dd53f413c38f 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -1395,14 +1395,14 @@ static int aqc111_suspend(struct usb_interface *intf, pm_message_t message)
aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC,
SFR_MEDIUM_STATUS_MODE, 2, &reg16);
- aqc111_write_cmd(dev, AQ_WOL_CFG, 0, 0,
- WOL_CFG_SIZE, &wol_cfg);
- aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
- &aqc111_data->phy_cfg);
+ aqc111_write_cmd_nopm(dev, AQ_WOL_CFG, 0, 0,
+ WOL_CFG_SIZE, &wol_cfg);
+ aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ &aqc111_data->phy_cfg);
} else {
aqc111_data->phy_cfg |= AQ_LOW_POWER;
- aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0,
- &aqc111_data->phy_cfg);
+ aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0,
+ &aqc111_data->phy_cfg);
/* Disable RX path */
aqc111_read16_cmd_nopm(dev, AQ_ACCESS_MAC,
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 7057c6c0cfc6..bb9929727eb9 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1656,6 +1656,7 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
struct usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp16 *ndp16;
int ret = -EINVAL;
+ size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
@@ -1675,8 +1676,8 @@ int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
sizeof(struct usb_cdc_ncm_dpe16));
ret--; /* we process NDP entries except for the last one */
- if ((sizeof(struct usb_cdc_ncm_ndp16) +
- ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) {
+ ndp_len = struct_size_t(struct usb_cdc_ncm_ndp16, dpe16, ret);
+ if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL;
}
@@ -1692,6 +1693,7 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
struct usbnet *dev = netdev_priv(skb_in->dev);
struct usb_cdc_ncm_ndp32 *ndp32;
int ret = -EINVAL;
+ size_t ndp_len;
if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "invalid NDP offset <%u>\n",
@@ -1711,8 +1713,8 @@ int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
sizeof(struct usb_cdc_ncm_dpe32));
ret--; /* we process NDP entries except for the last one */
- if ((sizeof(struct usb_cdc_ncm_ndp32) +
- ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
+ ndp_len = struct_size_t(struct usb_cdc_ncm_ndp32, dpe32, ret);
+ if (ndpoffset + ndp_len > skb_in->len) {
netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
ret = -EINVAL;
}
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 613fc6910f14..ee9c48f7f68f 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -132,11 +132,18 @@ kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status;
u8 ethernet_addr[ETH_ALEN];
+ static const u8 ep_addr[] = {
+ 1 | USB_DIR_IN,
+ 2 | USB_DIR_OUT,
+ 0};
/* Don't bind to AT command interface */
if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
return -EINVAL;
+ if (!usb_check_bulk_endpoints(intf, ep_addr))
+ return -ENODEV;
+
dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK);
dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK);
dev->status = NULL;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index c9efb7df892e..cb2472b59e10 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -765,7 +765,6 @@ static void kaweth_set_rx_mode(struct net_device *net)
netdev_dbg(net, "Setting Rx mode to %d\n", packet_filter_bitmap);
- netif_stop_queue(net);
if (net->flags & IFF_PROMISC) {
packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
@@ -775,7 +774,6 @@ static void kaweth_set_rx_mode(struct net_device *net)
}
kaweth->packet_filter_bitmap = packet_filter_bitmap;
- netif_wake_queue(net);
}
/****************************************************************
@@ -885,6 +883,13 @@ static int kaweth_probe(
const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int result = 0;
int rv = -EIO;
+ static const u8 bulk_ep_addr[] = {
+ 1 | USB_DIR_IN,
+ 2 | USB_DIR_OUT,
+ 0};
+ static const u8 int_ep_addr[] = {
+ 3 | USB_DIR_IN,
+ 0};
dev_dbg(dev,
"Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n",
@@ -898,6 +903,12 @@ static int kaweth_probe(
(int)udev->descriptor.bLength,
(int)udev->descriptor.bDescriptorType);
+ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+ !usb_check_int_endpoints(intf, int_ep_addr)) {
+ dev_err(dev, "couldn't find required endpoints\n");
+ return -ENODEV;
+ }
+
netdev = alloc_etherdev(sizeof(*kaweth));
if (!netdev)
return -ENOMEM;
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 8da8e04c3109..19cdf69fa589 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2094,8 +2094,6 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
dev->mdiobus->phy_mask = ~(1 << 1);
break;
case ID_REV_CHIP_ID_7801_:
- /* scan thru PHYAD[2..0] */
- dev->mdiobus->phy_mask = ~(0xFF);
break;
}
@@ -3121,6 +3119,10 @@ static int lan78xx_init_ltm(struct lan78xx_net *dev)
int ret;
u32 buf;
+ /* LAN7850 is USB 2.0 and does not support LTM */
+ if (dev->chipid == ID_REV_CHIP_ID_7850_)
+ return 0;
+
ret = lan78xx_read_reg(dev, USB_CFG1, &buf);
if (ret < 0)
goto init_ltm_failed;
@@ -3831,6 +3833,7 @@ static void lan78xx_rx_csum_offload(struct lan78xx_net *dev,
*/
if (!(dev->net->features & NETIF_F_RXCSUM) ||
unlikely(rx_cmd_a & RX_CMD_A_ICSM_) ||
+ unlikely(rx_cmd_a & RX_CMD_A_CSE_MASK_) ||
((rx_cmd_a & RX_CMD_A_FVTG_) &&
!(dev->net->features & NETIF_F_HW_VLAN_CTAG_RX))) {
skb->ip_summed = CHECKSUM_NONE;
@@ -3903,7 +3906,8 @@ static int lan78xx_rx(struct lan78xx_net *dev, struct sk_buff *skb,
return 0;
}
- if (unlikely(rx_cmd_a & RX_CMD_A_RED_)) {
+ if (unlikely(rx_cmd_a & RX_CMD_A_RED_) &&
+ (rx_cmd_a & RX_CMD_A_RX_HARD_ERRS_MASK_)) {
netif_dbg(dev, rx_err, dev->net,
"Error rx_cmd_a=0x%08x", rx_cmd_a);
} else {
@@ -4178,7 +4182,7 @@ static struct skb_data *lan78xx_tx_buf_fill(struct lan78xx_net *dev,
}
tx_data += len;
- entry->length += len;
+ entry->length += max_t(unsigned int, len, ETH_ZLEN);
entry->num_of_packet += skb_shinfo(skb)->gso_segs ?: 1;
dev_kfree_skb_any(skb);
@@ -4548,8 +4552,6 @@ static void lan78xx_disconnect(struct usb_interface *intf)
phylink_disconnect_phy(dev->phylink);
rtnl_unlock();
- netif_napi_del(&dev->napi);
-
unregister_netdev(net);
timer_shutdown_sync(&dev->stat_monitor);
diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h
index 968e5e5faee0..17a934acff3d 100644
--- a/drivers/net/usb/lan78xx.h
+++ b/drivers/net/usb/lan78xx.h
@@ -74,6 +74,9 @@
#define RX_CMD_A_ICSM_ (0x00004000)
#define RX_CMD_A_LEN_MASK_ (0x00003FFF)
+#define RX_CMD_A_RX_HARD_ERRS_MASK_ \
+ (RX_CMD_A_RX_ERRS_MASK_ & ~RX_CMD_A_CSE_MASK_)
+
/* Rx Command B */
#define RX_CMD_B_CSUM_SHIFT_ (16)
#define RX_CMD_B_CSUM_MASK_ (0xFFFF0000)
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 4f539b5d509a..db85f40734d7 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -28,6 +28,17 @@ static const char driver_name[] = "pegasus";
BMSR_100FULL | BMSR_ANEGCAPABLE)
#define CARRIER_CHECK_DELAY (2 * HZ)
+/*
+ * USB endpoints.
+ */
+
+enum pegasus_usb_ep {
+ PEGASUS_USB_EP_CONTROL = 0,
+ PEGASUS_USB_EP_BULK_IN = 1,
+ PEGASUS_USB_EP_BULK_OUT = 2,
+ PEGASUS_USB_EP_INT_IN = 3,
+};
+
static bool loopback;
static bool mii_mode;
static char *devid;
@@ -542,7 +553,7 @@ static void read_bulk_callback(struct urb *urb)
goto tl_sched;
goon:
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
- usb_rcvbulkpipe(pegasus->usb, 1),
+ usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
pegasus->rx_skb->data, PEGASUS_MTU,
read_bulk_callback, pegasus);
rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
@@ -582,7 +593,7 @@ static void rx_fixup(struct tasklet_struct *t)
return;
}
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
- usb_rcvbulkpipe(pegasus->usb, 1),
+ usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
pegasus->rx_skb->data, PEGASUS_MTU,
read_bulk_callback, pegasus);
try_again:
@@ -710,7 +721,7 @@ static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb,
((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len);
usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb,
- usb_sndbulkpipe(pegasus->usb, 2),
+ usb_sndbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_OUT),
pegasus->tx_buff, count,
write_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
@@ -801,8 +812,19 @@ static void unlink_all_urbs(pegasus_t *pegasus)
static int alloc_urbs(pegasus_t *pegasus)
{
+ static const u8 bulk_ep_addr[] = {
+ 1 | USB_DIR_IN,
+ 2 | USB_DIR_OUT,
+ 0};
+ static const u8 int_ep_addr[] = {
+ 3 | USB_DIR_IN,
+ 0};
int res = -ENOMEM;
+ if (!usb_check_bulk_endpoints(pegasus->intf, bulk_ep_addr) ||
+ !usb_check_int_endpoints(pegasus->intf, int_ep_addr))
+ return -ENODEV;
+
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
return res;
@@ -837,7 +859,7 @@ static int pegasus_open(struct net_device *net)
set_registers(pegasus, EthID, 6, net->dev_addr);
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
- usb_rcvbulkpipe(pegasus->usb, 1),
+ usb_rcvbulkpipe(pegasus->usb, PEGASUS_USB_EP_BULK_IN),
pegasus->rx_skb->data, PEGASUS_MTU,
read_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
@@ -848,7 +870,7 @@ static int pegasus_open(struct net_device *net)
}
usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
- usb_rcvintpipe(pegasus->usb, 3),
+ usb_rcvintpipe(pegasus->usb, PEGASUS_USB_EP_INT_IN),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
@@ -1133,16 +1155,31 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus_t *pegasus;
int dev_index = id - pegasus_ids;
int res = -ENOMEM;
+ static const u8 bulk_ep_addr[] = {
+ PEGASUS_USB_EP_BULK_IN | USB_DIR_IN,
+ PEGASUS_USB_EP_BULK_OUT | USB_DIR_OUT,
+ 0};
+ static const u8 int_ep_addr[] = {
+ PEGASUS_USB_EP_INT_IN | USB_DIR_IN,
+ 0};
if (pegasus_blacklisted(dev))
return -ENODEV;
+ /* Verify that all required endpoints are present */
+ if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+ !usb_check_int_endpoints(intf, int_ep_addr)) {
+ dev_err(&intf->dev, "Missing or invalid endpoints\n");
+ return -ENODEV;
+ }
+
net = alloc_etherdev(sizeof(struct pegasus));
if (!net)
goto out;
pegasus = netdev_priv(net);
pegasus->dev_index = dev_index;
+ pegasus->intf = intf;
res = alloc_urbs(pegasus);
if (res < 0) {
@@ -1154,7 +1191,6 @@ static int pegasus_probe(struct usb_interface *intf,
INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier);
- pegasus->intf = intf;
pegasus->usb = dev;
pegasus->net = net;
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3a4985b582cb..05acac10cd2b 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -928,7 +928,7 @@ err:
static const struct driver_info qmi_wwan_info = {
.description = "WWAN/QMI device",
- .flags = FLAG_WWAN | FLAG_SEND_ZLP,
+ .flags = FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
@@ -937,7 +937,7 @@ static const struct driver_info qmi_wwan_info = {
static const struct driver_info qmi_wwan_info_quirk_dtr = {
.description = "WWAN/QMI device",
- .flags = FLAG_WWAN | FLAG_SEND_ZLP,
+ .flags = FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 4af85728ac4f..0c83bbbea2e7 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -10054,6 +10054,7 @@ static const struct usb_device_id rtl8152_table[] = {
{ USB_DEVICE(VENDOR_ID_DLINK, 0xb301) },
{ USB_DEVICE(VENDOR_ID_DELL, 0xb097) },
{ USB_DEVICE(VENDOR_ID_ASUS, 0x1976) },
+ { USB_DEVICE(VENDOR_ID_TRENDNET, 0xe02b) },
{}
};
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ed86ba87ca4e..b72ba0803392 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1829,11 +1829,12 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod)
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
net->flags |= IFF_NOARP;
- if (net->max_mtu > (dev->hard_mtu - net->hard_header_len))
+ if ((dev->driver_info->flags & FLAG_NOMAXMTU) == 0 &&
+ net->max_mtu > (dev->hard_mtu - net->hard_header_len))
net->max_mtu = dev->hard_mtu - net->hard_header_len;
- if (net->mtu > net->max_mtu)
- net->mtu = net->max_mtu;
+ if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+ net->mtu = dev->hard_mtu - net->hard_header_len;
} else if (!info->in || !info->out)
status = usbnet_get_endpoints(dev, udev);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 72d6a9c6a5a2..c0b9bc5574e2 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -381,8 +381,6 @@ struct receive_queue {
struct xdp_buff **xsk_buffs;
};
-#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
-
/* Control VQ buffers: protected by the rtnl lock */
struct control_buf {
struct virtio_net_ctrl_hdr hdr;
@@ -486,7 +484,7 @@ struct virtnet_info {
/* Must be last as it ends in a flexible-array member. */
TRAILING_OVERLAP(struct virtio_net_rss_config_trailer, rss_trailer, hash_key_data,
- u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+ u8 rss_hash_key_data[NETDEV_RSS_KEY_LEN];
);
};
static_assert(offsetof(struct virtnet_info, rss_trailer.hash_key_data) ==
@@ -3267,8 +3265,12 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
struct virtio_net_hdr_v1_hash_tunnel *hdr;
int num_sg;
unsigned hdr_len = vi->hdr_len;
+ bool feature_hdrlen;
bool can_push;
+ feature_hdrlen = virtio_has_feature(vi->vdev,
+ VIRTIO_NET_F_GUEST_HDRLEN);
+
pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
/* Make sure it's safe to cast between formats */
@@ -3288,7 +3290,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl,
virtio_is_little_endian(vi->vdev), 0,
- false))
+ false, feature_hdrlen))
return -EPROTO;
if (vi->mergeable_rx_bufs)
@@ -3351,6 +3353,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Don't wait up for transmitted skbs to be freed. */
if (!use_napi) {
skb_orphan(skb);
+ skb_dst_drop(skb);
nf_reset_ct(skb);
}
@@ -6703,6 +6706,7 @@ static int virtnet_probe(struct virtio_device *vdev)
struct virtnet_info *vi;
u16 max_queue_pairs;
int mtu = 0;
+ u16 key_sz;
/* Find if host supports multiqueue/rss virtio_net device */
max_queue_pairs = 1;
@@ -6837,14 +6841,13 @@ static int virtnet_probe(struct virtio_device *vdev)
}
if (vi->has_rss || vi->has_rss_hash_report) {
- vi->rss_key_size =
- virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
- if (vi->rss_key_size > VIRTIO_NET_RSS_MAX_KEY_SIZE) {
- dev_err(&vdev->dev, "rss_max_key_size=%u exceeds the limit %u.\n",
- vi->rss_key_size, VIRTIO_NET_RSS_MAX_KEY_SIZE);
- err = -EINVAL;
- goto free;
- }
+ key_sz = virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
+
+ vi->rss_key_size = min_t(u16, key_sz, NETDEV_RSS_KEY_LEN);
+ if (key_sz > vi->rss_key_size)
+ dev_warn(&vdev->dev,
+ "rss_max_key_size=%u exceeds driver limit %u, clamping\n",
+ key_sz, vi->rss_key_size);
vi->rss_hash_types_supported =
virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 05558b6afecd..a94ac82a6136 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1965,12 +1965,14 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
ns_olen = request->len - skb_network_offset(request) -
sizeof(struct ipv6hdr) - sizeof(*ns);
for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
- if (!ns->opt[i + 1]) {
+ if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) {
kfree_skb(reply);
return NULL;
}
if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
- daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+ if ((ns->opt[i + 1] << 3) >=
+ sizeof(struct nd_opt_hdr) + ETH_ALEN)
+ daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
break;
}
}
@@ -2130,6 +2132,11 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct ipv6hdr *pip6;
+ /* check if nd_tbl is not initiliazed due to
+ * ipv6.disable=1 set during boot
+ */
+ if (!ipv6_stub->nd_tbl)
+ return false;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
return false;
pip6 = ipv6_hdr(skb);
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 957e0b272d54..73f393900710 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2550,6 +2550,8 @@ fst_remove_one(struct pci_dev *pdev)
fst_disable_intr(card);
free_irq(card->irq, card);
+ tasklet_kill(&fst_tx_task);
+ tasklet_kill(&fst_int_task);
iounmap(card->ctlmem);
iounmap(card->mem);
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index f357a7ac70ac..9861c99ea56c 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -446,33 +446,36 @@ static void lapbeth_free_device(struct lapbethdev *lapbeth)
static int lapbeth_device_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct lapbethdev *lapbeth;
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct lapbethdev *lapbeth;
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
- if (!dev_is_ethdev(dev) && !lapbeth_get_x25_dev(dev))
+ lapbeth = lapbeth_get_x25_dev(dev);
+ if (!dev_is_ethdev(dev) && !lapbeth)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UP:
/* New ethernet device -> new LAPB interface */
- if (!lapbeth_get_x25_dev(dev))
+ if (!lapbeth)
lapbeth_new_device(dev);
break;
case NETDEV_GOING_DOWN:
/* ethernet device closes -> close LAPB interface */
- lapbeth = lapbeth_get_x25_dev(dev);
if (lapbeth)
dev_close(lapbeth->axdev);
break;
case NETDEV_UNREGISTER:
/* ethernet device disappears -> remove LAPB interface */
- lapbeth = lapbeth_get_x25_dev(dev);
if (lapbeth)
lapbeth_free_device(lapbeth);
break;
+ case NETDEV_PRE_TYPE_CHANGE:
+ /* Our underlying device type must not change. */
+ if (lapbeth)
+ return NOTIFY_BAD;
}
return NOTIFY_DONE;
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 49d959b2e148..85defe11750d 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/ieee80211.h>
@@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
struct ath11k_base *ab = ar->ab;
struct ath11k_peer *peer;
struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
+ struct dp_rx_tid *rx_tid;
int vdev_id = arsta->arvif->vdev_id;
- dma_addr_t paddr;
- bool active;
int ret;
spin_lock_bh(&ab->base_lock);
@@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
return -ENOENT;
}
- paddr = peer->rx_tid[params->tid].paddr;
- active = peer->rx_tid[params->tid].active;
+ rx_tid = &peer->rx_tid[params->tid];
- if (!active) {
+ if (!rx_tid->active) {
spin_unlock_bh(&ab->base_lock);
return 0;
}
- ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false);
+ ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false);
spin_unlock_bh(&ab->base_lock);
if (ret) {
ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n",
@@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
}
ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
- params->sta->addr, paddr,
+ params->sta->addr,
+ rx_tid->paddr,
params->tid, 1, 1);
if (ret)
ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 5a82ede65dd3..244d5230a5bd 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -735,6 +735,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_dp_link_peer *peer;
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta);
+ struct ath12k_dp_rx_tid *rx_tid;
struct ath12k_link_sta *arsta;
int vdev_id;
bool active;
@@ -770,7 +771,8 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
return 0;
}
- ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, peer->dp_peer->rx_tid,
+ rx_tid = &peer->dp_peer->rx_tid[params->tid];
+ ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, rx_tid,
1, 0, false);
spin_unlock_bh(&dp->dp_lock);
if (ret) {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index c6b88909b6b7..b253d1e3f405 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5430,7 +5430,7 @@ int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw,
ar->last_tx_power_update))
goto send_tx_power;
- params.pdev_id = ar->pdev->pdev_id;
+ params.pdev_id = ath12k_mac_get_target_pdev_id(ar);
params.vdev_id = arvif->vdev_id;
params.stats_id = WMI_REQUEST_PDEV_STAT;
ret = ath12k_mac_get_fw_stats(ar, &params);
@@ -13452,7 +13452,7 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
/* TODO: Use real NF instead of default one. */
signal = rate_info.rssi_comb;
- params.pdev_id = ar->pdev->pdev_id;
+ params.pdev_id = ath12k_mac_get_target_pdev_id(ar);
params.vdev_id = 0;
params.stats_id = WMI_REQUEST_VDEV_STAT;
@@ -13580,7 +13580,7 @@ void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->ab->dp->dp_lock);
if (!signal && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA) {
- params.pdev_id = ar->pdev->pdev_id;
+ params.pdev_id = ath12k_mac_get_target_pdev_id(ar);
params.vdev_id = 0;
params.stats_id = WMI_REQUEST_VDEV_STAT;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index eb7615a289f7..48fee9346de8 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -8241,8 +8241,6 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
struct ath12k_fw_stats *stats = parse->stats;
struct ath12k *ar;
struct ath12k_link_vif *arvif;
- struct ieee80211_sta *sta;
- struct ath12k_sta *ahsta;
struct ath12k_link_sta *arsta;
int i, ret = 0;
const void *data = ptr;
@@ -8278,21 +8276,19 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
arvif = ath12k_mac_get_arvif(ar, le32_to_cpu(src->vdev_id));
if (arvif) {
- sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
- arvif->bssid,
- NULL);
- if (sta) {
- ahsta = ath12k_sta_to_ahsta(sta);
- arsta = &ahsta->deflink;
+ spin_lock_bh(&ab->base_lock);
+ arsta = ath12k_link_sta_find_by_addr(ab, arvif->bssid);
+ if (arsta) {
arsta->rssi_beacon = le32_to_cpu(src->beacon_snr);
ath12k_dbg(ab, ATH12K_DBG_WMI,
"wmi stats vdev id %d snr %d\n",
src->vdev_id, src->beacon_snr);
} else {
- ath12k_dbg(ab, ATH12K_DBG_WMI,
- "not found station bssid %pM for vdev stat\n",
- arvif->bssid);
+ ath12k_warn(ab,
+ "not found link sta with bssid %pM for vdev stat\n",
+ arvif->bssid);
}
+ spin_unlock_bh(&ab->base_lock);
}
data += sizeof(*src);
@@ -8363,8 +8359,6 @@ static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
struct ath12k_fw_stats *stats = parse->stats;
struct ath12k_link_vif *arvif;
struct ath12k_link_sta *arsta;
- struct ieee80211_sta *sta;
- struct ath12k_sta *ahsta;
struct ath12k *ar;
int vdev_id;
int j;
@@ -8400,19 +8394,15 @@ static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
"stats bssid %pM vif %p\n",
arvif->bssid, arvif->ahvif->vif);
- sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
- arvif->bssid,
- NULL);
- if (!sta) {
- ath12k_dbg(ab, ATH12K_DBG_WMI,
- "not found station of bssid %pM for rssi chain\n",
- arvif->bssid);
+ guard(spinlock_bh)(&ab->base_lock);
+ arsta = ath12k_link_sta_find_by_addr(ab, arvif->bssid);
+ if (!arsta) {
+ ath12k_warn(ab,
+ "not found link sta with bssid %pM for rssi chain\n",
+ arvif->bssid);
return -EPROTO;
}
- ahsta = ath12k_sta_to_ahsta(sta);
- arsta = &ahsta->deflink;
-
BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
ARRAY_SIZE(stats_rssi->rssi_avg_beacon));
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 121e51ce1bc0..8b27d8cc086a 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1006,7 +1006,7 @@ static void ath_scan_send_probe(struct ath_softc *sc,
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
- goto error;
+ return;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
if (ath_tx_start(sc->hw, skb, &txctl))
@@ -1119,10 +1119,8 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
- if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
- dev_kfree_skb_any(skb);
+ if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta))
return false;
- }
break;
default:
return false;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 28e5df04bd43..d24b80e492e0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -951,11 +951,10 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
goto out;
/* try to attach to the target device */
- sdiodev->bus = brcmf_sdio_probe(sdiodev);
- if (IS_ERR(sdiodev->bus)) {
- ret = PTR_ERR(sdiodev->bus);
+ ret = brcmf_sdio_probe(sdiodev);
+ if (ret)
goto out;
- }
+
brcmf_sdiod_host_fixup(sdiodev->func2->card->host);
out:
if (ret)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index 984886481f4e..1cff4ba76943 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -153,6 +153,11 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx);
return;
}
+ if (ifevent->bsscfgidx >= BRCMF_MAX_IFS) {
+ bphy_err(drvr, "invalid bsscfg index: %u\n",
+ ifevent->bsscfgidx);
+ return;
+ }
ifp = drvr->iflist[ifevent->bsscfgidx];
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index 30c19591c018..30f6fcb68632 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4445,7 +4445,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus)
return fwreq;
}
-struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret;
struct brcmf_sdio *bus;
@@ -4551,11 +4551,12 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
goto fail;
}
- return bus;
+ return 0;
fail:
brcmf_sdio_remove(bus);
- return ERR_PTR(ret);
+ sdiodev->bus = NULL;
+ return ret;
}
/* Detach and free everything */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
index 0d18ed15b403..80180d5c6c87 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -358,7 +358,7 @@ void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev);
int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev);
-struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
+int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_sdio_remove(struct brcmf_sdio *bus);
void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
index 9f6ef7ce1b58..a329c20e92fb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
@@ -483,7 +483,7 @@ static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
& boundary)) {
*alignbits = dma_align_sizetobits(size);
- dma_free_coherent(di->dmadev, size, va, *descpa);
+ dma_free_coherent(di->dmadev, *alloced, va, *descpa);
va = dma_alloc_consistent(di, size, *alignbits,
alloced, descpa);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
index 8d64a271bb94..36159a769916 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
@@ -297,6 +297,11 @@ enum iwl_legacy_cmds {
SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
/**
+ * @SCAN_START_NOTIFICATION_UMAC: uses &struct iwl_umac_scan_start
+ */
+ SCAN_START_NOTIFICATION_UMAC = 0xb2,
+
+ /**
* @MATCH_FOUND_NOTIFICATION: scan match found
*/
MATCH_FOUND_NOTIFICATION = 0xd9,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
index 60f0a4924ddf..46fcc32608e3 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
@@ -1157,6 +1157,16 @@ enum iwl_umac_scan_abort_status {
};
/**
+ * struct iwl_umac_scan_start - scan start notification
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @reserved: for future use
+ */
+struct iwl_umac_scan_start {
+ __le32 uid;
+ __le32 reserved;
+} __packed; /* SCAN_START_UMAC_API_S_VER_1 */
+
+/**
* struct iwl_umac_scan_complete - scan complete notification
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @last_schedule: last scheduling line
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
index 29df747c8938..9215fc7e2eca 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
@@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
IEEE80211_HE_MAC_CAP2_ACK_EN);
}
-static void iwl_mld_set_he_support(struct iwl_mld *mld,
- struct ieee80211_vif *vif,
- struct iwl_mac_config_cmd *cmd)
+struct iwl_mld_mac_wifi_gen_sta_iter_data {
+ struct ieee80211_vif *vif;
+ struct iwl_mac_wifi_gen_support *support;
+};
+
+static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
+ struct ieee80211_sta *sta)
{
- if (vif->type == NL80211_IFTYPE_AP)
- cmd->wifi_gen.he_ap_support = 1;
- else
- cmd->wifi_gen.he_support = 1;
+ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+ struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
+
+ if (mld_sta->vif != data->vif)
+ return;
+
+ for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
+ if (link_sta->he_cap.has_he)
+ data->support->he_support = 1;
+ if (link_sta->eht_cap.has_eht)
+ data->support->eht_support = 1;
+ }
+}
+
+static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_wifi_gen_support *support)
+{
+ struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
+ .vif = vif,
+ .support = support,
+ };
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MONITOR:
+ /* for sniffer, set to HW capabilities */
+ support->he_support = 1;
+ support->eht_support = mld->trans->cfg->eht_supported;
+ break;
+ case NL80211_IFTYPE_AP:
+ /* for AP set according to the link configs */
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ support->he_ap_support |= link_conf->he_support;
+ support->eht_support |= link_conf->eht_support;
+ }
+ break;
+ default:
+ /*
+ * If we have MLO enabled, then the firmware needs to enable
+ * address translation for the station(s) we add. That depends
+ * on having EHT enabled in firmware, which in turn depends on
+ * mac80211 in the iteration below.
+ * However, mac80211 doesn't enable capabilities on the AP STA
+ * until it has parsed the association response successfully,
+ * so set EHT (and HE as a pre-requisite for EHT) when the vif
+ * is an MLD.
+ */
+ if (ieee80211_vif_is_mld(vif)) {
+ support->he_support = 1;
+ support->eht_support = 1;
+ }
+
+ ieee80211_iterate_stations_mtx(mld->hw,
+ iwl_mld_mac_wifi_gen_sta_iter,
+ &sta_iter_data);
+ break;
+ }
}
/* fill the common part for all interface types */
@@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
u32 action)
{
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
- struct ieee80211_bss_conf *link_conf;
- unsigned int link_id;
lockdep_assert_wiphy(mld->wiphy);
@@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
cmd->nic_not_ack_enabled =
cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
- /* If we have MLO enabled, then the firmware needs to enable
- * address translation for the station(s) we add. That depends
- * on having EHT enabled in firmware, which in turn depends on
- * mac80211 in the code below.
- * However, mac80211 doesn't enable HE/EHT until it has parsed
- * the association response successfully, so just skip all that
- * and enable both when we have MLO.
- */
- if (ieee80211_vif_is_mld(vif)) {
- iwl_mld_set_he_support(mld, vif, cmd);
- cmd->wifi_gen.eht_support = 1;
- return;
- }
-
- for_each_vif_active_link(vif, link_conf, link_id) {
- if (!link_conf->he_support)
- continue;
-
- iwl_mld_set_he_support(mld, vif, cmd);
-
- /* EHT, if supported, was already set above */
- break;
- }
+ iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
}
static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 0c53d6bd9651..71a9a72c9ac0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -1761,6 +1761,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
if (vif->type == NL80211_IFTYPE_STATION)
iwl_mld_link_set_2mhz_block(mld, vif, sta);
+
+ if (sta->tdls) {
+ /*
+ * update MAC since wifi generation flags may change,
+ * we also update MAC on association to the AP via the
+ * vif assoc change
+ */
+ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
+ }
+
/* Now the link_sta's capabilities are set, update the FW */
iwl_mld_config_tlc(mld, vif, sta);
@@ -1873,6 +1883,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,
/* just removed last TDLS STA, so enable PM */
iwl_mld_update_mac_power(mld, vif, false);
}
+
+ if (sta->tdls) {
+ /*
+ * update MAC since wifi generation flags may change,
+ * we also update MAC on disassociation to the AP via
+ * the vif assoc change
+ */
+ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
+ }
} else {
return -EINVAL;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
index 495e9d8f3af6..9af79297c3b6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
@@ -171,6 +171,7 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = {
HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
HCMD_NAME(MAC_PM_POWER_TABLE),
HCMD_NAME(MFUART_LOAD_NOTIFICATION),
+ HCMD_NAME(SCAN_START_NOTIFICATION_UMAC),
HCMD_NAME(RSS_CONFIG_CMD),
HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
HCMD_NAME(REPLY_RX_MPDU_CMD),
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
index f842f5183223..fbff5915f7fd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
@@ -739,7 +739,7 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld,
/* Ignore any BSS that was not seen in the last MLO scan */
if (ktime_before(link_conf->bss->ts_boottime,
- mld->scan.last_mlo_scan_time))
+ mld->scan.last_mlo_scan_start_time))
continue;
data[n_data].link_id = link_id;
@@ -945,7 +945,7 @@ static void _iwl_mld_select_links(struct iwl_mld *mld,
if (!mld_vif->authorized || hweight16(usable_links) <= 1)
return;
- if (WARN(ktime_before(mld->scan.last_mlo_scan_time,
+ if (WARN(ktime_before(mld->scan.last_mlo_scan_start_time,
ktime_sub_ns(ktime_get_boottime_ns(),
5ULL * NSEC_PER_SEC)),
"Last MLO scan was too long ago, can't select links\n"))
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
index 240526d8b632..9c88a8579a75 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
@@ -287,6 +287,8 @@ static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld,
* at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
*/
+CMD_VERSIONS(scan_start_notif,
+ CMD_VER_ENTRY(1, iwl_umac_scan_start))
CMD_VERSIONS(scan_complete_notif,
CMD_VER_ENTRY(1, iwl_umac_scan_complete))
CMD_VERSIONS(scan_iter_complete_notif,
@@ -360,6 +362,7 @@ DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif,
link_id)
DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity)
DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid)
+DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid)
DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif,
mac_id)
DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif,
@@ -402,6 +405,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
RX_HANDLER_SYNC)
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif,
RX_HANDLER_SYNC)
+ RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC,
+ scan_start_notif)
RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC,
scan_complete_notif)
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index a1a4cf3ab3d3..abd4281b4b0e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -473,6 +473,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld,
params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN;
+ if (scan_status == IWL_MLD_SCAN_INT_MLO)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START;
+
if (params->enable_6ghz_passive)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN;
@@ -1817,9 +1820,6 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,
ret = _iwl_mld_single_scan_start(mld, vif, req, &ies,
IWL_MLD_SCAN_INT_MLO);
- if (!ret)
- mld->scan.last_mlo_scan_time = ktime_get_boottime_ns();
-
IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);
}
@@ -1904,6 +1904,30 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
ieee80211_sched_scan_results(mld->hw);
}
+void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt)
+{
+ struct iwl_umac_scan_complete *notif = (void *)pkt->data;
+ u32 uid = le32_to_cpu(notif->uid);
+
+ if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),
+ "FW reports out-of-range scan UID %d\n", uid))
+ return;
+
+ if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status),
+ "FW reports scan UID %d we didn't trigger\n", uid))
+ return;
+
+ IWL_DEBUG_SCAN(mld, "Scan started: uid=%u type=%u\n", uid,
+ mld->scan.uid_status[uid]);
+ if (IWL_FW_CHECK(mld, mld->scan.uid_status[uid] != IWL_MLD_SCAN_INT_MLO,
+ "FW reports scan start notification %d we didn't trigger\n",
+ mld->scan.uid_status[uid]))
+ return;
+
+ mld->scan.last_mlo_scan_start_time = ktime_get_boottime_ns();
+}
+
void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
struct iwl_rx_packet *pkt)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
index 69110f0cfc8e..de5620e7f463 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
@@ -27,6 +27,9 @@ int iwl_mld_sched_scan_start(struct iwl_mld *mld,
void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
struct iwl_rx_packet *pkt);
+void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
+ struct iwl_rx_packet *pkt);
+
void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
struct iwl_rx_packet *pkt);
@@ -114,8 +117,8 @@ enum iwl_mld_traffic_load {
* in jiffies.
* @last_start_time_jiffies: stores the last start time in jiffies
* (interface up/reset/resume).
- * @last_mlo_scan_time: start time of the last MLO scan in nanoseconds since
- * boot.
+ * @last_mlo_scan_start_time: start time of the last MLO scan in nanoseconds
+ * since boot.
*/
struct iwl_mld_scan {
/* Add here fields that need clean up on restart */
@@ -136,7 +139,7 @@ struct iwl_mld_scan {
void *cmd;
unsigned long last_6ghz_passive_jiffies;
unsigned long last_start_time_jiffies;
- u64 last_mlo_scan_time;
+ u64 last_mlo_scan_start_time;
};
/**
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index a19f9d2e9346..9a74f60c9185 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -2807,7 +2807,7 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm,
if (IS_ERR_OR_NULL(vif))
return;
- if (len < sizeof(struct iwl_scan_offload_match_info)) {
+ if (len < sizeof(struct iwl_scan_offload_match_info) + matches_len) {
IWL_ERR(mvm, "Invalid scan match info notification\n");
return;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 43cf94c9a36b..6cc78661116e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -470,7 +470,8 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm)
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
};
- if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) {
+ if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210 ||
+ !mvm->trans->cfg->uhb_supported) {
IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n");
return;
}
diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c
index d44e02c6fe38..dd97f1b61f4d 100644
--- a/drivers/net/wireless/marvell/libertas/main.c
+++ b/drivers/net/wireless/marvell/libertas/main.c
@@ -799,8 +799,8 @@ static void lbs_free_adapter(struct lbs_private *priv)
{
lbs_free_cmd_buffer(priv);
kfifo_free(&priv->event_fifo);
- timer_delete(&priv->command_timer);
- timer_delete(&priv->tx_lockup_timer);
+ timer_delete_sync(&priv->command_timer);
+ timer_delete_sync(&priv->tx_lockup_timer);
}
static const struct net_device_ops lbs_netdev_ops = {
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 43704106cd80..eb28fe718e71 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -3148,7 +3148,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
SET_NETDEV_DEV(dev, adapter->dev);
ret = dev_alloc_name(dev, name);
- if (ret)
+ if (ret < 0)
goto err_alloc_name;
priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC-%s",
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 3304b5971be0..b41ca1410da9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -413,6 +413,7 @@ mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
+ skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + 1 + 2 &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 871b67101976..0d9435900423 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -668,6 +668,7 @@ mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
+ skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
tid = MT_TX_ADDBA;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 2560e2f46e89..d4f3ee943b47 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -800,6 +800,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
+ skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
if (is_mt7990(&dev->mt76))
diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c
index ff9176cdee3d..63b0447e55c1 100644
--- a/drivers/net/wireless/mediatek/mt76/scan.c
+++ b/drivers/net/wireless/mediatek/mt76/scan.c
@@ -63,10 +63,8 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_lock();
- if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) {
- ieee80211_free_txskb(phy->hw, skb);
+ if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL))
goto out;
- }
info = IEEE80211_SKB_CB(skb);
if (req->no_cck)
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index f354b11cb919..944b2a812b63 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -163,7 +163,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source,
u32 index = 0;
u32 i, scan_timeout;
u8 *buffer;
- u8 valuesize = 0;
+ u32 valuesize = 0;
u8 *search_ssid_vals = NULL;
const u8 ch_list_len = request->n_channels;
struct host_if_drv *hif_drv = vif->hif_drv;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 54599cad78f9..aa5ecade2a40 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -828,7 +828,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
if (retval)
goto exit_free_device;
- rt2x00dev->anchor = devm_kmalloc(&usb_dev->dev,
+ rt2x00dev->anchor = devm_kmalloc(&usb_intf->dev,
sizeof(struct usb_anchor),
GFP_KERNEL);
if (!rt2x00dev->anchor) {
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 8c8e074a3a70..c7ae8031436a 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -668,7 +668,7 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw,
struct rsi_hw *adapter = hw->priv;
struct rsi_common *common = adapter->priv;
struct ieee80211_conf *conf = &hw->conf;
- int status = -EOPNOTSUPP;
+ int status = 0;
mutex_lock(&common->mutex);
diff --git a/drivers/net/wireless/st/cw1200/pm.c b/drivers/net/wireless/st/cw1200/pm.c
index 120f0379f81d..84eb15d729c7 100644
--- a/drivers/net/wireless/st/cw1200/pm.c
+++ b/drivers/net/wireless/st/cw1200/pm.c
@@ -264,12 +264,14 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
wiphy_err(priv->hw->wiphy,
"PM request failed: %d. WoW is disabled.\n", ret);
cw1200_wow_resume(hw);
+ mutex_unlock(&priv->conf_mutex);
return -EBUSY;
}
/* Force resume if event is coming from the device. */
if (atomic_read(&priv->bh_rx)) {
cw1200_wow_resume(hw);
+ mutex_unlock(&priv->conf_mutex);
return -EAGAIN;
}
diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c
index 2da8c0d5105b..4489aa77bb0f 100644
--- a/drivers/net/wireless/ti/wl1251/tx.c
+++ b/drivers/net/wireless/ti/wl1251/tx.c
@@ -402,12 +402,14 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
int hdrlen;
u8 *frame;
- skb = wl->tx_frames[result->id];
- if (skb == NULL) {
- wl1251_error("SKB for packet %d is NULL", result->id);
+ if (unlikely(result->id >= ARRAY_SIZE(wl->tx_frames) ||
+ wl->tx_frames[result->id] == NULL)) {
+ wl1251_error("invalid packet id %u", result->id);
return;
}
+ skb = wl->tx_frames[result->id];
+
info = IEEE80211_SKB_CB(skb);
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 17dd417756f2..1c340a4a0930 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1875,6 +1875,8 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
wl->wow_enabled);
WARN_ON(!wl->wow_enabled);
+ mutex_lock(&wl->mutex);
+
ret = pm_runtime_force_resume(wl->dev);
if (ret < 0) {
wl1271_error("ELP wakeup failure!");
@@ -1891,8 +1893,6 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
run_irq_work = true;
spin_unlock_irqrestore(&wl->wl_lock, flags);
- mutex_lock(&wl->mutex);
-
/* test the recovery flag before calling any SDIO functions */
pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
&wl->flags);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 6241866d39df..75cfbcfb7626 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -210,7 +210,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
if (skb_headroom(skb) < (total_len - skb->len) &&
pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) {
wl1271_free_tx_id(wl, id);
- return -EAGAIN;
+ return -ENOMEM;
}
desc = skb_push(skb, total_len - skb->len);
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index e89173f91637..1b6e55eb81a2 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -3021,7 +3021,6 @@ static void hw_scan_work(struct work_struct *work)
hwsim->tmp_chan->band,
NULL)) {
rcu_read_unlock();
- kfree_skb(probe);
continue;
}
@@ -6489,7 +6488,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
struct cfg80211_pmsr_capabilities *pmsr_capa;
- pmsr_capa = kmalloc_obj(*pmsr_capa);
+ pmsr_capa = kzalloc_obj(*pmsr_capa);
if (!pmsr_capa) {
ret = -ENOMEM;
goto out_free;
diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c
index 885dc7243e8d..97bd39d89e98 100644
--- a/drivers/net/wireless/virtual/virt_wifi.c
+++ b/drivers/net/wireless/virtual/virt_wifi.c
@@ -557,7 +557,6 @@ static int virt_wifi_newlink(struct net_device *dev,
eth_hw_addr_inherit(dev, priv->lowerdev);
netif_stacked_transfer_operstate(priv->lowerdev, dev);
- SET_NETDEV_DEV(dev, &priv->lowerdev->dev);
dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr);
if (!dev->ieee80211_ptr) {
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d316b35f404b..2ed673649c48 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1646,7 +1646,7 @@ static int xennet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
/* avoid the race with XDP headroom adjustment */
wait_event(module_wq,
- xenbus_read_driver_state(np->xbdev->otherend) ==
+ xenbus_read_driver_state(np->xbdev, np->xbdev->otherend) ==
XenbusStateReconfigured);
np->netfront_xdp_enabled = true;
@@ -1764,9 +1764,9 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
do {
xenbus_switch_state(dev, XenbusStateInitialising);
err = wait_event_timeout(module_wq,
- xenbus_read_driver_state(dev->otherend) !=
+ xenbus_read_driver_state(dev, dev->otherend) !=
XenbusStateClosed &&
- xenbus_read_driver_state(dev->otherend) !=
+ xenbus_read_driver_state(dev, dev->otherend) !=
XenbusStateUnknown, XENNET_TIMEOUT);
} while (!err);
@@ -2626,31 +2626,31 @@ static void xennet_bus_close(struct xenbus_device *dev)
{
int ret;
- if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
+ if (xenbus_read_driver_state(dev, dev->otherend) == XenbusStateClosed)
return;
do {
xenbus_switch_state(dev, XenbusStateClosing);
ret = wait_event_timeout(module_wq,
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosing ||
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosed ||
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateUnknown,
- XENNET_TIMEOUT);
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateClosing ||
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateClosed ||
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateUnknown,
+ XENNET_TIMEOUT);
} while (!ret);
- if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
+ if (xenbus_read_driver_state(dev, dev->otherend) == XenbusStateClosed)
return;
do {
xenbus_switch_state(dev, XenbusStateClosed);
ret = wait_event_timeout(module_wq,
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosed ||
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateUnknown,
- XENNET_TIMEOUT);
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateClosed ||
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateUnknown,
+ XENNET_TIMEOUT);
} while (!ret);
}
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index 6a5ce8ff91f0..b3d34433bd14 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -47,8 +47,8 @@ static int nxp_nci_i2c_set_mode(void *phy_id,
{
struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
- gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
- gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
+ gpiod_set_value_cansleep(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
+ gpiod_set_value_cansleep(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
usleep_range(10000, 15000);
if (mode == NXP_NCI_MODE_COLD)
diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
index 6d2f520a5bc8..e0d67cd2ac9b 100644
--- a/drivers/nfc/pn533/uart.c
+++ b/drivers/nfc/pn533/uart.c
@@ -211,14 +211,22 @@ static size_t pn532_receive_buf(struct serdev_device *serdev,
timer_delete(&dev->cmd_timeout);
for (i = 0; i < count; i++) {
+ if (!dev->recv_skb) {
+ dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN,
+ GFP_KERNEL);
+ if (!dev->recv_skb)
+ return i;
+ }
+
+ if (unlikely(!skb_tailroom(dev->recv_skb)))
+ skb_trim(dev->recv_skb, 0);
+
skb_put_u8(dev->recv_skb, *data++);
if (!pn532_uart_rx_is_frame(dev->recv_skb))
continue;
pn533_recv_frame(dev->priv, dev->recv_skb, 0);
- dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL);
- if (!dev->recv_skb)
- return 0;
+ dev->recv_skb = NULL;
}
return i;
diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c
index 018a80674f06..0f12f86ebb02 100644
--- a/drivers/nfc/pn533/usb.c
+++ b/drivers/nfc/pn533/usb.c
@@ -628,6 +628,7 @@ static void pn533_usb_disconnect(struct usb_interface *interface)
usb_free_urb(phy->out_urb);
usb_free_urb(phy->ack_urb);
kfree(phy->ack_buffer);
+ usb_put_dev(phy->udev);
nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n");
}
diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c
index 9c09c10c2a46..4ee481bd7e96 100644
--- a/drivers/nfc/s3fwrn5/uart.c
+++ b/drivers/nfc/s3fwrn5/uart.c
@@ -58,6 +58,12 @@ static size_t s3fwrn82_uart_read(struct serdev_device *serdev,
size_t i;
for (i = 0; i < count; i++) {
+ if (!phy->recv_skb) {
+ phy->recv_skb = alloc_skb(NCI_SKB_BUFF_LEN, GFP_KERNEL);
+ if (!phy->recv_skb)
+ return i;
+ }
+
skb_put_u8(phy->recv_skb, *data++);
if (phy->recv_skb->len < S3FWRN82_NCI_HEADER)
@@ -69,9 +75,7 @@ static size_t s3fwrn82_uart_read(struct serdev_device *serdev,
s3fwrn5_recv_frame(phy->common.ndev, phy->recv_skb,
phy->common.mode);
- phy->recv_skb = alloc_skb(NCI_SKB_BUFF_LEN, GFP_KERNEL);
- if (!phy->recv_skb)
- return 0;
+ phy->recv_skb = NULL;
}
return i;
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index bd9621d3f73c..45b7d756e39a 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -486,14 +486,15 @@ EXPORT_SYMBOL_GPL(nd_synchronize);
static void nd_async_device_register(void *d, async_cookie_t cookie)
{
struct device *dev = d;
+ struct device *parent = dev->parent;
if (device_add(dev) != 0) {
dev_err(dev, "%s: failed\n", __func__);
put_device(dev);
}
put_device(dev);
- if (dev->parent)
- put_device(dev->parent);
+ if (parent)
+ put_device(parent);
}
static void nd_async_device_unregister(void *d, async_cookie_t cookie)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f5ebcaa2f859..766e9cc4ffca 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2046,14 +2046,10 @@ static u32 nvme_configure_atomic_write(struct nvme_ns *ns,
if (id->nabspf)
boundary = (le16_to_cpu(id->nabspf) + 1) * bs;
} else {
- /*
- * Use the controller wide atomic write unit. This sucks
- * because the limit is defined in terms of logical blocks while
- * namespaces can have different formats, and because there is
- * no clear language in the specification prohibiting different
- * values for different controllers in the subsystem.
- */
- atomic_bs = (1 + ns->ctrl->subsys->awupf) * bs;
+ if (ns->ctrl->awupf)
+ dev_info_once(ns->ctrl->device,
+ "AWUPF ignored, only NAWUPF accepted\n");
+ atomic_bs = bs;
}
lim->atomic_write_hw_max = atomic_bs;
@@ -3222,7 +3218,6 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
memcpy(subsys->model, id->mn, sizeof(subsys->model));
subsys->vendor_id = le16_to_cpu(id->vid);
subsys->cmic = id->cmic;
- subsys->awupf = le16_to_cpu(id->awupf);
/* Versions prior to 1.4 don't necessarily report a valid type */
if (id->cntrltype == NVME_CTRL_DISC ||
@@ -3655,6 +3650,7 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
dev_pm_qos_expose_latency_tolerance(ctrl->device);
else if (!ctrl->apst_enabled && prev_apst_enabled)
dev_pm_qos_hide_latency_tolerance(ctrl->device);
+ ctrl->awupf = le16_to_cpu(id->awupf);
out_free:
kfree(id);
return ret;
@@ -4186,13 +4182,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
nvme_mpath_add_disk(ns, info->anagrpid);
nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
- /*
- * Set ns->disk->device->driver_data to ns so we can access
- * ns->head->passthru_err_log_enabled in
- * nvme_io_passthru_err_log_enabled_[store | show]().
- */
- dev_set_drvdata(disk_to_dev(ns->disk), ns);
-
return;
out_cleanup_ns_from_list:
@@ -4845,7 +4834,6 @@ EXPORT_SYMBOL_GPL(nvme_complete_async_event);
int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
const struct blk_mq_ops *ops, unsigned int cmd_size)
{
- struct queue_limits lim = {};
int ret;
memset(set, 0, sizeof(*set));
@@ -4865,7 +4853,14 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
if (ret)
return ret;
- ctrl->admin_q = blk_mq_alloc_queue(set, &lim, NULL);
+ /*
+ * If a previous admin queue exists (e.g., from before a reset),
+ * put it now before allocating a new one to avoid orphaning it.
+ */
+ if (ctrl->admin_q)
+ blk_put_queue(ctrl->admin_q);
+
+ ctrl->admin_q = blk_mq_alloc_queue(set, NULL, NULL);
if (IS_ERR(ctrl->admin_q)) {
ret = PTR_ERR(ctrl->admin_q);
goto out_free_tagset;
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 5fe09e327b3d..ac3d4f400601 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -1290,8 +1290,8 @@ void nvmf_free_options(struct nvmf_ctrl_options *opts)
kfree(opts->subsysnqn);
kfree(opts->host_traddr);
kfree(opts->host_iface);
- kfree(opts->dhchap_secret);
- kfree(opts->dhchap_ctrl_secret);
+ kfree_sensitive(opts->dhchap_secret);
+ kfree_sensitive(opts->dhchap_ctrl_secret);
kfree(opts);
}
EXPORT_SYMBOL_GPL(nvmf_free_options);
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 174027d1cc19..fc6800a9f7f9 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -1300,7 +1300,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
mutex_lock(&head->subsys->lock);
/*
* We are called when all paths have been removed, and at that point
- * head->list is expected to be empty. However, nvme_remove_ns() and
+ * head->list is expected to be empty. However, nvme_ns_remove() and
* nvme_init_ns_head() can run concurrently and so if head->delayed_
* removal_secs is configured, it is possible that by the time we reach
* this point, head->list may no longer be empty. Therefore, we recheck
@@ -1310,13 +1310,11 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
if (!list_empty(&head->list))
goto out;
- if (head->delayed_removal_secs) {
- /*
- * Ensure that no one could remove this module while the head
- * remove work is pending.
- */
- if (!try_module_get(THIS_MODULE))
- goto out;
+ /*
+ * Ensure that no one could remove this module while the head
+ * remove work is pending.
+ */
+ if (head->delayed_removal_secs && try_module_get(THIS_MODULE)) {
mod_delayed_work(nvme_wq, &head->remove_work,
head->delayed_removal_secs * HZ);
} else {
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 9a5f28c5103c..9971045dbc05 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -180,6 +180,60 @@ enum nvme_quirks {
NVME_QUIRK_DMAPOOL_ALIGN_512 = (1 << 22),
};
+static inline char *nvme_quirk_name(enum nvme_quirks q)
+{
+ switch (q) {
+ case NVME_QUIRK_STRIPE_SIZE:
+ return "stripe_size";
+ case NVME_QUIRK_IDENTIFY_CNS:
+ return "identify_cns";
+ case NVME_QUIRK_DEALLOCATE_ZEROES:
+ return "deallocate_zeroes";
+ case NVME_QUIRK_DELAY_BEFORE_CHK_RDY:
+ return "delay_before_chk_rdy";
+ case NVME_QUIRK_NO_APST:
+ return "no_apst";
+ case NVME_QUIRK_NO_DEEPEST_PS:
+ return "no_deepest_ps";
+ case NVME_QUIRK_QDEPTH_ONE:
+ return "qdepth_one";
+ case NVME_QUIRK_MEDIUM_PRIO_SQ:
+ return "medium_prio_sq";
+ case NVME_QUIRK_IGNORE_DEV_SUBNQN:
+ return "ignore_dev_subnqn";
+ case NVME_QUIRK_DISABLE_WRITE_ZEROES:
+ return "disable_write_zeroes";
+ case NVME_QUIRK_SIMPLE_SUSPEND:
+ return "simple_suspend";
+ case NVME_QUIRK_SINGLE_VECTOR:
+ return "single_vector";
+ case NVME_QUIRK_128_BYTES_SQES:
+ return "128_bytes_sqes";
+ case NVME_QUIRK_SHARED_TAGS:
+ return "shared_tags";
+ case NVME_QUIRK_NO_TEMP_THRESH_CHANGE:
+ return "no_temp_thresh_change";
+ case NVME_QUIRK_NO_NS_DESC_LIST:
+ return "no_ns_desc_list";
+ case NVME_QUIRK_DMA_ADDRESS_BITS_48:
+ return "dma_address_bits_48";
+ case NVME_QUIRK_SKIP_CID_GEN:
+ return "skip_cid_gen";
+ case NVME_QUIRK_BOGUS_NID:
+ return "bogus_nid";
+ case NVME_QUIRK_NO_SECONDARY_TEMP_THRESH:
+ return "no_secondary_temp_thresh";
+ case NVME_QUIRK_FORCE_NO_SIMPLE_SUSPEND:
+ return "force_no_simple_suspend";
+ case NVME_QUIRK_BROKEN_MSI:
+ return "broken_msi";
+ case NVME_QUIRK_DMAPOOL_ALIGN_512:
+ return "dmapool_align_512";
+ }
+
+ return "unknown";
+}
+
/*
* Common request structure for NVMe passthrough. All drivers must have
* this structure as the first member of their request-private data.
@@ -410,6 +464,8 @@ struct nvme_ctrl {
enum nvme_ctrl_type cntrltype;
enum nvme_dctype dctype;
+
+ u16 awupf; /* 0's based value. */
};
static inline enum nvme_ctrl_state nvme_ctrl_state(struct nvme_ctrl *ctrl)
@@ -442,7 +498,6 @@ struct nvme_subsystem {
u8 cmic;
enum nvme_subsys_type subtype;
u16 vendor_id;
- u16 awupf; /* 0's based value. */
struct ida ns_ida;
#ifdef CONFIG_NVME_MULTIPATH
enum nvme_iopolicy iopolicy;
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 2f0c05719316..b78ba239c8ea 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -72,6 +72,13 @@
static_assert(MAX_PRP_RANGE / NVME_CTRL_PAGE_SIZE <=
(1 /* prp1 */ + NVME_MAX_NR_DESCRIPTORS * PRPS_PER_PAGE));
+struct quirk_entry {
+ u16 vendor_id;
+ u16 dev_id;
+ u32 enabled_quirks;
+ u32 disabled_quirks;
+};
+
static int use_threaded_interrupts;
module_param(use_threaded_interrupts, int, 0444);
@@ -102,6 +109,143 @@ static unsigned int io_queue_depth = 1024;
module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644);
MODULE_PARM_DESC(io_queue_depth, "set io queue depth, should >= 2 and < 4096");
+static struct quirk_entry *nvme_pci_quirk_list;
+static unsigned int nvme_pci_quirk_count;
+
+/* Helper to parse individual quirk names */
+static int nvme_parse_quirk_names(char *quirk_str, struct quirk_entry *entry)
+{
+ int i;
+ size_t field_len;
+ bool disabled, found;
+ char *p = quirk_str, *field;
+
+ while ((field = strsep(&p, ",")) && *field) {
+ disabled = false;
+ found = false;
+
+ if (*field == '^') {
+ /* Skip the '^' character */
+ disabled = true;
+ field++;
+ }
+
+ field_len = strlen(field);
+ for (i = 0; i < 32; i++) {
+ unsigned int bit = 1U << i;
+ char *q_name = nvme_quirk_name(bit);
+ size_t q_len = strlen(q_name);
+
+ if (!strcmp(q_name, "unknown"))
+ break;
+
+ if (!strcmp(q_name, field) &&
+ q_len == field_len) {
+ if (disabled)
+ entry->disabled_quirks |= bit;
+ else
+ entry->enabled_quirks |= bit;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("nvme: unrecognized quirk %s\n", field);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/* Helper to parse a single VID:DID:quirk_names entry */
+static int nvme_parse_quirk_entry(char *s, struct quirk_entry *entry)
+{
+ char *field;
+
+ field = strsep(&s, ":");
+ if (!field || kstrtou16(field, 16, &entry->vendor_id))
+ return -EINVAL;
+
+ field = strsep(&s, ":");
+ if (!field || kstrtou16(field, 16, &entry->dev_id))
+ return -EINVAL;
+
+ field = strsep(&s, ":");
+ if (!field)
+ return -EINVAL;
+
+ return nvme_parse_quirk_names(field, entry);
+}
+
+static int quirks_param_set(const char *value, const struct kernel_param *kp)
+{
+ int count, err, i;
+ struct quirk_entry *qlist;
+ char *field, *val, *sep_ptr;
+
+ err = param_set_copystring(value, kp);
+ if (err)
+ return err;
+
+ val = kstrdup(value, GFP_KERNEL);
+ if (!val)
+ return -ENOMEM;
+
+ if (!*val)
+ goto out_free_val;
+
+ count = 1;
+ for (i = 0; val[i]; i++) {
+ if (val[i] == '-')
+ count++;
+ }
+
+ qlist = kcalloc(count, sizeof(*qlist), GFP_KERNEL);
+ if (!qlist) {
+ err = -ENOMEM;
+ goto out_free_val;
+ }
+
+ i = 0;
+ sep_ptr = val;
+ while ((field = strsep(&sep_ptr, "-"))) {
+ if (nvme_parse_quirk_entry(field, &qlist[i])) {
+ pr_err("nvme: failed to parse quirk string %s\n",
+ value);
+ goto out_free_qlist;
+ }
+
+ i++;
+ }
+
+ kfree(nvme_pci_quirk_list);
+ nvme_pci_quirk_count = count;
+ nvme_pci_quirk_list = qlist;
+ goto out_free_val;
+
+out_free_qlist:
+ kfree(qlist);
+out_free_val:
+ kfree(val);
+ return err;
+}
+
+static char quirks_param[128];
+static const struct kernel_param_ops quirks_param_ops = {
+ .set = quirks_param_set,
+ .get = param_get_string,
+};
+
+static struct kparam_string quirks_param_string = {
+ .maxlen = sizeof(quirks_param),
+ .string = quirks_param,
+};
+
+module_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0444);
+MODULE_PARM_DESC(quirks, "Enable/disable NVMe quirks by specifying "
+ "quirks=VID:DID:quirk_names");
+
static int io_queue_count_set(const char *val, const struct kernel_param *kp)
{
unsigned int n;
@@ -400,7 +544,7 @@ static void nvme_dbbuf_set(struct nvme_dev *dev)
/* Free memory and continue on */
nvme_dbbuf_dma_free(dev);
- for (i = 1; i <= dev->online_queues; i++)
+ for (i = 1; i < dev->online_queues; i++)
nvme_dbbuf_free(&dev->queues[i]);
}
}
@@ -1481,14 +1625,16 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
static void nvme_poll_irqdisable(struct nvme_queue *nvmeq)
{
struct pci_dev *pdev = to_pci_dev(nvmeq->dev->dev);
+ int irq;
WARN_ON_ONCE(test_bit(NVMEQ_POLLED, &nvmeq->flags));
- disable_irq(pci_irq_vector(pdev, nvmeq->cq_vector));
+ irq = pci_irq_vector(pdev, nvmeq->cq_vector);
+ disable_irq(irq);
spin_lock(&nvmeq->cq_poll_lock);
nvme_poll_cq(nvmeq, NULL);
spin_unlock(&nvmeq->cq_poll_lock);
- enable_irq(pci_irq_vector(pdev, nvmeq->cq_vector));
+ enable_irq(irq);
}
static int nvme_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
@@ -1496,7 +1642,8 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
struct nvme_queue *nvmeq = hctx->driver_data;
bool found;
- if (!nvme_cqe_pending(nvmeq))
+ if (!test_bit(NVMEQ_POLLED, &nvmeq->flags) ||
+ !nvme_cqe_pending(nvmeq))
return 0;
spin_lock(&nvmeq->cq_poll_lock);
@@ -2774,7 +2921,25 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
dev->nr_write_queues = write_queues;
dev->nr_poll_queues = poll_queues;
- nr_io_queues = dev->nr_allocated_queues - 1;
+ if (dev->ctrl.tagset) {
+ /*
+ * The set's maps are allocated only once at initialization
+ * time. We can't add special queues later if their mq_map
+ * wasn't preallocated.
+ */
+ if (dev->ctrl.tagset->nr_maps < 3)
+ dev->nr_poll_queues = 0;
+ if (dev->ctrl.tagset->nr_maps < 2)
+ dev->nr_write_queues = 0;
+ }
+
+ /*
+ * The initial number of allocated queue slots may be too large if the
+ * user reduced the special queue parameters. Cap the value to the
+ * number we need for this round.
+ */
+ nr_io_queues = min(nvme_max_io_queues(dev),
+ dev->nr_allocated_queues - 1);
result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues);
if (result < 0)
return result;
@@ -3458,12 +3623,25 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
return 0;
}
+static struct quirk_entry *detect_dynamic_quirks(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i < nvme_pci_quirk_count; i++)
+ if (pdev->vendor == nvme_pci_quirk_list[i].vendor_id &&
+ pdev->device == nvme_pci_quirk_list[i].dev_id)
+ return &nvme_pci_quirk_list[i];
+
+ return NULL;
+}
+
static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev,
const struct pci_device_id *id)
{
unsigned long quirks = id->driver_data;
int node = dev_to_node(&pdev->dev);
struct nvme_dev *dev;
+ struct quirk_entry *qentry;
int ret = -ENOMEM;
dev = kzalloc_node(struct_size(dev, descriptor_pools, nr_node_ids),
@@ -3495,6 +3673,11 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev,
"platform quirk: setting simple suspend\n");
quirks |= NVME_QUIRK_SIMPLE_SUSPEND;
}
+ qentry = detect_dynamic_quirks(pdev);
+ if (qentry) {
+ quirks |= qentry->enabled_quirks;
+ quirks &= ~qentry->disabled_quirks;
+ }
ret = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops,
quirks);
if (ret)
@@ -4095,6 +4278,7 @@ static int __init nvme_init(void)
static void __exit nvme_exit(void)
{
+ kfree(nvme_pci_quirk_list);
pci_unregister_driver(&nvme_driver);
flush_workqueue(nvme_wq);
}
diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c
index ad2ecc2f49a9..fe7dbe264815 100644
--- a/drivers/nvme/host/pr.c
+++ b/drivers/nvme/host/pr.c
@@ -242,7 +242,7 @@ static int nvme_pr_read_keys(struct block_device *bdev,
if (rse_len > U32_MAX)
return -EINVAL;
- rse = kzalloc(rse_len, GFP_KERNEL);
+ rse = kvzalloc(rse_len, GFP_KERNEL);
if (!rse)
return -ENOMEM;
@@ -267,7 +267,7 @@ static int nvme_pr_read_keys(struct block_device *bdev,
}
free_rse:
- kfree(rse);
+ kvfree(rse);
return ret;
}
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index 29430949ce2f..16c6fea4b2db 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -601,6 +601,28 @@ static ssize_t dctype_show(struct device *dev,
}
static DEVICE_ATTR_RO(dctype);
+static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int count = 0, i;
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+ unsigned long quirks = ctrl->quirks;
+
+ if (!quirks)
+ return sysfs_emit(buf, "none\n");
+
+ for (i = 0; quirks; ++i) {
+ if (quirks & 1) {
+ count += sysfs_emit_at(buf, count, "%s\n",
+ nvme_quirk_name(BIT(i)));
+ }
+ quirks >>= 1;
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RO(quirks);
+
#ifdef CONFIG_NVME_HOST_AUTH
static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -742,6 +764,7 @@ static struct attribute *nvme_dev_attrs[] = {
&dev_attr_kato.attr,
&dev_attr_cntrltype.attr,
&dev_attr_dctype.attr,
+ &dev_attr_quirks.attr,
#ifdef CONFIG_NVME_HOST_AUTH
&dev_attr_dhchap_secret.attr,
&dev_attr_dhchap_ctrl_secret.attr,
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 9ab3f61196a3..243dab830dc8 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -25,7 +25,8 @@
struct nvme_tcp_queue;
-/* Define the socket priority to use for connections were it is desirable
+/*
+ * Define the socket priority to use for connections where it is desirable
* that the NIC consider performing optimized packet processing or filtering.
* A non-zero value being sufficient to indicate general consideration of any
* possible optimization. Making it a module param allows for alternative
@@ -926,7 +927,7 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
req->curr_bio = req->curr_bio->bi_next;
/*
- * If we don`t have any bios it means that controller
+ * If we don't have any bios it means the controller
* sent more data than we requested, hence error
*/
if (!req->curr_bio) {
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 9de93f65d7d7..ca5b08ce1211 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -1585,7 +1585,7 @@ void nvmet_execute_async_event(struct nvmet_req *req)
ctrl->async_event_cmds[ctrl->nr_async_event_cmds++] = req;
mutex_unlock(&ctrl->lock);
- queue_work(nvmet_wq, &ctrl->async_event_work);
+ queue_work(nvmet_aen_wq, &ctrl->async_event_work);
}
void nvmet_execute_keep_alive(struct nvmet_req *req)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 5e43d0acc86e..9238e13bd480 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -27,6 +27,8 @@ static DEFINE_IDA(cntlid_ida);
struct workqueue_struct *nvmet_wq;
EXPORT_SYMBOL_GPL(nvmet_wq);
+struct workqueue_struct *nvmet_aen_wq;
+EXPORT_SYMBOL_GPL(nvmet_aen_wq);
/*
* This read/write semaphore is used to synchronize access to configuration
@@ -206,7 +208,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
list_add_tail(&aen->entry, &ctrl->async_events);
mutex_unlock(&ctrl->lock);
- queue_work(nvmet_wq, &ctrl->async_event_work);
+ queue_work(nvmet_aen_wq, &ctrl->async_event_work);
}
static void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, __le32 nsid)
@@ -1956,9 +1958,14 @@ static int __init nvmet_init(void)
if (!nvmet_wq)
goto out_free_buffered_work_queue;
+ nvmet_aen_wq = alloc_workqueue("nvmet-aen-wq",
+ WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
+ if (!nvmet_aen_wq)
+ goto out_free_nvmet_work_queue;
+
error = nvmet_init_debugfs();
if (error)
- goto out_free_nvmet_work_queue;
+ goto out_free_nvmet_aen_work_queue;
error = nvmet_init_discovery();
if (error)
@@ -1974,6 +1981,8 @@ out_exit_discovery:
nvmet_exit_discovery();
out_exit_debugfs:
nvmet_exit_debugfs();
+out_free_nvmet_aen_work_queue:
+ destroy_workqueue(nvmet_aen_wq);
out_free_nvmet_work_queue:
destroy_workqueue(nvmet_wq);
out_free_buffered_work_queue:
@@ -1991,6 +2000,7 @@ static void __exit nvmet_exit(void)
nvmet_exit_discovery();
nvmet_exit_debugfs();
ida_destroy(&cntlid_ida);
+ destroy_workqueue(nvmet_aen_wq);
destroy_workqueue(nvmet_wq);
destroy_workqueue(buffered_io_wq);
destroy_workqueue(zbd_wq);
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 866048f07e61..b63af3b643a6 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -491,6 +491,7 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
struct fcloop_rport *rport = remoteport->private;
struct nvmet_fc_target_port *targetport = rport->targetport;
struct fcloop_tport *tport;
+ int ret = 0;
if (!targetport) {
/*
@@ -500,12 +501,18 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
* We end up here from delete association exchange:
* nvmet_fc_xmt_disconnect_assoc sends an async request.
*
- * Return success because this is what LLDDs do; silently
- * drop the response.
+ * Return success when remoteport is still online because this
+ * is what LLDDs do and silently drop the response. Otherwise,
+ * return with error to signal upper layer to perform the lsrsp
+ * resource cleanup.
*/
- lsrsp->done(lsrsp);
+ if (remoteport->port_state == FC_OBJSTATE_ONLINE)
+ lsrsp->done(lsrsp);
+ else
+ ret = -ENODEV;
+
kmem_cache_free(lsreq_cache, tls_req);
- return 0;
+ return ret;
}
memcpy(lsreq->rspaddr, lsrsp->rspbuf,
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index b664b584fdc8..319d6a5e9cf0 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -501,6 +501,7 @@ extern struct kmem_cache *nvmet_bvec_cache;
extern struct workqueue_struct *buffered_io_wq;
extern struct workqueue_struct *zbd_wq;
extern struct workqueue_struct *nvmet_wq;
+extern struct workqueue_struct *nvmet_aen_wq;
static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
{
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 2d6eb89f98af..e6e2c3f9afdf 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -2087,6 +2087,7 @@ static void nvmet_rdma_remove_one(struct ib_device *ib_device, void *client_data
mutex_unlock(&nvmet_rdma_queue_mutex);
flush_workqueue(nvmet_wq);
+ flush_workqueue(nvmet_aen_wq);
}
static struct ib_client nvmet_rdma_ib_client = {
diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index 7cf7e809a8f5..a0d2985c6d03 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -131,6 +131,7 @@ static int imx_ocotp_cell_pp(void *context, const char *id, int index,
static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
struct nvmem_cell_info *cell)
{
+ cell->raw_len = round_up(cell->bytes, 4);
cell->read_post_process = imx_ocotp_cell_pp;
}
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 7bf7656d4f96..108d78d7f6cb 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -589,6 +589,7 @@ MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
struct nvmem_cell_info *cell)
{
+ cell->raw_len = round_up(cell->bytes, 4);
cell->read_post_process = imx_ocotp_cell_pp;
}
diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c
index 7da717d6c7fa..d297ff150dc0 100644
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -66,7 +66,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
dma_addr_t dma_buf;
size_t words = bytes / WORD_INBYTES;
int ret;
- int value;
+ unsigned int value;
char *data;
if (bytes % WORD_INBYTES != 0) {
@@ -80,7 +80,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
}
if (pufflag == 1 && flag == EFUSE_WRITE) {
- memcpy(&value, val, bytes);
+ memcpy(&value, val, sizeof(value));
if ((offset == EFUSE_PUF_START_OFFSET ||
offset == EFUSE_PUF_MID_OFFSET) &&
value & P_USER_0_64_UPPER_MASK) {
@@ -100,7 +100,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
if (!efuse)
return -ENOMEM;
- data = dma_alloc_coherent(dev, sizeof(bytes),
+ data = dma_alloc_coherent(dev, bytes,
&dma_buf, GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
@@ -134,7 +134,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
if (flag == EFUSE_READ)
memcpy(val, data, bytes);
efuse_access_err:
- dma_free_coherent(dev, sizeof(bytes),
+ dma_free_coherent(dev, bytes,
data, dma_buf);
efuse_data_fail:
dma_free_coherent(dev, sizeof(struct xilinx_efuse),
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 295076cf70de..c57ae4d6c5c0 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -905,6 +905,19 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
* supported, so we avoid reprogramming the region on every MSI,
* specifically unmapping immediately after writel().
*/
+ if (ep->msi_iatu_mapped && (ep->msi_msg_addr != msg_addr ||
+ ep->msi_map_size != map_size)) {
+ /*
+ * The host changed the MSI target address or the required
+ * mapping size changed. Reprogramming the iATU when there are
+ * operations in flight is unsafe on this controller. However,
+ * there is no unified way to check if we have operations in
+ * flight, thus we don't know if we should WARN() or not.
+ */
+ dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys);
+ ep->msi_iatu_mapped = false;
+ }
+
if (!ep->msi_iatu_mapped) {
ret = dw_pcie_ep_map_addr(epc, func_no, 0,
ep->msi_mem_phys, msg_addr,
@@ -915,15 +928,6 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
ep->msi_iatu_mapped = true;
ep->msi_msg_addr = msg_addr;
ep->msi_map_size = map_size;
- } else if (WARN_ON_ONCE(ep->msi_msg_addr != msg_addr ||
- ep->msi_map_size != map_size)) {
- /*
- * The host changed the MSI target address or the required
- * mapping size changed. Reprogramming the iATU at runtime is
- * unsafe on this controller, so bail out instead of trying to
- * update the existing region.
- */
- return -EINVAL;
}
writel(msg_data | (interrupt_num - 1), ep->msi_mem + offset);
@@ -1010,6 +1014,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
writel(msg_data, ep->msi_mem + offset);
+ /* flush posted write before unmap */
+ readl(ep->msi_mem + offset);
+
dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys);
return 0;
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 2c7a406b4ba8..49c0a2d51162 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -2485,6 +2485,14 @@ static void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
if (!hv_dev)
continue;
+ /*
+ * If the Hyper-V host doesn't provide a NUMA node for the
+ * device, default to node 0. With NUMA_NO_NODE the kernel
+ * may spread work across NUMA nodes, which degrades
+ * performance on Hyper-V.
+ */
+ set_dev_node(&dev->dev, 0);
+
if (hv_dev->desc.flags & HV_PCI_DEVICE_FLAG_NUMA_AFFINITY &&
hv_dev->desc.virtual_numa_node < num_possible_nodes())
/*
@@ -3778,7 +3786,7 @@ static int hv_pci_probe(struct hv_device *hdev,
hbus->bridge->domain_nr);
if (!hbus->wq) {
ret = -ENOMEM;
- goto free_dom;
+ goto free_bus;
}
hdev->channel->next_request_id_callback = vmbus_next_request_id;
@@ -3874,8 +3882,6 @@ close:
vmbus_close(hdev->channel);
destroy_wq:
destroy_workqueue(hbus->wq);
-free_dom:
- pci_bus_release_emul_domain_nr(hbus->bridge->domain_nr);
free_bus:
kfree(hbus);
return ret;
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 582938b7b4f1..33548935765e 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -894,6 +894,11 @@ static void pci_epf_test_bar_subrange_setup(struct pci_epf_test *epf_test,
dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret);
bar->submap = old_submap;
bar->num_submap = old_nsub;
+ ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar);
+ if (ret)
+ dev_warn(&epf->dev, "Failed to restore the original BAR mapping: %d\n",
+ ret);
+
kfree(submap);
goto err;
}
diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c
index 6f7dea6746e0..97cff5b8ca88 100644
--- a/drivers/pci/pwrctrl/core.c
+++ b/drivers/pci/pwrctrl/core.c
@@ -268,6 +268,48 @@ err_power_off:
}
EXPORT_SYMBOL_GPL(pci_pwrctrl_power_on_devices);
+/*
+ * Check whether the pwrctrl device really needs to be created or not. The
+ * pwrctrl device will only be created if the node satisfies below requirements:
+ *
+ * 1. Presence of compatible property with "pci" prefix to match against the
+ * pwrctrl driver (AND)
+ * 2. At least one of the power supplies defined in the devicetree node of the
+ * device (OR) in the remote endpoint parent node to indicate pwrctrl
+ * requirement.
+ */
+static bool pci_pwrctrl_is_required(struct device_node *np)
+{
+ struct device_node *endpoint;
+ const char *compat;
+ int ret;
+
+ ret = of_property_read_string(np, "compatible", &compat);
+ if (ret < 0)
+ return false;
+
+ if (!strstarts(compat, "pci"))
+ return false;
+
+ if (of_pci_supply_present(np))
+ return true;
+
+ if (of_graph_is_present(np)) {
+ for_each_endpoint_of_node(np, endpoint) {
+ struct device_node *remote __free(device_node) =
+ of_graph_get_remote_port_parent(endpoint);
+ if (remote) {
+ if (of_pci_supply_present(remote)) {
+ of_node_put(endpoint);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
static int pci_pwrctrl_create_device(struct device_node *np,
struct device *parent)
{
@@ -287,19 +329,7 @@ static int pci_pwrctrl_create_device(struct device_node *np,
return 0;
}
- /*
- * Sanity check to make sure that the node has the compatible property
- * to allow driver binding.
- */
- if (!of_property_present(np, "compatible"))
- return 0;
-
- /*
- * Check whether the pwrctrl device really needs to be created or not.
- * This is decided based on at least one of the power supplies defined
- * in the devicetree node of the device or the graph property.
- */
- if (!of_pci_supply_present(np) && !of_graph_is_present(np)) {
+ if (!pci_pwrctrl_is_required(np)) {
dev_dbg(parent, "Skipping OF node: %s\n", np->name);
return 0;
}
diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c
index 0d0377283c37..c7e4beec160a 100644
--- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c
+++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c
@@ -68,13 +68,6 @@ static int pwrseq_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl)
return pwrseq_power_off(pwrseq->pwrseq);
}
-static void devm_pwrseq_pwrctrl_power_off(void *data)
-{
- struct pwrseq_pwrctrl *pwrseq = data;
-
- pwrseq_pwrctrl_power_off(&pwrseq->pwrctrl);
-}
-
static int pwrseq_pwrctrl_probe(struct platform_device *pdev)
{
const struct pwrseq_pwrctrl_pdata *pdata;
@@ -101,11 +94,6 @@ static int pwrseq_pwrctrl_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq),
"Failed to get the power sequencer\n");
- ret = devm_add_action_or_reset(dev, devm_pwrseq_pwrctrl_power_off,
- pwrseq);
- if (ret)
- return ret;
-
pwrseq->pwrctrl.power_on = pwrseq_pwrctrl_power_on;
pwrseq->pwrctrl.power_off = pwrseq_pwrctrl_power_off;
diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c
index 082af81efe25..b87639253ae2 100644
--- a/drivers/pci/pwrctrl/slot.c
+++ b/drivers/pci/pwrctrl/slot.c
@@ -63,7 +63,6 @@ static void devm_slot_pwrctrl_release(void *data)
{
struct slot_pwrctrl *slot = data;
- slot_pwrctrl_power_off(&slot->pwrctrl);
regulator_bulk_free(slot->num_supplies, slot->supplies);
}
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index b8aaa292c3e7..cffc32d66032 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -856,7 +856,7 @@ static void pcifront_try_connect(struct pcifront_device *pdev)
int err;
/* Only connect once */
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) !=
XenbusStateInitialised)
return;
@@ -876,7 +876,7 @@ static int pcifront_try_disconnect(struct pcifront_device *pdev)
enum xenbus_state prev_state;
- prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+ prev_state = xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename);
if (prev_state >= XenbusStateClosing)
goto out;
@@ -895,7 +895,7 @@ out:
static void pcifront_attach_devices(struct pcifront_device *pdev)
{
- if (xenbus_read_driver_state(pdev->xdev->nodename) ==
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) ==
XenbusStateReconfiguring)
pcifront_connect(pdev);
}
@@ -909,7 +909,7 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
struct pci_dev *pci_dev;
char str[64];
- state = xenbus_read_driver_state(pdev->xdev->nodename);
+ state = xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename);
if (state == XenbusStateInitialised) {
dev_dbg(&pdev->xdev->dev, "Handle skipped connect.\n");
/* We missed Connected and need to initialize. */
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 02467dfd4fb0..1875d5b784f6 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -6,7 +6,7 @@
menu "PHY Subsystem"
config PHY_COMMON_PROPS
- bool
+ bool "PHY common properties" if KUNIT_ALL_TESTS
help
This parses properties common between generic PHYs and Ethernet PHYs.
@@ -16,8 +16,7 @@ config PHY_COMMON_PROPS
config PHY_COMMON_PROPS_TEST
tristate "KUnit tests for PHY common props" if !KUNIT_ALL_TESTS
- select PHY_COMMON_PROPS
- depends on KUNIT
+ depends on KUNIT && PHY_COMMON_PROPS
default KUNIT_ALL_TESTS
help
This builds KUnit tests for the PHY common property API.
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index 2b0fd95ba62f..63427fc34e26 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1069,6 +1069,8 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
lane = &priv->lane[i];
+ if (!lane->phy)
+ continue;
mutex_lock(&lane->phy->mutex);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index df138a5442eb..771bc7c2ab50 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -990,6 +990,7 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0xc1),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e),
@@ -999,13 +1000,11 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = {
};
static const struct qmp_phy_init_tbl sm8650_ufsphy_g4_pcs[] = {
- QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x13),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
};
static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = {
- QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05),
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4d),
diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c
index 342061380012..9215d0b223b2 100644
--- a/drivers/phy/spacemit/phy-k1-usb2.c
+++ b/drivers/phy/spacemit/phy-k1-usb2.c
@@ -48,6 +48,9 @@
#define PHY_CLK_HSTXP_EN BIT(3) /* clock hstxp enable */
#define PHY_HSTXP_MODE BIT(4) /* 0: force en_txp to be 1; 1: no force */
+#define PHY_K1_HS_HOST_DISC 0x40
+#define PHY_K1_HS_HOST_DISC_CLR BIT(0)
+
#define PHY_PLL_DIV_CFG 0x98
#define PHY_FDIV_FRACT_8_15 GENMASK(7, 0)
#define PHY_FDIV_FRACT_16_19 GENMASK(11, 8)
@@ -142,9 +145,20 @@ static int spacemit_usb2phy_exit(struct phy *phy)
return 0;
}
+static int spacemit_usb2phy_disconnect(struct phy *phy, int port)
+{
+ struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
+
+ regmap_update_bits(sphy->regmap_base, PHY_K1_HS_HOST_DISC,
+ PHY_K1_HS_HOST_DISC_CLR, PHY_K1_HS_HOST_DISC_CLR);
+
+ return 0;
+}
+
static const struct phy_ops spacemit_usb2phy_ops = {
.init = spacemit_usb2phy_init,
.exit = spacemit_usb2phy_exit,
+ .disconnect = spacemit_usb2phy_disconnect,
.owner = THIS_MODULE,
};
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 6e9ecb88dc8b..6b584706b913 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -1425,6 +1425,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
dev_err(dev,
"%s: Reading \"reg\" from \"%s\" failed: %d\n",
__func__, subnode->name, ret);
+ of_node_put(serdes);
return ret;
}
of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes);
@@ -1439,6 +1440,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
}
}
+ of_node_put(serdes);
return 0;
}
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
index a8f82104a384..227c37c360e1 100644
--- a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
+++ b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
@@ -574,10 +574,9 @@ static int cs42l43_pin_probe(struct platform_device *pdev)
if (child) {
ret = devm_add_action_or_reset(&pdev->dev,
cs42l43_fwnode_put, child);
- if (ret) {
- fwnode_handle_put(child);
+ if (ret)
return ret;
- }
+
if (!child->dev)
child->dev = priv->dev;
fwnode = child;
diff --git a/drivers/pinctrl/cix/pinctrl-sky1.c b/drivers/pinctrl/cix/pinctrl-sky1.c
index 5d0d8be815b2..938894058d86 100644
--- a/drivers/pinctrl/cix/pinctrl-sky1.c
+++ b/drivers/pinctrl/cix/pinctrl-sky1.c
@@ -522,11 +522,10 @@ static int __maybe_unused sky1_pinctrl_resume(struct device *dev)
return pinctrl_force_default(spctl->pctl);
}
-const struct dev_pm_ops sky1_pinctrl_pm_ops = {
+static const struct dev_pm_ops sky1_pinctrl_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(sky1_pinctrl_suspend,
sky1_pinctrl_resume)
};
-EXPORT_SYMBOL_GPL(sky1_pinctrl_pm_ops);
static int sky1_pinctrl_probe(struct platform_device *pdev)
{
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 9d32bb8bc13a..97bf5ec78db4 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -53,8 +53,6 @@
#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p))
#define PADOWN_GPP(p) ((p) / 8)
-#define PWMC 0x204
-
/* Offset from pad_regs */
#define PADCFG0 0x000
#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25)
@@ -205,19 +203,25 @@ static bool intel_pad_owned_by_host(const struct intel_pinctrl *pctrl, unsigned
community = intel_get_community(pctrl, pin);
if (!community)
return false;
- if (!community->padown_offset)
+
+ /* If padown_offset is not provided, assume host ownership */
+ padown = community->regs + community->padown_offset;
+ if (padown == community->regs)
return true;
+ /* New HW generations have extended PAD_OWN registers */
+ if (community->features & PINCTRL_FEATURE_3BIT_PAD_OWN)
+ return !(readl(padown + pin_to_padno(community, pin) * 4) & 7);
+
padgrp = intel_community_get_padgroup(community, pin);
if (!padgrp)
return false;
gpp_offset = padgroup_offset(padgrp, pin);
gpp = PADOWN_GPP(gpp_offset);
- offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4;
- padown = community->regs + offset;
+ offset = padgrp->padown_num * 4 + gpp * 4;
- return !(readl(padown) & PADOWN_MASK(gpp_offset));
+ return !(readl(padown + offset) & PADOWN_MASK(gpp_offset));
}
static bool intel_pad_acpi_mode(const struct intel_pinctrl *pctrl, unsigned int pin)
@@ -1549,8 +1553,10 @@ static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl)
}
static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl,
- struct intel_community *community)
+ struct intel_community *community,
+ unsigned short capability_offset)
{
+ void __iomem *base = community->regs + capability_offset + 4;
static const struct pwm_lpss_boardinfo info = {
.clk_rate = 19200000,
.npwm = 1,
@@ -1564,7 +1570,7 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl,
if (!IS_REACHABLE(CONFIG_PWM_LPSS))
return 0;
- chip = devm_pwm_lpss_probe(pctrl->dev, community->regs + PWMC, &info);
+ chip = devm_pwm_lpss_probe(pctrl->dev, base, &info);
return PTR_ERR_OR_ZERO(chip);
}
@@ -1595,7 +1601,9 @@ int intel_pinctrl_probe(struct platform_device *pdev,
for (i = 0; i < pctrl->ncommunities; i++) {
struct intel_community *community = &pctrl->communities[i];
+ unsigned short capability_offset[6];
void __iomem *regs;
+ u32 revision;
u32 offset;
u32 value;
@@ -1610,10 +1618,14 @@ int intel_pinctrl_probe(struct platform_device *pdev,
value = readl(regs + REVID);
if (value == ~0u)
return -ENODEV;
- if (((value & REVID_MASK) >> REVID_SHIFT) >= 0x94) {
+
+ revision = (value & REVID_MASK) >> REVID_SHIFT;
+ if (revision >= 0x092) {
community->features |= PINCTRL_FEATURE_DEBOUNCE;
community->features |= PINCTRL_FEATURE_1K_PD;
}
+ if (revision >= 0x110)
+ community->features |= PINCTRL_FEATURE_3BIT_PAD_OWN;
/* Determine community features based on the capabilities */
offset = CAPLIST;
@@ -1622,15 +1634,19 @@ int intel_pinctrl_probe(struct platform_device *pdev,
switch ((value & CAPLIST_ID_MASK) >> CAPLIST_ID_SHIFT) {
case CAPLIST_ID_GPIO_HW_INFO:
community->features |= PINCTRL_FEATURE_GPIO_HW_INFO;
+ capability_offset[CAPLIST_ID_GPIO_HW_INFO] = offset;
break;
case CAPLIST_ID_PWM:
community->features |= PINCTRL_FEATURE_PWM;
+ capability_offset[CAPLIST_ID_PWM] = offset;
break;
case CAPLIST_ID_BLINK:
community->features |= PINCTRL_FEATURE_BLINK;
+ capability_offset[CAPLIST_ID_BLINK] = offset;
break;
case CAPLIST_ID_EXP:
community->features |= PINCTRL_FEATURE_EXP;
+ capability_offset[CAPLIST_ID_EXP] = offset;
break;
default:
break;
@@ -1653,7 +1669,7 @@ int intel_pinctrl_probe(struct platform_device *pdev,
if (ret)
return ret;
- ret = intel_pinctrl_probe_pwm(pctrl, community);
+ ret = intel_pinctrl_probe_pwm(pctrl, community, capability_offset[CAPLIST_ID_PWM]);
if (ret)
return ret;
}
diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h
index 2f37109d5860..b5476b9de0db 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.h
+++ b/drivers/pinctrl/intel/pinctrl-intel.h
@@ -150,6 +150,7 @@ struct intel_community {
#define PINCTRL_FEATURE_PWM BIT(3)
#define PINCTRL_FEATURE_BLINK BIT(4)
#define PINCTRL_FEATURE_EXP BIT(5)
+#define PINCTRL_FEATURE_3BIT_PAD_OWN BIT(6)
#define __INTEL_COMMUNITY(b, s, e, g, n, gs, gn, soc) \
{ \
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index d6a46fe0cda8..3f518dce6d23 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -1135,9 +1135,12 @@ int mtk_pctrl_init(struct platform_device *pdev,
goto chip_error;
}
- ret = mtk_eint_init(pctl, pdev);
- if (ret)
- goto chip_error;
+ /* Only initialize EINT if we have EINT pins */
+ if (data->eint_hw.ap_num > 0) {
+ ret = mtk_eint_init(pctl, pdev);
+ if (ret)
+ goto chip_error;
+ }
return 0;
diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
index dfa32b11555c..e2293a872dcb 100644
--- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
+++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
@@ -679,7 +679,6 @@ static int aml_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
unsigned int *num_maps)
{
struct device *dev = pctldev->dev;
- struct device_node *pnode;
unsigned long *configs = NULL;
unsigned int num_configs = 0;
struct property *prop;
@@ -693,7 +692,7 @@ static int aml_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
return -ENOENT;
}
- pnode = of_get_parent(np);
+ struct device_node *pnode __free(device_node) = of_get_parent(np);
if (!pnode) {
dev_info(dev, "Missing function node\n");
return -EINVAL;
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 94b1d057197c..2b030bd0e6ad 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -351,13 +351,13 @@ int pinconf_generic_parse_dt_config(struct device_node *np,
ret = parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
if (ret)
- return ret;
+ goto out;
if (pctldev && pctldev->desc->num_custom_params &&
pctldev->desc->custom_params) {
ret = parse_dt_cfg(np, pctldev->desc->custom_params,
pctldev->desc->num_custom_params, cfg, &ncfg);
if (ret)
- return ret;
+ goto out;
}
/* no configs found at all */
diff --git a/drivers/pinctrl/pinctrl-amdisp.c b/drivers/pinctrl/pinctrl-amdisp.c
index efbf40c776ea..e0874cc086a7 100644
--- a/drivers/pinctrl/pinctrl-amdisp.c
+++ b/drivers/pinctrl/pinctrl-amdisp.c
@@ -80,7 +80,7 @@ static int amdisp_get_group_pins(struct pinctrl_dev *pctldev,
return 0;
}
-const struct pinctrl_ops amdisp_pinctrl_ops = {
+static const struct pinctrl_ops amdisp_pinctrl_ops = {
.get_groups_count = amdisp_get_groups_count,
.get_group_name = amdisp_get_group_name,
.get_group_pins = amdisp_get_group_pins,
diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c
index a4b04bf6d081..5c055d344ac9 100644
--- a/drivers/pinctrl/pinctrl-cy8c95x0.c
+++ b/drivers/pinctrl/pinctrl-cy8c95x0.c
@@ -627,7 +627,7 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_scatter(tmask, mask, chip->map, MAX_LINE);
bitmap_scatter(tval, val, chip->map, MAX_LINE);
- for_each_set_clump8(offset, bits, tmask, chip->tpin) {
+ for_each_set_clump8(offset, bits, tmask, chip->nport * BANK_SZ) {
unsigned int i = offset / 8;
write_val = bitmap_get_value8(tval, offset);
@@ -655,7 +655,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_scatter(tmask, mask, chip->map, MAX_LINE);
bitmap_scatter(tval, val, chip->map, MAX_LINE);
- for_each_set_clump8(offset, bits, tmask, chip->tpin) {
+ for_each_set_clump8(offset, bits, tmask, chip->nport * BANK_SZ) {
unsigned int i = offset / 8;
ret = cy8c95x0_regmap_read_bits(chip, reg, i, bits, &read_val);
diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
index 48b55c5bf8d4..ba1c867b7b89 100644
--- a/drivers/pinctrl/pinctrl-equilibrium.c
+++ b/drivers/pinctrl/pinctrl-equilibrium.c
@@ -23,7 +23,7 @@
#define PIN_NAME_LEN 10
#define PAD_REG_OFF 0x100
-static void eqbr_gpio_disable_irq(struct irq_data *d)
+static void eqbr_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -36,7 +36,7 @@ static void eqbr_gpio_disable_irq(struct irq_data *d)
gpiochip_disable_irq(gc, offset);
}
-static void eqbr_gpio_enable_irq(struct irq_data *d)
+static void eqbr_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -50,7 +50,7 @@ static void eqbr_gpio_enable_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
-static void eqbr_gpio_ack_irq(struct irq_data *d)
+static void eqbr_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -62,10 +62,17 @@ static void eqbr_gpio_ack_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
-static void eqbr_gpio_mask_ack_irq(struct irq_data *d)
+static void eqbr_irq_mask_ack(struct irq_data *d)
{
- eqbr_gpio_disable_irq(d);
- eqbr_gpio_ack_irq(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
+ unsigned int offset = irqd_to_hwirq(d);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&gctrl->lock, flags);
+ writel(BIT(offset), gctrl->membase + GPIO_IRNENCLR);
+ writel(BIT(offset), gctrl->membase + GPIO_IRNCR);
+ raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
static inline void eqbr_cfg_bit(void __iomem *addr,
@@ -92,7 +99,7 @@ static int eqbr_irq_type_cfg(struct gpio_irq_type *type,
return 0;
}
-static int eqbr_gpio_set_irq_type(struct irq_data *d, unsigned int type)
+static int eqbr_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -166,11 +173,11 @@ static void eqbr_irq_handler(struct irq_desc *desc)
static const struct irq_chip eqbr_irq_chip = {
.name = "gpio_irq",
- .irq_mask = eqbr_gpio_disable_irq,
- .irq_unmask = eqbr_gpio_enable_irq,
- .irq_ack = eqbr_gpio_ack_irq,
- .irq_mask_ack = eqbr_gpio_mask_ack_irq,
- .irq_set_type = eqbr_gpio_set_irq_type,
+ .irq_ack = eqbr_irq_ack,
+ .irq_mask = eqbr_irq_mask,
+ .irq_mask_ack = eqbr_irq_mask_ack,
+ .irq_unmask = eqbr_irq_unmask,
+ .irq_set_type = eqbr_irq_set_type,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 586f2f67c617..b89b3169e8be 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -664,6 +664,15 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
if (mcp->irq && mcp->irq_controller) {
struct gpio_irq_chip *girq = &mcp->chip.irq;
+ /*
+ * Disable all pin interrupts, to prevent the interrupt handler from
+ * calling nested handlers for any currently-enabled interrupts that
+ * do not (yet) have an actual handler.
+ */
+ ret = mcp_write(mcp, MCP_GPINTEN, 0);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "can't disable interrupts\n");
+
gpio_irq_chip_set_chip(girq, &mcp23s08_irq_chip);
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index d87c0b1de616..f15b18f334ee 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3640,14 +3640,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
* or the gpio driver hasn't probed yet.
*/
scoped_guard(mutex, &bank->deferred_lock) {
- if (!gpio || !gpio->direction_output) {
- rc = rockchip_pinconf_defer_pin(bank,
- pin - bank->pin_base,
- param, arg);
- if (rc)
- return rc;
- break;
- }
+ if (!gpio || !gpio->direction_output)
+ return rockchip_pinconf_defer_pin(bank,
+ pin - bank->pin_base,
+ param, arg);
}
}
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs615.c b/drivers/pinctrl/qcom/pinctrl-qcs615.c
index 4dfa820d4e77..f1c827ddbfbf 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs615.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs615.c
@@ -1067,6 +1067,7 @@ static const struct msm_pinctrl_soc_data qcs615_tlmm = {
.ntiles = ARRAY_SIZE(qcs615_tiles),
.wakeirq_map = qcs615_pdc_map,
.nwakeirq_map = ARRAY_SIZE(qcs615_pdc_map),
+ .wakeirq_dual_edge_errata = true,
};
static const struct of_device_id qcs615_tlmm_of_match[] = {
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c
index d93af5f0e8d3..65411abfbfac 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c
@@ -76,7 +76,7 @@ static const char * const pdm_clk_groups[] = { "gpio18" };
static const char * const pdm_rx_groups[] = { "gpio21", "gpio23", "gpio25" };
static const char * const pdm_sync_groups[] = { "gpio19" };
-const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
+static const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
LPI_PINGROUP_OFFSET(0, LPI_NO_SLEW, _, _, _, _, 0x0000),
LPI_PINGROUP_OFFSET(1, LPI_NO_SLEW, _, _, _, _, 0x1000),
LPI_PINGROUP_OFFSET(2, LPI_NO_SLEW, _, _, _, _, 0x2000),
@@ -113,7 +113,7 @@ const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
LPI_PINGROUP_OFFSET(31, LPI_NO_SLEW, _, _, _, _, 0xb010),
};
-const struct lpi_function sdm660_lpi_pinctrl_functions[] = {
+static const struct lpi_function sdm660_lpi_pinctrl_functions[] = {
LPI_FUNCTION(comp_rx),
LPI_FUNCTION(dmic1_clk),
LPI_FUNCTION(dmic1_data),
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 83f940fe30b2..d02d42513ebb 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -723,6 +723,21 @@ static const struct pinconf_ops pmic_gpio_pinconf_ops = {
.pin_config_group_dbg_show = pmic_gpio_config_dbg_show,
};
+static int pmic_gpio_get_direction(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
+ struct pmic_gpio_pad *pad;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ if (!pad->is_enabled || pad->analog_pass ||
+ (!pad->input_enabled && !pad->output_enabled))
+ return -EINVAL;
+
+ /* Make sure the state is aligned on what pmic_gpio_get() returns */
+ return pad->input_enabled ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
+}
+
static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
struct pmic_gpio_state *state = gpiochip_get_data(chip);
@@ -801,6 +816,7 @@ static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
}
static const struct gpio_chip pmic_gpio_gpio_template = {
+ .get_direction = pmic_gpio_get_direction,
.direction_input = pmic_gpio_direction_input,
.direction_output = pmic_gpio_direction_output,
.get = pmic_gpio_get,
diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c
index bc8b9b9ad05b..d2949e4dbaf7 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza1.c
@@ -589,7 +589,7 @@ static inline unsigned int rza1_get_bit(struct rza1_port *port,
{
void __iomem *mem = RZA1_ADDR(port->base, reg, port->id);
- return ioread16(mem) & BIT(bit);
+ return !!(ioread16(mem) & BIT(bit));
}
/**
diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c
index 9949108a35bb..5927744c7a96 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c
@@ -85,7 +85,7 @@ struct rzt2h_pinctrl {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range;
DECLARE_BITMAP(used_irqs, RZT2H_INTERRUPTS_NUM);
- spinlock_t lock; /* lock read/write registers */
+ raw_spinlock_t lock; /* lock read/write registers */
struct mutex mutex; /* serialize adding groups and functions */
bool safety_port_enabled;
atomic_t wakeup_path;
@@ -145,7 +145,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl,
u64 reg64;
u16 reg16;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
/* Set pin to 'Non-use (Hi-Z input protection)' */
reg16 = rzt2h_pinctrl_readw(pctrl, port, PM(port));
@@ -474,7 +474,7 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset)
if (ret)
return ret;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
/* Select GPIO mode in PMC Register */
rzt2h_pinctrl_set_gpio_en(pctrl, port, bit, true);
@@ -487,7 +487,7 @@ static void rzt2h_gpio_set_direction(struct rzt2h_pinctrl *pctrl, u32 port,
{
u16 reg;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
reg &= ~PM_PIN_MASK(bit);
@@ -509,7 +509,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
if (ret)
return ret;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) {
/*
@@ -547,7 +547,7 @@ static int rzt2h_gpio_set(struct gpio_chip *chip, unsigned int offset,
u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
u8 reg;
- guard(spinlock_irqsave)(&pctrl->lock);
+ guard(raw_spinlock_irqsave)(&pctrl->lock);
reg = rzt2h_pinctrl_readb(pctrl, port, P(port));
if (value)
@@ -833,6 +833,7 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
if (ret)
return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n");
+ of_node_put(of_args.np);
if (of_args.args[0] != 0 || of_args.args[1] != 0 ||
of_args.args[2] != pctrl->data->n_port_pins)
return dev_err_probe(dev, -EINVAL,
@@ -964,7 +965,7 @@ static int rzt2h_pinctrl_probe(struct platform_device *pdev)
if (ret)
return ret;
- spin_lock_init(&pctrl->lock);
+ raw_spin_lock_init(&pctrl->lock);
mutex_init(&pctrl->mutex);
platform_set_drvdata(pdev, pctrl);
diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig
index 5f67e1ee66dd..d6a171523012 100644
--- a/drivers/pinctrl/stm32/Kconfig
+++ b/drivers/pinctrl/stm32/Kconfig
@@ -65,6 +65,7 @@ config PINCTRL_STM32_HDP
select PINMUX
select GENERIC_PINCONF
select GPIOLIB
+ select GPIO_GENERIC
help
The Hardware Debug Port allows the observation of internal signals.
It uses configurable multiplexer to route signals in a dedicated observation register.
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 48434292a39b..d3042e0c9712 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -157,6 +157,7 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
const char *pin_name,
const char *func_name)
{
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
int i;
for (i = 0; i < pctl->desc->npins; i++) {
@@ -168,7 +169,7 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
while (func->name) {
if (!strcmp(func->name, func_name) &&
(!func->variant ||
- func->variant & pctl->variant))
+ func->variant & variant))
return func;
func++;
@@ -204,6 +205,34 @@ sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
return NULL;
}
+static struct sunxi_desc_function *
+sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl,
+ const u16 pin_num,
+ const u8 muxval)
+{
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
+
+ for (unsigned int i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ struct sunxi_desc_function *func = pin->functions;
+
+ if (pin->pin.number != pin_num)
+ continue;
+
+ if (pin->variant && !(variant & pin->variant))
+ continue;
+
+ while (func->name) {
+ if (func->muxval == muxval)
+ return func;
+
+ func++;
+ }
+ }
+
+ return NULL;
+}
+
static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
@@ -930,6 +959,30 @@ static const struct pinmux_ops sunxi_pmx_ops = {
.strict = true,
};
+static int sunxi_pinctrl_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
+ const struct sunxi_desc_function *func;
+ u32 pin = offset + chip->base;
+ u32 reg, shift, mask;
+ u8 muxval;
+
+ sunxi_mux_reg(pctl, offset, &reg, &shift, &mask);
+
+ muxval = (readl(pctl->membase + reg) & mask) >> shift;
+
+ func = sunxi_pinctrl_desc_find_function_by_pin_and_mux(pctl, pin, muxval);
+ if (!func)
+ return -ENODEV;
+
+ if (!strcmp(func->name, "gpio_out"))
+ return GPIO_LINE_DIRECTION_OUT;
+ if (!strcmp(func->name, "gpio_in") || !strcmp(func->name, "irq"))
+ return GPIO_LINE_DIRECTION_IN;
+ return -EINVAL;
+}
+
static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
@@ -1039,6 +1092,9 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
{
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
struct sunxi_desc_function *func;
+ unsigned int offset;
+ u32 reg, shift, mask;
+ u8 disabled_mux, muxval;
int ret;
func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
@@ -1046,8 +1102,21 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
if (!func)
return -EINVAL;
- ret = gpiochip_lock_as_irq(pctl->chip,
- pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
+ offset = pctl->irq_array[d->hwirq] - pctl->desc->pin_base;
+ sunxi_mux_reg(pctl, offset, &reg, &shift, &mask);
+ muxval = (readl(pctl->membase + reg) & mask) >> shift;
+
+ /* Change muxing to GPIO INPUT mode if at reset value */
+ if (pctl->flags & SUNXI_PINCTRL_NEW_REG_LAYOUT)
+ disabled_mux = SUN4I_FUNC_DISABLED_NEW;
+ else
+ disabled_mux = SUN4I_FUNC_DISABLED_OLD;
+
+ if (muxval == disabled_mux)
+ sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq],
+ SUN4I_FUNC_INPUT);
+
+ ret = gpiochip_lock_as_irq(pctl->chip, offset);
if (ret) {
dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
irqd_to_hwirq(d));
@@ -1288,6 +1357,7 @@ static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
static int sunxi_pinctrl_build_state(struct platform_device *pdev)
{
struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
void *ptr;
int i;
@@ -1312,7 +1382,7 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
group->name = pin->pin.name;
@@ -1337,11 +1407,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
for (func = pin->functions; func->name; func++) {
- if (func->variant && !(pctl->variant & func->variant))
+ if (func->variant && !(variant & func->variant))
continue;
/* Create interrupt mapping while we're at it */
@@ -1369,14 +1439,14 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
struct sunxi_desc_function *func;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
for (func = pin->functions; func->name; func++) {
struct sunxi_pinctrl_function *func_item;
const char **func_grp;
- if (func->variant && !(pctl->variant & func->variant))
+ if (func->variant && !(variant & func->variant))
continue;
func_item = sunxi_pinctrl_find_function_by_name(pctl,
@@ -1518,7 +1588,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
pctl->dev = &pdev->dev;
pctl->desc = desc;
- pctl->variant = flags & SUNXI_PINCTRL_VARIANT_MASK;
+ pctl->flags = flags;
if (flags & SUNXI_PINCTRL_NEW_REG_LAYOUT) {
pctl->bank_mem_size = D1_BANK_MEM_SIZE;
pctl->pull_regs_offset = D1_PULL_REGS_OFFSET;
@@ -1554,8 +1624,9 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK;
- if (pin->variant && !(pctl->variant & pin->variant))
+ if (pin->variant && !(variant & pin->variant))
continue;
pins[pin_idx++] = pin->pin;
@@ -1599,6 +1670,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
pctl->chip->request = gpiochip_generic_request;
pctl->chip->free = gpiochip_generic_free;
pctl->chip->set_config = gpiochip_generic_config;
+ pctl->chip->get_direction = sunxi_pinctrl_gpio_get_direction;
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input;
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output;
pctl->chip->get = sunxi_pinctrl_gpio_get;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index ad26e4de16a8..0daf7600e2fb 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -86,6 +86,8 @@
#define SUN4I_FUNC_INPUT 0
#define SUN4I_FUNC_IRQ 6
+#define SUN4I_FUNC_DISABLED_OLD 7
+#define SUN4I_FUNC_DISABLED_NEW 15
#define SUNXI_PINCTRL_VARIANT_MASK GENMASK(7, 0)
#define SUNXI_PINCTRL_NEW_REG_LAYOUT BIT(8)
@@ -174,7 +176,7 @@ struct sunxi_pinctrl {
unsigned *irq_array;
raw_spinlock_t lock;
struct pinctrl_dev *pctl_dev;
- unsigned long variant;
+ unsigned long flags;
u32 bank_mem_size;
u32 pull_regs_offset;
u32 dlevel_field_width;
diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c
index fa7b3bda688a..bee271a4fda1 100644
--- a/drivers/platform/olpc/olpc-xo175-ec.c
+++ b/drivers/platform/olpc/olpc-xo175-ec.c
@@ -482,7 +482,7 @@ static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp,
dev_dbg(dev, "CMD %x, %zd bytes expected\n", cmd, resp_len);
if (inlen > 5) {
- dev_err(dev, "command len %zd too big!\n", resp_len);
+ dev_err(dev, "command len %zd too big!\n", inlen);
return -EOVERFLOW;
}
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c
index 19f82c1d3090..631ffc0978d1 100644
--- a/drivers/platform/x86/amd/hsmp/hsmp.c
+++ b/drivers/platform/x86/amd/hsmp/hsmp.c
@@ -117,7 +117,7 @@ static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *ms
}
if (unlikely(mbox_status == HSMP_STATUS_NOT_READY)) {
- dev_err(sock->dev, "Message ID 0x%X failure : SMU tmeout (status = 0x%X)\n",
+ dev_err(sock->dev, "Message ID 0x%X failure : SMU timeout (status = 0x%X)\n",
msg->msg_id, mbox_status);
return -ETIMEDOUT;
} else if (unlikely(mbox_status == HSMP_ERR_INVALID_MSG)) {
diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c
index ed285afaf9b0..24506e342943 100644
--- a/drivers/platform/x86/amd/pmc/pmc-quirks.c
+++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c
@@ -203,6 +203,15 @@ static const struct dmi_system_id fwbug_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "82XQ"),
}
},
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=221273 */
+ {
+ .ident = "Thinkpad L14 Gen3",
+ .driver_data = &quirk_s2idle_bug,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21C6"),
+ }
+ },
/* https://gitlab.freedesktop.org/drm/amd/-/issues/4434 */
{
.ident = "Lenovo Yoga 6 13ALC6",
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index 6e9703bd5017..c30d2b451e01 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -348,6 +348,35 @@ struct power_data {
static const struct dmi_system_id power_limits[] = {
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA401UM"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 31,
+ .ppt_pl2_sppt_max = 44,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "FA401UV"),
},
.driver_data = &(struct power_data) {
@@ -565,6 +594,37 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA607NU"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_def = 54,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 25,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "FA607P"),
},
.driver_data = &(struct power_data) {
@@ -1053,6 +1113,20 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GA503QM"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_def = 35,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_max = 80,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "GA503QR"),
},
.driver_data = &(struct power_data) {
@@ -1268,6 +1342,34 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GU605MU"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 135,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 20,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_tgp_min = 55,
+ .nv_tgp_max = 85,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 38,
+ .ppt_pl2_sppt_max = 53,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
},
.driver_data = &(struct power_data) {
@@ -1335,6 +1437,33 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GV302XU"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 55,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 60,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 35,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "GV302XV"),
},
.driver_data = &(struct power_data) {
@@ -1459,6 +1588,67 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GX650RX"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 70,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_def = 70,
+ .ppt_pl2_sppt_max = 100,
+ .ppt_pl3_fppt_min = 28,
+ .ppt_pl3_fppt_def = 110,
+ .ppt_pl3_fppt_max = 125,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 76,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 50,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 50,
+ .ppt_pl3_fppt_min = 28,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 76,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GZ302EA"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 60,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_def = 75,
+ .ppt_pl2_sppt_max = 92,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_def = 86,
+ .ppt_pl3_fppt_max = 93,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 45,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 32,
+ .ppt_pl2_sppt_def = 52,
+ .ppt_pl2_sppt_max = 92,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_def = 71,
+ .ppt_pl3_fppt_max = 93,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G513I"),
},
.driver_data = &(struct power_data) {
@@ -1537,6 +1727,40 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G614FP"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 30,
+ .ppt_pl1_spl_max = 120,
+ .ppt_pl2_sppt_min = 65,
+ .ppt_pl2_sppt_def = 140,
+ .ppt_pl2_sppt_max = 165,
+ .ppt_pl3_fppt_min = 65,
+ .ppt_pl3_fppt_def = 140,
+ .ppt_pl3_fppt_max = 165,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ .nv_tgp_min = 50,
+ .nv_tgp_max = 100,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 65,
+ .ppt_pl2_sppt_min = 25,
+ .ppt_pl2_sppt_max = 65,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 75,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .requires_fan_curve = true,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G614J"),
},
.driver_data = &(struct power_data) {
@@ -1710,6 +1934,20 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G733QS"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 80,
+ },
+ .requires_fan_curve = false,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G814J"),
},
.driver_data = &(struct power_data) {
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index a38a65f5c550..b4677c5bba5b 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -548,7 +548,7 @@ static const struct dmi_system_id asus_quirks[] = {
.callback = dmi_matched,
.ident = "ASUS ROG Z13",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"),
},
.driver_data = &quirk_asus_z13,
diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c
index e69b50162bb1..d1b4df91401b 100644
--- a/drivers/platform/x86/dell/alienware-wmi-wmax.c
+++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c
@@ -175,7 +175,7 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18"),
},
- .driver_data = &generic_quirks,
+ .driver_data = &g_series_quirks,
},
{
.ident = "Alienware x15",
diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c
index 4eefbade2f5e..e7a411ae9ca1 100644
--- a/drivers/platform/x86/dell/dell-wmi-base.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -80,6 +80,12 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
static const struct key_entry dell_wmi_keymap_type_0000[] = {
{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
+ /* Audio mute toggle */
+ { KE_KEY, 0x0109, { KEY_MUTE } },
+
+ /* Mic mute toggle */
+ { KE_KEY, 0x0150, { KEY_MICMUTE } },
+
/* Meta key lock */
{ KE_IGNORE, 0xe000, { KEY_RIGHTMETA } },
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
index 86ec962aace9..e586f7957946 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
@@ -93,7 +93,6 @@ int set_new_password(const char *password_type, const char *new)
if (ret < 0)
goto out;
- print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
/* on success copy the new password to current password */
if (!ret)
diff --git a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
index 470b9f44ed7a..af4d1920d488 100644
--- a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
+++ b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
@@ -94,8 +94,11 @@ int hp_alloc_enumeration_data(void)
bioscfg_drv.enumeration_instances_count =
hp_get_instance_count(HP_WMI_BIOS_ENUMERATION_GUID);
- bioscfg_drv.enumeration_data = kzalloc_objs(*bioscfg_drv.enumeration_data,
- bioscfg_drv.enumeration_instances_count);
+ if (!bioscfg_drv.enumeration_instances_count)
+ return -EINVAL;
+ bioscfg_drv.enumeration_data = kvcalloc(bioscfg_drv.enumeration_instances_count,
+ sizeof(*bioscfg_drv.enumeration_data), GFP_KERNEL);
+
if (!bioscfg_drv.enumeration_data) {
bioscfg_drv.enumeration_instances_count = 0;
return -ENOMEM;
@@ -444,6 +447,6 @@ void hp_exit_enumeration_attributes(void)
}
bioscfg_drv.enumeration_instances_count = 0;
- kfree(bioscfg_drv.enumeration_data);
+ kvfree(bioscfg_drv.enumeration_data);
bioscfg_drv.enumeration_data = NULL;
}
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 304d9ac63c8a..988a0acc9622 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -120,6 +120,13 @@ static const struct thermal_profile_params omen_v1_thermal_params = {
.ec_tp_offset = HP_VICTUS_S_EC_THERMAL_PROFILE_OFFSET,
};
+static const struct thermal_profile_params omen_v1_legacy_thermal_params = {
+ .performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE,
+ .balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT,
+ .low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT,
+ .ec_tp_offset = HP_OMEN_EC_THERMAL_PROFILE_OFFSET,
+};
+
/*
* A generic pointer for the currently-active board's thermal profile
* parameters.
@@ -146,6 +153,7 @@ static const char * const omen_thermal_profile_boards[] = {
"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
"8A15", "8A42",
"8BAD",
+ "8E41",
};
/* DMI Board names of Omen laptops that are specifically set to be thermal
@@ -166,18 +174,35 @@ static const char * const omen_timed_thermal_profile_boards[] = {
"8BAD",
};
-/* DMI Board names of Victus 16-d1xxx laptops */
+/* DMI Board names of Victus 16-d laptops */
static const char * const victus_thermal_profile_boards[] = {
+ "88F8",
"8A25",
};
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A4D") },
+ .driver_data = (void *)&omen_v1_legacy_thermal_params,
+ },
+ {
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BAB") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BBE") },
.driver_data = (void *)&victus_s_thermal_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCA") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCD") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BD4") },
.driver_data = (void *)&victus_s_thermal_params,
},
@@ -186,6 +211,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst
.driver_data = (void *)&victus_s_thermal_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C76") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") },
.driver_data = (void *)&omen_v1_thermal_params,
},
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 0f8684f4464b..2ddd8af8c1ce 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -136,6 +136,13 @@ static const struct dmi_system_id button_array_table[] = {
},
},
{
+ .ident = "Lenovo ThinkPad X1 Fold 16 Gen 1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"),
+ },
+ },
+ {
.ident = "Microsoft Surface Go 3",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
@@ -189,6 +196,18 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 12 Tablet RA02260"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell 14 Plus 2-in-1 DB04250"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell 16 Plus 2-in-1 DB06250"),
+ },
+ },
{ }
};
@@ -419,6 +438,14 @@ static int intel_hid_pl_suspend_handler(struct device *device)
return 0;
}
+static int intel_hid_pl_freeze_handler(struct device *device)
+{
+ struct intel_hid_priv *priv = dev_get_drvdata(device);
+
+ priv->wakeup_mode = false;
+ return intel_hid_pl_suspend_handler(device);
+}
+
static int intel_hid_pl_resume_handler(struct device *device)
{
intel_hid_pm_complete(device);
@@ -433,7 +460,7 @@ static int intel_hid_pl_resume_handler(struct device *device)
static const struct dev_pm_ops intel_hid_pl_pm_ops = {
.prepare = intel_hid_pm_prepare,
.complete = intel_hid_pm_complete,
- .freeze = intel_hid_pl_suspend_handler,
+ .freeze = intel_hid_pl_freeze_handler,
.thaw = intel_hid_pl_resume_handler,
.restore = intel_hid_pl_resume_handler,
.suspend = intel_hid_pl_suspend_handler,
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 1455d9a7afca..1c65ce87cde0 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -223,6 +223,10 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
*con_id = "avdd";
*gpio_flags = GPIO_ACTIVE_HIGH;
break;
+ case INT3472_GPIO_TYPE_DOVDD:
+ *con_id = "dovdd";
+ *gpio_flags = GPIO_ACTIVE_HIGH;
+ break;
case INT3472_GPIO_TYPE_HANDSHAKE:
*con_id = "dvdd";
*gpio_flags = GPIO_ACTIVE_HIGH;
@@ -251,6 +255,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
* 0x0b Power enable
* 0x0c Clock enable
* 0x0d Privacy LED
+ * 0x10 DOVDD (digital I/O voltage)
* 0x13 Hotplug detect
*
* There are some known platform specific quirks where that does not quite
@@ -332,6 +337,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
case INT3472_GPIO_TYPE_CLK_ENABLE:
case INT3472_GPIO_TYPE_PRIVACY_LED:
case INT3472_GPIO_TYPE_POWER_ENABLE:
+ case INT3472_GPIO_TYPE_DOVDD:
case INT3472_GPIO_TYPE_HANDSHAKE:
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags);
if (IS_ERR(gpio)) {
@@ -356,6 +362,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
case INT3472_GPIO_TYPE_POWER_ENABLE:
second_sensor = int3472->quirks.avdd_second_sensor;
fallthrough;
+ case INT3472_GPIO_TYPE_DOVDD:
case INT3472_GPIO_TYPE_HANDSHAKE:
ret = skl_int3472_register_regulator(int3472, gpio, enable_time_us,
con_id, second_sensor);
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
index b8cdaa233ea9..b804cb753f94 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
@@ -36,7 +36,7 @@
/* Supported SST hardware version by this driver */
#define ISST_MAJOR_VERSION 0
-#define ISST_MINOR_VERSION 2
+#define ISST_MINOR_VERSION 3
/*
* Used to indicate if value read from MMIO needs to get multiplied
@@ -558,6 +558,9 @@ static bool disable_dynamic_sst_features(void)
{
u64 value;
+ if (!static_cpu_has(X86_FEATURE_HWP))
+ return true;
+
rdmsrq(MSR_PM_ENABLE, value);
return !(value & 0x1);
}
@@ -869,7 +872,7 @@ static int isst_if_get_perf_level(void __user *argp)
_read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET,
SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
_read_pp_info("locked", perf_level.locked, SST_PP_STATUS_OFFSET,
- SST_PP_LOCK_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
+ SST_PP_LOCK_START, SST_PP_LOCK_WIDTH, SST_MUL_FACTOR_NONE)
_read_pp_info("feature_state", perf_level.feature_state, SST_PP_STATUS_OFFSET,
SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE)
perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1));
@@ -1458,6 +1461,8 @@ static int isst_if_get_turbo_freq_info(void __user *argp)
SST_MUL_FACTOR_FREQ)
}
+ memset(turbo_freq.bucket_core_counts, 0, sizeof(turbo_freq.bucket_core_counts));
+
if (feature_rev >= 2) {
bool has_tf_info_8 = false;
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
index 1237d9570886..88015a2c6a0d 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
@@ -31,7 +31,7 @@
#include "uncore-frequency-common.h"
#define UNCORE_MAJOR_VERSION 0
-#define UNCORE_MINOR_VERSION 2
+#define UNCORE_MINOR_VERSION 3
#define UNCORE_ELC_SUPPORTED_VERSION 2
#define UNCORE_HEADER_INDEX 0
#define UNCORE_FABRIC_CLUSTER_OFFSET 8
@@ -537,6 +537,7 @@ static void set_cdie_id(int domain_id, struct tpmi_uncore_cluster_info *cluster_
#define UNCORE_VERSION_MASK GENMASK_ULL(7, 0)
#define UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK GENMASK_ULL(15, 8)
#define UNCORE_CLUSTER_OFF_MASK GENMASK_ULL(7, 0)
+#define UNCORE_AUTONOMOUS_UFS_DISABLED BIT(32)
#define UNCORE_MAX_CLUSTER_PER_DOMAIN 8
static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
@@ -598,6 +599,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
for (i = 0; i < num_resources; ++i) {
struct tpmi_uncore_power_domain_info *pd_info;
+ bool auto_ufs_enabled;
struct resource *res;
u64 cluster_offset;
u8 cluster_mask;
@@ -647,6 +649,8 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
continue;
}
+ auto_ufs_enabled = !(header & UNCORE_AUTONOMOUS_UFS_DISABLED);
+
/* Find out number of clusters in this resource */
pd_info->cluster_count = hweight8(cluster_mask);
@@ -689,7 +693,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
cluster_info->uncore_root = tpmi_uncore;
- if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION)
+ if ((TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >=
+ UNCORE_ELC_SUPPORTED_VERSION) &&
+ auto_ufs_enabled)
cluster_info->elc_supported = true;
ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0);
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index f9c736777908..8982d92dfd97 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -9525,14 +9525,16 @@ static int tpacpi_battery_get(int what, int battery, int *ret)
{
switch (what) {
case THRESHOLD_START:
- if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, ret, battery))
+ if (!battery_info.batteries[battery].start_support ||
+ ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, ret, battery)))
return -ENODEV;
/* The value is in the low 8 bits of the response */
*ret = *ret & 0xFF;
return 0;
case THRESHOLD_STOP:
- if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_STOP, ret, battery))
+ if (!battery_info.batteries[battery].stop_support ||
+ ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_STOP, ret, battery)))
return -ENODEV;
/* Value is in lower 8 bits */
*ret = *ret & 0xFF;
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c
index 381836d29a96..c7fe7e3c9f17 100644
--- a/drivers/platform/x86/lenovo/wmi-gamezone.c
+++ b/drivers/platform/x86/lenovo/wmi-gamezone.c
@@ -31,8 +31,6 @@
#define LWMI_GZ_METHOD_ID_SMARTFAN_SET 44
#define LWMI_GZ_METHOD_ID_SMARTFAN_GET 45
-static BLOCKING_NOTIFIER_HEAD(gz_chain_head);
-
struct lwmi_gz_priv {
enum thermal_mode current_mode;
struct notifier_block event_nb;
diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
index 144a454103b9..6d4a53a2ed60 100644
--- a/drivers/platform/x86/oxpec.c
+++ b/drivers/platform/x86/oxpec.c
@@ -11,7 +11,7 @@
*
* Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
* Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com>
- * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
+ * Copyright (C) 2025-2026 Antheas Kapenekakis <lkml@antheas.dev>
*/
#include <linux/acpi.h>
@@ -117,6 +117,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A2 Pro"),
+ },
+ .driver_data = (void *)aok_zoe_a1,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1X"),
},
.driver_data = (void *)oxp_fly,
@@ -145,6 +152,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER APEX"),
+ },
+ .driver_data = (void *)oxp_fly,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"),
},
.driver_data = (void *)oxp_fly,
@@ -215,6 +229,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1z"),
+ },
+ .driver_data = (void *)oxp_x1,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"),
},
.driver_data = (void *)oxp_x1,
@@ -229,6 +250,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Air"),
+ },
+ .driver_data = (void *)oxp_x1,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"),
},
.driver_data = (void *)oxp_x1,
diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c
index 949236b93a32..e5cb348e3a39 100644
--- a/drivers/platform/x86/redmi-wmi.c
+++ b/drivers/platform/x86/redmi-wmi.c
@@ -20,7 +20,10 @@
static const struct key_entry redmi_wmi_keymap[] = {
{KE_KEY, 0x00000201, {KEY_SELECTIVE_SCREENSHOT}},
{KE_KEY, 0x00000301, {KEY_ALL_APPLICATIONS}},
- {KE_KEY, 0x00001b01, {KEY_SETUP}},
+ {KE_KEY, 0x00001b01, {KEY_CONFIG}},
+ {KE_KEY, 0x00011b01, {KEY_CONFIG}},
+ {KE_KEY, 0x00010101, {KEY_SWITCHVIDEOMODE}},
+ {KE_KEY, 0x00001a01, {KEY_REFRESH_RATE_TOGGLE}},
/* AI button has code for each position */
{KE_KEY, 0x00011801, {KEY_ASSISTANT}},
@@ -32,6 +35,26 @@ static const struct key_entry redmi_wmi_keymap[] = {
{KE_IGNORE, 0x00050501, {}},
{KE_IGNORE, 0x000a0501, {}},
+ /* Xiaomi G Command Center */
+ {KE_KEY, 0x00010a01, {KEY_VENDOR}},
+
+ /* OEM preset power mode */
+ {KE_IGNORE, 0x00011601, {}},
+ {KE_IGNORE, 0x00021601, {}},
+ {KE_IGNORE, 0x00031601, {}},
+ {KE_IGNORE, 0x00041601, {}},
+
+ /* Fn Lock state */
+ {KE_IGNORE, 0x00000701, {}},
+ {KE_IGNORE, 0x00010701, {}},
+
+ /* Fn+`/1/2/3/4 */
+ {KE_KEY, 0x00011101, {KEY_F13}},
+ {KE_KEY, 0x00011201, {KEY_F14}},
+ {KE_KEY, 0x00011301, {KEY_F15}},
+ {KE_KEY, 0x00011401, {KEY_F16}},
+ {KE_KEY, 0x00011501, {KEY_F17}},
+
{KE_END}
};
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index bdc19cd8d3ed..d83c387821ea 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -410,6 +410,16 @@ static const struct ts_dmi_data gdix1002_upside_down_data = {
.properties = gdix1001_upside_down_props,
};
+static const struct property_entry gdix1001_y_inverted_props[] = {
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ { }
+};
+
+static const struct ts_dmi_data gdix1001_y_inverted_data = {
+ .acpi_name = "GDIX1001",
+ .properties = gdix1001_y_inverted_props,
+};
+
static const struct property_entry gp_electronic_t701_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
@@ -1659,6 +1669,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* SUPI S10 */
+ .driver_data = (void *)&gdix1001_y_inverted_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SUPI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S10"),
+ },
+ },
+ {
/* Techbite Arc 11.6 */
.driver_data = (void *)&techbite_arc_11_6_data,
.matches = {
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index fee93537aa43..6341dca20b76 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -314,8 +314,8 @@
#define LED_CHANNELS 3
#define LED_MAX_BRIGHTNESS 200
-#define UNIWILL_FEATURE_FN_LOCK_TOGGLE BIT(0)
-#define UNIWILL_FEATURE_SUPER_KEY_TOGGLE BIT(1)
+#define UNIWILL_FEATURE_FN_LOCK BIT(0)
+#define UNIWILL_FEATURE_SUPER_KEY BIT(1)
#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2)
#define UNIWILL_FEATURE_LIGHTBAR BIT(3)
#define UNIWILL_FEATURE_BATTERY BIT(4)
@@ -330,6 +330,7 @@ struct uniwill_data {
struct acpi_battery_hook hook;
unsigned int last_charge_ctrl;
struct mutex battery_lock; /* Protects the list of currently registered batteries */
+ unsigned int last_status;
unsigned int last_switch_status;
struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
struct list_head batteries;
@@ -377,11 +378,15 @@ static const struct key_entry uniwill_keymap[] = {
{ KE_IGNORE, UNIWILL_OSD_CAPSLOCK, { KEY_CAPSLOCK }},
{ KE_IGNORE, UNIWILL_OSD_NUMLOCK, { KEY_NUMLOCK }},
- /* Reported when the user locks/unlocks the super key */
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE, { KEY_UNKNOWN }},
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE, { KEY_UNKNOWN }},
+ /*
+ * Reported when the user enables/disables the super key.
+ * Those events might even be reported when the change was done
+ * using the sysfs attribute!
+ */
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_DISABLE, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_ENABLE, { KEY_UNKNOWN }},
/* Optional, might not be reported by all devices */
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_STATE_CHANGED, { KEY_UNKNOWN }},
/* Reported in manual mode when toggling the airplane mode status */
{ KE_KEY, UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
@@ -401,9 +406,6 @@ static const struct key_entry uniwill_keymap[] = {
/* Reported when the user wants to toggle the mute status */
{ KE_IGNORE, UNIWILL_OSD_MUTE, { KEY_MUTE }},
- /* Reported when the user locks/unlocks the Fn key */
- { KE_IGNORE, UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
-
/* Reported when the user wants to toggle the brightness of the keyboard */
{ KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
@@ -576,6 +578,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
case EC_ADDR_SECOND_FAN_RPM_1:
case EC_ADDR_SECOND_FAN_RPM_2:
case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_BIOS_OEM:
case EC_ADDR_PWM_1:
case EC_ADDR_PWM_2:
case EC_ADDR_TRIGGER:
@@ -600,8 +603,8 @@ static const struct regmap_config uniwill_ec_config = {
.use_single_write = true,
};
-static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -624,8 +627,7 @@ static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_att
return count;
}
-static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -638,10 +640,10 @@ static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attr
return sysfs_emit(buf, "%d\n", !!(value & FN_LOCK_STATUS));
}
-static DEVICE_ATTR_RW(fn_lock_toggle_enable);
+static DEVICE_ATTR_RW(fn_lock);
-static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t super_key_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -673,8 +675,7 @@ static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_a
return count;
}
-static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t super_key_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -687,7 +688,7 @@ static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_at
return sysfs_emit(buf, "%d\n", !(value & SUPER_KEY_LOCK_STATUS));
}
-static DEVICE_ATTR_RW(super_key_toggle_enable);
+static DEVICE_ATTR_RW(super_key_enable);
static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -881,8 +882,8 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
static struct attribute *uniwill_attrs[] = {
/* Keyboard-related */
- &dev_attr_fn_lock_toggle_enable.attr,
- &dev_attr_super_key_toggle_enable.attr,
+ &dev_attr_fn_lock.attr,
+ &dev_attr_super_key_enable.attr,
&dev_attr_touchpad_toggle_enable.attr,
/* Lightbar-related */
&dev_attr_rainbow_animation.attr,
@@ -897,13 +898,13 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
struct device *dev = kobj_to_dev(kobj);
struct uniwill_data *data = dev_get_drvdata(dev);
- if (attr == &dev_attr_fn_lock_toggle_enable.attr) {
- if (uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK_TOGGLE))
+ if (attr == &dev_attr_fn_lock.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
return attr->mode;
}
- if (attr == &dev_attr_super_key_toggle_enable.attr) {
- if (uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (attr == &dev_attr_super_key_enable.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return attr->mode;
}
@@ -1357,6 +1358,9 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
switch (action) {
case UNIWILL_OSD_BATTERY_ALERT:
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY))
+ return NOTIFY_DONE;
+
mutex_lock(&data->battery_lock);
list_for_each_entry(entry, &data->batteries, head) {
power_supply_changed(entry->battery);
@@ -1370,6 +1374,13 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
*/
return NOTIFY_OK;
+ case UNIWILL_OSD_FN_LOCK:
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return NOTIFY_DONE;
+
+ sysfs_notify(&data->dev->kobj, NULL, "fn_lock");
+
+ return NOTIFY_OK;
default:
mutex_lock(&data->input_lock);
sparse_keymap_report_event(data->input_device, action, 1, true);
@@ -1503,9 +1514,21 @@ static void uniwill_shutdown(struct platform_device *pdev)
regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
}
-static int uniwill_suspend_keyboard(struct uniwill_data *data)
+static int uniwill_suspend_fn_lock(struct uniwill_data *data)
{
- if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return 0;
+
+ /*
+ * The EC_ADDR_BIOS_OEM is marked as volatile, so we have to restore it
+ * ourselves.
+ */
+ return regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &data->last_status);
+}
+
+static int uniwill_suspend_super_key(struct uniwill_data *data)
+{
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
/*
@@ -1542,7 +1565,11 @@ static int uniwill_suspend(struct device *dev)
struct uniwill_data *data = dev_get_drvdata(dev);
int ret;
- ret = uniwill_suspend_keyboard(data);
+ ret = uniwill_suspend_fn_lock(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_suspend_super_key(data);
if (ret < 0)
return ret;
@@ -1560,12 +1587,21 @@ static int uniwill_suspend(struct device *dev)
return 0;
}
-static int uniwill_resume_keyboard(struct uniwill_data *data)
+static int uniwill_resume_fn_lock(struct uniwill_data *data)
+{
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return 0;
+
+ return regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS,
+ data->last_status);
+}
+
+static int uniwill_resume_super_key(struct uniwill_data *data)
{
unsigned int value;
int ret;
- if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
@@ -1608,7 +1644,11 @@ static int uniwill_resume(struct device *dev)
if (ret < 0)
return ret;
- ret = uniwill_resume_keyboard(data);
+ ret = uniwill_resume_fn_lock(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_resume_super_key(data);
if (ret < 0)
return ret;
@@ -1643,16 +1683,16 @@ static struct platform_driver uniwill_driver = {
};
static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
- .features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
- UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
UNIWILL_FEATURE_BATTERY |
UNIWILL_FEATURE_HWMON,
};
static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
- .features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
- UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
UNIWILL_FEATURE_LIGHTBAR |
UNIWILL_FEATURE_BATTERY |
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h
index 48783b2e9ffb..fb1910c0f741 100644
--- a/drivers/platform/x86/uniwill/uniwill-wmi.h
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
@@ -64,8 +64,8 @@
#define UNIWILL_OSD_KB_LED_LEVEL3 0x3E
#define UNIWILL_OSD_KB_LED_LEVEL4 0x3F
-#define UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE 0x40
-#define UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE 0x41
+#define UNIWILL_OSD_SUPER_KEY_DISABLE 0x40
+#define UNIWILL_OSD_SUPER_KEY_ENABLE 0x41
#define UNIWILL_OSD_MENU_JP 0x42
@@ -74,7 +74,7 @@
#define UNIWILL_OSD_RFKILL 0xA4
-#define UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED 0xA5
+#define UNIWILL_OSD_SUPER_KEY_STATE_CHANGED 0xA5
#define UNIWILL_OSD_LIGHTBAR_STATE_CHANGED 0xA6
diff --git a/drivers/pmdomain/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c
index 1d29addfe036..eee87a300532 100644
--- a/drivers/pmdomain/bcm/bcm2835-power.c
+++ b/drivers/pmdomain/bcm/bcm2835-power.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/mfd/bcm2835-pm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -153,7 +154,6 @@ struct bcm2835_power {
static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
{
void __iomem *base = power->asb;
- u64 start;
u32 val;
switch (reg) {
@@ -166,8 +166,6 @@ static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable
break;
}
- start = ktime_get_ns();
-
/* Enable the module's async AXI bridges. */
if (enable) {
val = readl(base + reg) & ~ASB_REQ_STOP;
@@ -176,11 +174,9 @@ static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable
}
writel(PM_PASSWORD | val, base + reg);
- while (!!(readl(base + reg) & ASB_ACK) == enable) {
- cpu_relax();
- if (ktime_get_ns() - start >= 1000)
- return -ETIMEDOUT;
- }
+ if (readl_poll_timeout_atomic(base + reg, val,
+ !!(val & ASB_ACK) != enable, 0, 5))
+ return -ETIMEDOUT;
return 0;
}
@@ -580,11 +576,11 @@ static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
switch (id) {
case BCM2835_RESET_V3D:
- return !PM_READ(PM_GRAFX & PM_V3DRSTN);
+ return !(PM_READ(PM_GRAFX) & PM_V3DRSTN);
case BCM2835_RESET_H264:
- return !PM_READ(PM_IMAGE & PM_H264RSTN);
+ return !(PM_READ(PM_IMAGE) & PM_H264RSTN);
case BCM2835_RESET_ISP:
- return !PM_READ(PM_IMAGE & PM_ISPRSTN);
+ return !(PM_READ(PM_IMAGE) & PM_ISPRSTN);
default:
return -EINVAL;
}
diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c
index cff738e4d546..a829f8da5be7 100644
--- a/drivers/pmdomain/imx/gpcv2.c
+++ b/drivers/pmdomain/imx/gpcv2.c
@@ -1416,7 +1416,9 @@ static int imx_pgc_domain_suspend(struct device *dev)
static int imx_pgc_domain_resume(struct device *dev)
{
- return pm_runtime_put(dev);
+ pm_runtime_put(dev);
+
+ return 0;
}
#endif
diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
index 8fc79f9723f0..3f5b9499d30a 100644
--- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
@@ -352,9 +352,6 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
break;
- case IMX8MP_HDMIBLK_PD_HDCP:
- regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
- break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
@@ -408,9 +405,6 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
break;
- case IMX8MP_HDMIBLK_PD_HDCP:
- regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
- break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
@@ -439,7 +433,7 @@ static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
- BIT(0) | BIT(1) | BIT(10));
+ BIT(0) | BIT(1) | BIT(10) | BIT(11));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
/*
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index f64f24d520dd..e2800aa1bc59 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -1203,7 +1203,7 @@ static int scpsys_probe(struct platform_device *pdev)
scpsys->soc_data = soc;
scpsys->pd_data.domains = scpsys->domains;
- scpsys->pd_data.num_domains = soc->num_domains;
+ scpsys->pd_data.num_domains = num_domains;
parent = dev->parent;
if (!parent) {
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index 997e93c12951..44d34840ede7 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -1311,7 +1311,7 @@ static const struct rockchip_domain_info rk3576_pm_domains[] = {
static const struct rockchip_domain_info rk3588_pm_domains[] = {
[RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false, true),
[RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false, true),
- [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, false),
+ [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, true),
[RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false, false),
[RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false, false),
[RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false, false),
diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
index d31a7dd8b35c..dadb4aad9d5d 100644
--- a/drivers/power/sequencing/pwrseq-pcie-m2.c
+++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
@@ -109,7 +109,7 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ctx->of_node = of_node_get(dev->of_node);
+ ctx->of_node = dev_of_node(dev);
ctx->pdata = device_get_match_data(dev);
if (!ctx->pdata)
return dev_err_probe(dev, -ENODEV,
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a708fc63f581..d10b6f9243d5 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -508,7 +508,7 @@ config REGULATOR_FP9931
This driver supports the FP9931/JD9930 voltage regulator chip
which is used to provide power to Electronic Paper Displays
so it is found in E-Book readers.
- If HWWON is enabled, it also provides temperature measurement.
+ If HWMON is enabled, it also provides temperature measurement.
config REGULATOR_LM363X
tristate "TI LM363X voltage regulators"
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index c8f3343cfe23..473beb4399d9 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -785,7 +785,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
},
};
-#define BD72720_BUCK10_DESC_INDEX 10
+#define BD72720_BUCK10_DESC_INDEX 9
#define BD72720_NUM_BUCK_VOLTS 0x100
#define BD72720_NUM_LDO_VOLTS 0x100
#define BD72720_NUM_LDO12346_VOLTS 0x80
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
index fc1ccede4468..dab8f1ab4450 100644
--- a/drivers/regulator/bq257xx-regulator.c
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -115,11 +115,10 @@ static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev)
return;
subchild = of_get_child_by_name(child, pdata->desc.of_match);
+ of_node_put(child);
if (!subchild)
return;
- of_node_put(child);
-
pdata->otg_en_gpio = devm_fwnode_gpiod_get_index(&pdev->dev,
of_fwnode_handle(subchild),
"enable", 0,
diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c
index 7fbcc6327cc6..abea3b69d8a0 100644
--- a/drivers/regulator/fp9931.c
+++ b/drivers/regulator/fp9931.c
@@ -144,13 +144,12 @@ static int fp9931_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
return ret;
ret = regmap_read(data->regmap, FP9931_REG_TMST_VALUE, &val);
- if (ret)
- return ret;
+ if (!ret)
+ *temp = (s8)val * 1000;
pm_runtime_put_autosuspend(data->dev);
- *temp = (s8)val * 1000;
- return 0;
+ return ret;
}
static umode_t fp9931_hwmon_is_visible(const void *data,
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
index 03af5fa53600..0aebcbda0a19 100644
--- a/drivers/regulator/mt6363-regulator.c
+++ b/drivers/regulator/mt6363-regulator.c
@@ -899,10 +899,8 @@ static int mt6363_regulator_probe(struct platform_device *pdev)
"Failed to map IRQ%d\n", info->hwirq);
ret = devm_add_action_or_reset(dev, mt6363_irq_remove, &info->virq);
- if (ret) {
- irq_dispose_mapping(info->hwirq);
+ if (ret)
return ret;
- }
config.driver_data = info;
INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work);
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index 5fa868264250..45d7dc44c2cd 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -1293,6 +1293,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
struct regulator_dev *ldo5;
struct pca9450 *pca9450;
unsigned int device_id, i;
+ const char *type_name;
int ret;
pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL);
@@ -1303,15 +1304,22 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
case PCA9450_TYPE_PCA9450A:
regulator_desc = pca9450a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9450a_regulators);
+ type_name = "pca9450a";
break;
case PCA9450_TYPE_PCA9450BC:
regulator_desc = pca9450bc_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators);
+ type_name = "pca9450bc";
break;
case PCA9450_TYPE_PCA9451A:
+ regulator_desc = pca9451a_regulators;
+ pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators);
+ type_name = "pca9451a";
+ break;
case PCA9450_TYPE_PCA9452:
regulator_desc = pca9451a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators);
+ type_name = "pca9452";
break;
default:
dev_err(&i2c->dev, "Unknown device type");
@@ -1369,7 +1377,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
if (pca9450->irq) {
ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL,
pca9450_irq_handler,
- (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ (IRQF_TRIGGER_LOW | IRQF_ONESHOT),
"pca9450-irq", pca9450);
if (ret != 0)
return dev_err_probe(pca9450->dev, ret, "Failed to request IRQ: %d\n",
@@ -1413,9 +1421,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450_i2c_restart_handler, pca9450))
dev_warn(&i2c->dev, "Failed to register restart handler\n");
- dev_info(&i2c->dev, "%s probed.\n",
- type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
- (type == PCA9450_TYPE_PCA9451A ? "pca9451a" : "pca9450bc"));
+ dev_info(&i2c->dev, "%s probed.\n", type_name);
return 0;
}
diff --git a/drivers/regulator/pf9453-regulator.c b/drivers/regulator/pf9453-regulator.c
index 779a6fdb0574..eed3055d1c1c 100644
--- a/drivers/regulator/pf9453-regulator.c
+++ b/drivers/regulator/pf9453-regulator.c
@@ -809,7 +809,7 @@ static int pf9453_i2c_probe(struct i2c_client *i2c)
}
ret = devm_request_threaded_irq(pf9453->dev, pf9453->irq, NULL, pf9453_irq_handler,
- (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ IRQF_ONESHOT,
"pf9453-irq", pf9453);
if (ret)
return dev_err_probe(pf9453->dev, ret, "Failed to request IRQ: %d\n", pf9453->irq);
diff --git a/drivers/regulator/tps65185.c b/drivers/regulator/tps65185.c
index 3286c9ab33d0..786622d8d598 100644
--- a/drivers/regulator/tps65185.c
+++ b/drivers/regulator/tps65185.c
@@ -332,6 +332,9 @@ static int tps65185_probe(struct i2c_client *client)
int i;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
data->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(data->regmap))
return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index f5f916d67905..8c8ddbf995a4 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -617,7 +617,7 @@ static int imx_rproc_prepare(struct rproc *rproc)
err = of_reserved_mem_region_to_resource(np, i++, &res);
if (err)
- return 0;
+ break;
/*
* Ignore the first memory region which will be used vdev buffer.
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index 4651311aeb07..bb6f6a16d895 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -1592,12 +1592,51 @@ static const struct of_device_id mtk_scp_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_scp_of_match);
+static int __maybe_unused scp_suspend(struct device *dev)
+{
+ struct mtk_scp *scp = dev_get_drvdata(dev);
+ struct rproc *rproc = scp->rproc;
+
+ /*
+ * Only unprepare if the SCP is running and holding the clock.
+ *
+ * Note: `scp_ops` doesn't implement .attach() callback, hence
+ * `rproc->state` can never be RPROC_ATTACHED. Otherwise, it
+ * should also be checked here.
+ */
+ if (rproc->state == RPROC_RUNNING)
+ clk_unprepare(scp->clk);
+ return 0;
+}
+
+static int __maybe_unused scp_resume(struct device *dev)
+{
+ struct mtk_scp *scp = dev_get_drvdata(dev);
+ struct rproc *rproc = scp->rproc;
+
+ /*
+ * Only prepare if the SCP was running and holding the clock.
+ *
+ * Note: `scp_ops` doesn't implement .attach() callback, hence
+ * `rproc->state` can never be RPROC_ATTACHED. Otherwise, it
+ * should also be checked here.
+ */
+ if (rproc->state == RPROC_RUNNING)
+ return clk_prepare(scp->clk);
+ return 0;
+}
+
+static const struct dev_pm_ops scp_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(scp_suspend, scp_resume)
+};
+
static struct platform_driver mtk_scp_driver = {
.probe = scp_probe,
.remove = scp_remove,
.driver = {
.name = "mtk-scp",
.of_match_table = mtk_scp_of_match,
+ .pm = &scp_pm_ops,
},
};
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index cf10e8ecfb8f..3ceec1fd6d99 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -203,7 +203,7 @@ static const struct qmi_elem_info ssctl_shutdown_resp_ei[] = {
};
struct ssctl_subsys_event_req {
- u8 subsys_name_len;
+ u32 subsys_name_len;
char subsys_name[SSCTL_SUBSYS_NAME_LENGTH];
u32 event;
u8 evt_driven_valid;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index ee18bf2e8054..4add9037dbd5 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -537,7 +537,7 @@ static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
wcnss->mem_phys = wcnss->mem_reloc = res.start;
wcnss->mem_size = resource_size(&res);
- wcnss->mem_region = devm_ioremap_resource_wc(wcnss->dev, &res);
+ wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
if (IS_ERR(wcnss->mem_region)) {
dev_err(wcnss->dev, "unable to map memory region: %pR\n", &res);
return PTR_ERR(wcnss->mem_region);
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 1eebc2602187..0666be6b0e88 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -1428,6 +1428,7 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
static int mpam_restore_mbwu_state(void *_ris)
{
int i;
+ u64 val;
struct mon_read mwbu_arg;
struct mpam_msc_ris *ris = _ris;
struct mpam_class *class = ris->vmsc->comp->class;
@@ -1437,6 +1438,7 @@ static int mpam_restore_mbwu_state(void *_ris)
mwbu_arg.ris = ris;
mwbu_arg.ctx = &ris->mbwu_state[i].cfg;
mwbu_arg.type = mpam_msmon_choose_counter(class);
+ mwbu_arg.val = &val;
__ris_msmon_read(&mwbu_arg);
}
diff --git a/drivers/resctrl/test_mpam_devices.c b/drivers/resctrl/test_mpam_devices.c
index 3e8d564a0c64..31871f519729 100644
--- a/drivers/resctrl/test_mpam_devices.c
+++ b/drivers/resctrl/test_mpam_devices.c
@@ -322,9 +322,17 @@ static void test_mpam_enable_merge_features(struct kunit *test)
mutex_unlock(&mpam_list_lock);
}
+static void __test_mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
+{
+ /* Avoid warnings when running with CONFIG_DEBUG_PREEMPT */
+ guard(preempt)();
+
+ mpam_reset_msc_bitmap(msc, reg, wd);
+}
+
static void test_mpam_reset_msc_bitmap(struct kunit *test)
{
- char __iomem *buf = kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
+ char __iomem *buf = (__force char __iomem *)kunit_kzalloc(test, SZ_16K, GFP_KERNEL);
struct mpam_msc fake_msc = {};
u32 *test_result;
@@ -339,33 +347,33 @@ static void test_mpam_reset_msc_bitmap(struct kunit *test)
mutex_init(&fake_msc.part_sel_lock);
mutex_lock(&fake_msc.part_sel_lock);
- test_result = (u32 *)(buf + MPAMCFG_CPBM);
+ test_result = (__force u32 *)(buf + MPAMCFG_CPBM);
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 0);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 0);
KUNIT_EXPECT_EQ(test, test_result[0], 0);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 1);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 1);
KUNIT_EXPECT_EQ(test, test_result[0], 1);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 16);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 16);
KUNIT_EXPECT_EQ(test, test_result[0], 0xffff);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 32);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 32);
KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff);
KUNIT_EXPECT_EQ(test, test_result[1], 0);
test_result[0] = 0;
test_result[1] = 0;
- mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 33);
+ __test_mpam_reset_msc_bitmap(&fake_msc, MPAMCFG_CPBM, 33);
KUNIT_EXPECT_EQ(test, test_result[0], 0xffffffff);
KUNIT_EXPECT_EQ(test, test_result[1], 1);
test_result[0] = 0;
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index fceec45c8afc..352c2360603b 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -856,7 +856,6 @@ static int reset_add_gpio_aux_device(struct device *parent,
ret = __auxiliary_device_add(adev, "reset");
if (ret) {
auxiliary_device_uninit(adev);
- kfree(adev);
return ret;
}
diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
index 32bc268c9149..fd75d9601a3b 100644
--- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c
+++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c
@@ -136,6 +136,9 @@ static int rzg2l_usbphy_ctrl_set_pwrrdy(struct regmap_field *pwrrdy,
{
u32 val = power_on ? 0 : 1;
+ if (!pwrrdy)
+ return 0;
+
/* The initialization path guarantees that the mask is 1 bit long. */
return regmap_field_update_bits(pwrrdy, 1, val);
}
@@ -347,4 +350,4 @@ module_platform_driver(rzg2l_usbphy_ctrl_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Renesas RZ/G2L USBPHY Control");
-MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
diff --git a/drivers/reset/spacemit/reset-spacemit-k3.c b/drivers/reset/spacemit/reset-spacemit-k3.c
index e9e32e4c1ba5..9841f5e057b2 100644
--- a/drivers/reset/spacemit/reset-spacemit-k3.c
+++ b/drivers/reset/spacemit/reset-spacemit-k3.c
@@ -112,16 +112,21 @@ static const struct ccu_reset_data k3_apmu_resets[] = {
[RESET_APMU_SDH0] = RESET_DATA(APMU_SDH0_CLK_RES_CTRL, 0, BIT(1)),
[RESET_APMU_SDH1] = RESET_DATA(APMU_SDH1_CLK_RES_CTRL, 0, BIT(1)),
[RESET_APMU_SDH2] = RESET_DATA(APMU_SDH2_CLK_RES_CTRL, 0, BIT(1)),
- [RESET_APMU_USB2] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0,
- BIT(1)|BIT(2)|BIT(3)),
- [RESET_APMU_USB3_PORTA] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0,
- BIT(5)|BIT(6)|BIT(7)),
- [RESET_APMU_USB3_PORTB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0,
- BIT(9)|BIT(10)|BIT(11)),
- [RESET_APMU_USB3_PORTC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0,
- BIT(13)|BIT(14)|BIT(15)),
- [RESET_APMU_USB3_PORTD] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0,
- BIT(17)|BIT(18)|BIT(19)),
+ [RESET_APMU_USB2_AHB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(1)),
+ [RESET_APMU_USB2_VCC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(2)),
+ [RESET_APMU_USB2_PHY] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(3)),
+ [RESET_APMU_USB3_A_AHB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(5)),
+ [RESET_APMU_USB3_A_VCC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(6)),
+ [RESET_APMU_USB3_A_PHY] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(7)),
+ [RESET_APMU_USB3_B_AHB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(9)),
+ [RESET_APMU_USB3_B_VCC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(10)),
+ [RESET_APMU_USB3_B_PHY] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(11)),
+ [RESET_APMU_USB3_C_AHB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(13)),
+ [RESET_APMU_USB3_C_VCC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(14)),
+ [RESET_APMU_USB3_C_PHY] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(15)),
+ [RESET_APMU_USB3_D_AHB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(17)),
+ [RESET_APMU_USB3_D_VCC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(18)),
+ [RESET_APMU_USB3_D_PHY] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(19)),
[RESET_APMU_QSPI] = RESET_DATA(APMU_QSPI_CLK_RES_CTRL, 0, BIT(1)),
[RESET_APMU_QSPI_BUS] = RESET_DATA(APMU_QSPI_CLK_RES_CTRL, 0, BIT(0)),
[RESET_APMU_DMA] = RESET_DATA(APMU_DMA_CLK_RES_CTRL, 0, BIT(0)),
@@ -151,10 +156,12 @@ static const struct ccu_reset_data k3_apmu_resets[] = {
[RESET_APMU_CPU7_SW] = RESET_DATA(APMU_PMU_CC2_AP, BIT(26), 0),
[RESET_APMU_C1_MPSUB_SW] = RESET_DATA(APMU_PMU_CC2_AP, BIT(28), 0),
[RESET_APMU_MPSUB_DBG] = RESET_DATA(APMU_PMU_CC2_AP, BIT(29), 0),
- [RESET_APMU_UCIE] = RESET_DATA(APMU_UCIE_CTRL,
- BIT(1) | BIT(2) | BIT(3), 0),
- [RESET_APMU_RCPU] = RESET_DATA(APMU_RCPU_CLK_RES_CTRL, 0,
- BIT(3) | BIT(2) | BIT(0)),
+ [RESET_APMU_UCIE_IP] = RESET_DATA(APMU_UCIE_CTRL, BIT(1), 0),
+ [RESET_APMU_UCIE_HOT] = RESET_DATA(APMU_UCIE_CTRL, BIT(2), 0),
+ [RESET_APMU_UCIE_MON] = RESET_DATA(APMU_UCIE_CTRL, BIT(3), 0),
+ [RESET_APMU_RCPU_AUDIO_SYS] = RESET_DATA(APMU_RCPU_CLK_RES_CTRL, 0, BIT(0)),
+ [RESET_APMU_RCPU_MCU_CORE] = RESET_DATA(APMU_RCPU_CLK_RES_CTRL, 0, BIT(2)),
+ [RESET_APMU_RCPU_AUDIO_APMU] = RESET_DATA(APMU_RCPU_CLK_RES_CTRL, 0, BIT(3)),
[RESET_APMU_DSI4LN2_ESCCLK] = RESET_DATA(APMU_LCD_CLK_RES_CTRL3, 0, BIT(3)),
[RESET_APMU_DSI4LN2_LCD_SW] = RESET_DATA(APMU_LCD_CLK_RES_CTRL3, 0, BIT(4)),
[RESET_APMU_DSI4LN2_LCD_MCLK] = RESET_DATA(APMU_LCD_CLK_RES_CTRL4, 0, BIT(9)),
@@ -164,16 +171,21 @@ static const struct ccu_reset_data k3_apmu_resets[] = {
[RESET_APMU_UFS_ACLK] = RESET_DATA(APMU_UFS_CLK_RES_CTRL, 0, BIT(0)),
[RESET_APMU_EDP0] = RESET_DATA(APMU_LCD_EDP_CTRL, 0, BIT(0)),
[RESET_APMU_EDP1] = RESET_DATA(APMU_LCD_EDP_CTRL, 0, BIT(16)),
- [RESET_APMU_PCIE_PORTA] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_A, 0,
- BIT(5) | BIT(4) | BIT(3)),
- [RESET_APMU_PCIE_PORTB] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_B, 0,
- BIT(5) | BIT(4) | BIT(3)),
- [RESET_APMU_PCIE_PORTC] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_C, 0,
- BIT(5) | BIT(4) | BIT(3)),
- [RESET_APMU_PCIE_PORTD] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_D, 0,
- BIT(5) | BIT(4) | BIT(3)),
- [RESET_APMU_PCIE_PORTE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_E, 0,
- BIT(5) | BIT(4) | BIT(3)),
+ [RESET_APMU_PCIE_A_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_A, 0, BIT(3)),
+ [RESET_APMU_PCIE_A_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_A, 0, BIT(4)),
+ [RESET_APMU_PCIE_A_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_A, 0, BIT(5)),
+ [RESET_APMU_PCIE_B_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_B, 0, BIT(3)),
+ [RESET_APMU_PCIE_B_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_B, 0, BIT(4)),
+ [RESET_APMU_PCIE_B_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_B, 0, BIT(5)),
+ [RESET_APMU_PCIE_C_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_C, 0, BIT(3)),
+ [RESET_APMU_PCIE_C_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_C, 0, BIT(4)),
+ [RESET_APMU_PCIE_C_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_C, 0, BIT(5)),
+ [RESET_APMU_PCIE_D_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_D, 0, BIT(3)),
+ [RESET_APMU_PCIE_D_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_D, 0, BIT(4)),
+ [RESET_APMU_PCIE_D_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_D, 0, BIT(5)),
+ [RESET_APMU_PCIE_E_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_E, 0, BIT(3)),
+ [RESET_APMU_PCIE_E_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_E, 0, BIT(4)),
+ [RESET_APMU_PCIE_E_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_E, 0, BIT(5)),
[RESET_APMU_EMAC0] = RESET_DATA(APMU_EMAC0_CLK_RES_CTRL, 0, BIT(1)),
[RESET_APMU_EMAC1] = RESET_DATA(APMU_EMAC1_CLK_RES_CTRL, 0, BIT(1)),
[RESET_APMU_EMAC2] = RESET_DATA(APMU_EMAC2_CLK_RES_CTRL, 0, BIT(1)),
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index cb068d5e2145..14e58c336baa 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6135,6 +6135,7 @@ static void copy_pair_set_active(struct dasd_copy_relation *copy, char *new_busi
static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid,
char *sec_busid)
{
+ struct dasd_eckd_private *prim_priv, *sec_priv;
struct dasd_device *primary, *secondary;
struct dasd_copy_relation *copy;
struct dasd_block *block;
@@ -6155,6 +6156,9 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
if (!secondary)
return DASD_COPYPAIRSWAP_SECONDARY;
+ prim_priv = primary->private;
+ sec_priv = secondary->private;
+
/*
* usually the device should be quiesced for swap
* for paranoia stop device and requeue requests again
@@ -6182,6 +6186,18 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
dev_name(&secondary->cdev->dev), rc);
}
+ if (primary->stopped & DASD_STOPPED_QUIESCE) {
+ dasd_device_set_stop_bits(secondary, DASD_STOPPED_QUIESCE);
+ dasd_device_remove_stop_bits(primary, DASD_STOPPED_QUIESCE);
+ }
+
+ /*
+ * The secondary device never got through format detection, but since it
+ * is a copy of the primary device, the format is exactly the same;
+ * therefore, the detected layout can simply be copied.
+ */
+ sec_priv->uses_cdl = prim_priv->uses_cdl;
+
/* re-enable device */
dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);
dasd_device_remove_stop_bits(secondary, DASD_STOPPED_PPRC);
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index 573bad1d6d86..37a157a1d969 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -1639,11 +1639,13 @@ int cca_get_info(u16 cardnr, u16 domain, struct cca_info *ci, u32 xflags)
memset(ci, 0, sizeof(*ci));
- /* get first info from zcrypt device driver about this apqn */
- rc = zcrypt_device_status_ext(cardnr, domain, &devstat);
- if (rc)
- return rc;
- ci->hwtype = devstat.hwtype;
+ /* if specific domain given, fetch status and hw info for this apqn */
+ if (domain != AUTOSEL_DOM) {
+ rc = zcrypt_device_status_ext(cardnr, domain, &devstat);
+ if (rc)
+ return rc;
+ ci->hwtype = devstat.hwtype;
+ }
/*
* Prep memory for rule array and var array use.
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index e9a984903bff..e7b0ed26a9ec 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -85,8 +85,7 @@ static ssize_t cca_serialnr_show(struct device *dev,
memset(&ci, 0, sizeof(ci));
- if (ap_domain_index >= 0)
- cca_get_info(ac->id, ap_domain_index, &ci, 0);
+ cca_get_info(ac->id, AUTOSEL_DOM, &ci, 0);
return sysfs_emit(buf, "%s\n", ci.serial);
}
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index a0dcab5dc4f2..23a32221e41a 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -953,6 +953,10 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
/*
* The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo request.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
* @zq: pointer to zcrypt_queue structure that identifies the
* CEXxC device to the request distributor
* @mex: pointer to the modexpo request buffer
@@ -964,21 +968,17 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
struct ap_response_type *resp_type = &ap_msg->response;
int rc;
- ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
- ap_msg->bufsize = PAGE_SIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex);
if (rc)
- goto out_free;
+ goto out;
resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
- goto out_free;
+ goto out;
rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
@@ -991,15 +991,17 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
ap_cancel_message(zq->queue, ap_msg);
}
-out_free:
- free_page((unsigned long)ap_msg->msg);
- ap_msg->msg = NULL;
+out:
return rc;
}
/*
* The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo_crt request.
+ * This function assumes that ap_msg has been initialized with
+ * ap_init_apmsg() and thus a valid buffer with the size of
+ * ap_msg->bufsize is available within ap_msg. Also the caller has
+ * to make sure ap_release_apmsg() is always called even on failure.
* @zq: pointer to zcrypt_queue structure that identifies the
* CEXxC device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
@@ -1011,21 +1013,17 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
struct ap_response_type *resp_type = &ap_msg->response;
int rc;
- ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
- if (!ap_msg->msg)
- return -ENOMEM;
- ap_msg->bufsize = PAGE_SIZE;
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt);
if (rc)
- goto out_free;
+ goto out;
resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
init_completion(&resp_type->work);
rc = ap_queue_message(zq->queue, ap_msg);
if (rc)
- goto out_free;
+ goto out;
rc = wait_for_completion_interruptible(&resp_type->work);
if (rc == 0) {
rc = ap_msg->rc;
@@ -1038,9 +1036,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
ap_cancel_message(zq->queue, ap_msg);
}
-out_free:
- free_page((unsigned long)ap_msg->msg);
- ap_msg->msg = NULL;
+out:
return rc;
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 30a9c6612651..c2b082f1252c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -2578,7 +2578,7 @@ int hisi_sas_probe(struct platform_device *pdev,
shost->transportt = hisi_sas_stt;
shost->max_id = HISI_SAS_MAX_DEVICES;
shost->max_lun = ~0;
- shost->max_channel = 1;
+ shost->max_channel = 0;
shost->max_cmd_len = HISI_SAS_MAX_CDB_LEN;
if (hisi_hba->hw->slot_index_alloc) {
shost->can_queue = HISI_SAS_MAX_COMMANDS;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 2f9e01717ef3..f69efc6494b8 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -4993,7 +4993,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
shost->transportt = hisi_sas_stt;
shost->max_id = HISI_SAS_MAX_DEVICES;
shost->max_lun = ~0;
- shost->max_channel = 1;
+ shost->max_channel = 0;
shost->max_cmd_len = HISI_SAS_MAX_CDB_LEN;
shost->can_queue = HISI_SAS_UNRESERVED_IPTT;
shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index a20fce04fe79..3dd2adda195e 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -4966,7 +4966,8 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
switch (mad_status) {
case IBMVFC_MAD_SUCCESS:
ibmvfc_dbg(vhost, "Discover Targets succeeded\n");
- vhost->num_targets = be32_to_cpu(rsp->num_written);
+ vhost->num_targets = min_t(u32, be32_to_cpu(rsp->num_written),
+ max_targets);
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
break;
case IBMVFC_MAD_FAILED:
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 94ad253d65a0..e9d9ac7da485 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -12025,6 +12025,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
iounmap(phba->sli4_hba.conf_regs_memmap_p);
if (phba->sli4_hba.dpp_regs_memmap_p)
iounmap(phba->sli4_hba.dpp_regs_memmap_p);
+ if (phba->sli4_hba.dpp_regs_memmap_wc_p)
+ iounmap(phba->sli4_hba.dpp_regs_memmap_wc_p);
break;
case LPFC_SLI_INTF_IF_TYPE_1:
break;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 1cbfbe44cb7c..303523f754b8 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -15977,6 +15977,32 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
return NULL;
}
+static __maybe_unused void __iomem *
+lpfc_dpp_wc_map(struct lpfc_hba *phba, uint8_t dpp_barset)
+{
+
+ /* DPP region is supposed to cover 64-bit BAR2 */
+ if (dpp_barset != WQ_PCI_BAR_4_AND_5) {
+ lpfc_log_msg(phba, KERN_WARNING, LOG_INIT,
+ "3273 dpp_barset x%x != WQ_PCI_BAR_4_AND_5\n",
+ dpp_barset);
+ return NULL;
+ }
+
+ if (!phba->sli4_hba.dpp_regs_memmap_wc_p) {
+ void __iomem *dpp_map;
+
+ dpp_map = ioremap_wc(phba->pci_bar2_map,
+ pci_resource_len(phba->pcidev,
+ PCI_64BIT_BAR4));
+
+ if (dpp_map)
+ phba->sli4_hba.dpp_regs_memmap_wc_p = dpp_map;
+ }
+
+ return phba->sli4_hba.dpp_regs_memmap_wc_p;
+}
+
/**
* lpfc_modify_hba_eq_delay - Modify Delay Multiplier on EQs
* @phba: HBA structure that EQs are on.
@@ -16940,9 +16966,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
uint8_t dpp_barset;
uint32_t dpp_offset;
uint8_t wq_create_version;
-#ifdef CONFIG_X86
- unsigned long pg_addr;
-#endif
/* sanity check on queue memory */
if (!wq || !cq)
@@ -17128,14 +17151,15 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
#ifdef CONFIG_X86
/* Enable combined writes for DPP aperture */
- pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK;
- rc = set_memory_wc(pg_addr, 1);
- if (rc) {
+ bar_memmap_p = lpfc_dpp_wc_map(phba, dpp_barset);
+ if (!bar_memmap_p) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3272 Cannot setup Combined "
"Write on WQ[%d] - disable DPP\n",
wq->queue_id);
phba->cfg_enable_dpp = 0;
+ } else {
+ wq->dpp_regaddr = bar_memmap_p + dpp_offset;
}
#else
phba->cfg_enable_dpp = 0;
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index ee58383492b2..b6d90604bb61 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -785,6 +785,9 @@ struct lpfc_sli4_hba {
void __iomem *dpp_regs_memmap_p; /* Kernel memory mapped address for
* dpp registers
*/
+ void __iomem *dpp_regs_memmap_wc_p;/* Kernel memory mapped address for
+ * dpp registers with write combining
+ */
union {
struct {
/* IF Type 0, BAR 0 PCI cfg space reg mem map */
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 81150bef1145..c744210cc901 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -1618,6 +1618,7 @@ retry_bring_ioc_ready:
ioc_info(mrioc,
"successfully transitioned to %s state\n",
mpi3mr_iocstate_name(ioc_state));
+ mpi3mr_clear_reset_history(mrioc);
return 0;
}
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
@@ -1637,6 +1638,15 @@ retry_bring_ioc_ready:
elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
} while (elapsed_time_sec < mrioc->ready_timeout);
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state == MRIOC_STATE_READY) {
+ ioc_info(mrioc,
+ "successfully transitioned to %s state after %llu seconds\n",
+ mpi3mr_iocstate_name(ioc_state), elapsed_time_sec);
+ mpi3mr_clear_reset_history(mrioc);
+ return 0;
+ }
+
out_failed:
elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
if ((retry < 2) && (elapsed_time_sec < (mrioc->ready_timeout - 60))) {
@@ -4807,21 +4817,25 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
}
for (i = 0; i < mrioc->num_queues; i++) {
- mrioc->op_reply_qinfo[i].qid = 0;
- mrioc->op_reply_qinfo[i].ci = 0;
- mrioc->op_reply_qinfo[i].num_replies = 0;
- mrioc->op_reply_qinfo[i].ephase = 0;
- atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
- atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
- mpi3mr_memset_op_reply_q_buffers(mrioc, i);
-
- mrioc->req_qinfo[i].ci = 0;
- mrioc->req_qinfo[i].pi = 0;
- mrioc->req_qinfo[i].num_requests = 0;
- mrioc->req_qinfo[i].qid = 0;
- mrioc->req_qinfo[i].reply_qid = 0;
- spin_lock_init(&mrioc->req_qinfo[i].q_lock);
- mpi3mr_memset_op_req_q_buffers(mrioc, i);
+ if (mrioc->op_reply_qinfo) {
+ mrioc->op_reply_qinfo[i].qid = 0;
+ mrioc->op_reply_qinfo[i].ci = 0;
+ mrioc->op_reply_qinfo[i].num_replies = 0;
+ mrioc->op_reply_qinfo[i].ephase = 0;
+ atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0);
+ atomic_set(&mrioc->op_reply_qinfo[i].in_use, 0);
+ mpi3mr_memset_op_reply_q_buffers(mrioc, i);
+ }
+
+ if (mrioc->req_qinfo) {
+ mrioc->req_qinfo[i].ci = 0;
+ mrioc->req_qinfo[i].pi = 0;
+ mrioc->req_qinfo[i].num_requests = 0;
+ mrioc->req_qinfo[i].qid = 0;
+ mrioc->req_qinfo[i].reply_qid = 0;
+ spin_lock_init(&mrioc->req_qinfo[i].q_lock);
+ mpi3mr_memset_op_req_q_buffers(mrioc, i);
+ }
}
atomic_set(&mrioc->pend_large_data_sz, 0);
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 6a8d35aea93a..645524f3fe2d 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -525,8 +525,9 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags)
} else {
task->task_done(task);
}
- rc = -ENODEV;
- goto err_out;
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ pm8001_dbg(pm8001_ha, IO, "pm8001_task_exec device gone\n");
+ return 0;
}
ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, task);
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 9038f6723444..dbe3cd4e274c 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2751,7 +2751,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
if (!elsio->u.els_logo.els_logo_pyld) {
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- qla2x00_free_fcport(fcport);
return QLA_FUNCTION_FAILED;
}
@@ -2776,7 +2775,6 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
if (rval != QLA_SUCCESS) {
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- qla2x00_free_fcport(fcport);
return QLA_FUNCTION_FAILED;
}
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 0dada89d8d99..68a992494b12 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -190,7 +190,7 @@ static struct {
{"IBM", "2076", NULL, BLIST_NO_VPD_SIZE},
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
- {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN},
+ {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN | BLIST_SKIP_IO_HINTS},
{"IOMEGA", "Io20S *F", NULL, BLIST_KEY},
{"INSITE", "Floptical F*8I", NULL, BLIST_KEY},
{"INSITE", "I325VM", NULL, BLIST_KEY},
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 60c06fa4ec32..7b11bc7de0e3 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -360,11 +360,8 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
* default device queue depth to figure out sbitmap shift
* since we use this queue depth most of times.
*/
- if (scsi_realloc_sdev_budget_map(sdev, depth)) {
- put_device(&starget->dev);
- kfree(sdev);
- goto out;
- }
+ if (scsi_realloc_sdev_budget_map(sdev, depth))
+ goto out_device_destroy;
scsi_change_queue_depth(sdev, depth);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 12124f9d5ccd..13412702188e 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1734,7 +1734,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
break;
default:
- if (channel < shost->max_channel) {
+ if (channel <= shost->max_channel) {
res = scsi_scan_host_selected(shost, channel, id, lun,
SCSI_SCAN_MANUAL);
} else {
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 35101e9b7ba7..4c348645b04e 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -215,7 +215,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
unsigned char *type_ptr = ses_dev->page1_types;
unsigned char *desc_ptr = ses_dev->page2 + 8;
- if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0)
+ if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len))
return NULL;
for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
@@ -528,9 +528,8 @@ struct efd {
};
static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
- void *data)
+ struct efd *efd)
{
- struct efd *efd = data;
int i;
struct ses_component *scomp;
@@ -683,7 +682,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
if (efd.addr) {
efd.dev = &sdev->sdev_gendev;
- enclosure_for_each_device(ses_enclosure_find_by_addr, &efd);
+ ses_enclosure_find_by_addr(edev, &efd);
}
}
diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c
index c692de061f29..ed7771e62854 100644
--- a/drivers/scsi/snic/vnic_dev.c
+++ b/drivers/scsi/snic/vnic_dev.c
@@ -42,8 +42,6 @@ struct vnic_dev {
struct vnic_devcmd_notify *notify;
struct vnic_devcmd_notify notify_copy;
dma_addr_t notify_pa;
- u32 *linkstatus;
- dma_addr_t linkstatus_pa;
struct vnic_stats *stats;
dma_addr_t stats_pa;
struct vnic_devcmd_fw_info *fw_info;
@@ -650,8 +648,6 @@ int svnic_dev_init(struct vnic_dev *vdev, int arg)
int svnic_dev_link_status(struct vnic_dev *vdev)
{
- if (vdev->linkstatus)
- return *vdev->linkstatus;
if (!vnic_dev_notify_ready(vdev))
return 0;
@@ -686,11 +682,6 @@ void svnic_dev_unregister(struct vnic_dev *vdev)
sizeof(struct vnic_devcmd_notify),
vdev->notify,
vdev->notify_pa);
- if (vdev->linkstatus)
- dma_free_coherent(&vdev->pdev->dev,
- sizeof(u32),
- vdev->linkstatus,
- vdev->linkstatus_pa);
if (vdev->stats)
dma_free_coherent(&vdev->pdev->dev,
sizeof(struct vnic_stats),
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 664ad55728b5..ae1abab97835 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1856,8 +1856,9 @@ static enum scsi_qc_status storvsc_queuecommand(struct Scsi_Host *host,
cmd_request->payload_sz = payload_sz;
/* Invokes the vsc to start an IO */
- ret = storvsc_do_io(dev, cmd_request, get_cpu());
- put_cpu();
+ migrate_disable();
+ ret = storvsc_do_io(dev, cmd_request, smp_processor_id());
+ migrate_enable();
if (ret)
scsi_dma_unmap(scmnd);
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
index 42cde0017f12..989bcaee42ca 100644
--- a/drivers/scsi/xen-scsifront.c
+++ b/drivers/scsi/xen-scsifront.c
@@ -1175,7 +1175,7 @@ static void scsifront_backend_changed(struct xenbus_device *dev,
return;
}
- if (xenbus_read_driver_state(dev->nodename) ==
+ if (xenbus_read_driver_state(dev, dev->nodename) ==
XenbusStateInitialised)
scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 9aa7218b4e8d..1ed6be6e85d2 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1535,10 +1535,8 @@ static int of_qcom_slim_ngd_register(struct device *parent,
ngd->id = id;
ngd->pdev->dev.parent = parent;
- ret = driver_set_override(&ngd->pdev->dev,
- &ngd->pdev->driver_override,
- QCOM_SLIM_NGD_DRV_NAME,
- strlen(QCOM_SLIM_NGD_DRV_NAME));
+ ret = device_set_driver_override(&ngd->pdev->dev,
+ QCOM_SLIM_NGD_DRV_NAME);
if (ret) {
platform_device_put(ngd->pdev);
kfree(ngd);
diff --git a/drivers/soc/aspeed/aspeed-socinfo.c b/drivers/soc/aspeed/aspeed-socinfo.c
index 5e34e01ad26d..fb8fde94b651 100644
--- a/drivers/soc/aspeed/aspeed-socinfo.c
+++ b/drivers/soc/aspeed/aspeed-socinfo.c
@@ -39,7 +39,7 @@ static const char *siliconid_to_name(u32 siliconid)
unsigned int i;
for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) {
- if (rev_table[i].id == id)
+ if ((rev_table[i].id & 0xff00ffff) == id)
return rev_table[i].name;
}
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 411381f1a1c4..9ddafcb18f1c 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1827,6 +1827,8 @@ EXPORT_SYMBOL(qman_create_fq);
void qman_destroy_fq(struct qman_fq *fq)
{
+ int leaked;
+
/*
* We don't need to lock the FQ as it is a pre-condition that the FQ be
* quiesced. Instead, run some checks.
@@ -1834,11 +1836,29 @@ void qman_destroy_fq(struct qman_fq *fq)
switch (fq->state) {
case qman_fq_state_parked:
case qman_fq_state_oos:
- if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
- qman_release_fqid(fq->fqid);
+ /*
+ * There's a race condition here on releasing the fqid,
+ * setting the fq_table to NULL, and freeing the fqid.
+ * To prevent it, this order should be respected:
+ */
+ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) {
+ leaked = qman_shutdown_fq(fq->fqid);
+ if (leaked)
+ pr_debug("FQID %d leaked\n", fq->fqid);
+ }
DPAA_ASSERT(fq_table[fq->idx]);
fq_table[fq->idx] = NULL;
+
+ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID) && !leaked) {
+ /*
+ * fq_table[fq->idx] should be set to null before
+ * freeing fq->fqid otherwise it could by allocated by
+ * qman_alloc_fqid() while still being !NULL
+ */
+ smp_wmb();
+ gen_pool_free(qm_fqalloc, fq->fqid | DPAA_GENALLOC_OFF, 1);
+ }
return;
default:
break;
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
index c4587b32a59b..672adff8e35f 100644
--- a/drivers/soc/fsl/qe/qmc.c
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -1790,8 +1790,8 @@ static int qmc_qe_init_resources(struct qmc *qmc, struct platform_device *pdev)
return -EINVAL;
qmc->dpram_offset = res->start - qe_muram_dma(qe_muram_addr(0));
qmc->dpram = devm_ioremap_resource(qmc->dev, res);
- if (IS_ERR(qmc->scc_pram))
- return PTR_ERR(qmc->scc_pram);
+ if (IS_ERR(qmc->dpram))
+ return PTR_ERR(qmc->dpram);
return 0;
}
diff --git a/drivers/soc/microchip/mpfs-control-scb.c b/drivers/soc/microchip/mpfs-control-scb.c
index f0b84b1f49cb..8dda5704a389 100644
--- a/drivers/soc/microchip/mpfs-control-scb.c
+++ b/drivers/soc/microchip/mpfs-control-scb.c
@@ -14,8 +14,10 @@ static int mpfs_control_scb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- return mfd_add_devices(dev, PLATFORM_DEVID_NONE, mpfs_control_scb_devs,
- ARRAY_SIZE(mpfs_control_scb_devs), NULL, 0, NULL);
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ mpfs_control_scb_devs,
+ ARRAY_SIZE(mpfs_control_scb_devs), NULL, 0,
+ NULL);
}
static const struct of_device_id mpfs_control_scb_of_match[] = {
diff --git a/drivers/soc/microchip/mpfs-mss-top-sysreg.c b/drivers/soc/microchip/mpfs-mss-top-sysreg.c
index b2244e44ff0f..b0f42b8dd3ed 100644
--- a/drivers/soc/microchip/mpfs-mss-top-sysreg.c
+++ b/drivers/soc/microchip/mpfs-mss-top-sysreg.c
@@ -16,8 +16,10 @@ static int mpfs_mss_top_sysreg_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int ret;
- ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, mpfs_mss_top_sysreg_devs,
- ARRAY_SIZE(mpfs_mss_top_sysreg_devs) , NULL, 0, NULL);
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ mpfs_mss_top_sysreg_devs,
+ ARRAY_SIZE(mpfs_mss_top_sysreg_devs), NULL,
+ 0, NULL);
if (ret)
return ret;
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 8e7ae3cb92ff..10b2fc39da66 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -142,8 +142,10 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev)
sys_controller->flash = of_get_mtd_device_by_node(np);
of_node_put(np);
- if (IS_ERR(sys_controller->flash))
- return dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");
+ if (IS_ERR(sys_controller->flash)) {
+ ret = dev_err_probe(dev, PTR_ERR(sys_controller->flash), "Failed to get flash\n");
+ goto out_free;
+ }
no_flash:
sys_controller->client.dev = dev;
@@ -155,8 +157,7 @@ no_flash:
if (IS_ERR(sys_controller->chan)) {
ret = dev_err_probe(dev, PTR_ERR(sys_controller->chan),
"Failed to get mbox channel\n");
- kfree(sys_controller);
- return ret;
+ goto out_free;
}
init_completion(&sys_controller->c);
@@ -174,6 +175,10 @@ no_flash:
dev_info(&pdev->dev, "Registered MPFS system controller\n");
return 0;
+
+out_free:
+ kfree(sys_controller);
+ return ret;
}
static void mpfs_sys_controller_remove(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
index 039508c1bbf7..047c0160b617 100644
--- a/drivers/soc/qcom/pdr_internal.h
+++ b/drivers/soc/qcom/pdr_internal.h
@@ -84,7 +84,7 @@ struct servreg_set_ack_resp {
struct servreg_loc_pfr_req {
char service[SERVREG_NAME_LENGTH + 1];
- char reason[257];
+ char reason[SERVREG_PFR_LENGTH + 1];
};
struct servreg_loc_pfr_resp {
diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
index d0afdcb96ee1..619bad2c27ee 100644
--- a/drivers/soc/qcom/pmic_glink_altmode.c
+++ b/drivers/soc/qcom/pmic_glink_altmode.c
@@ -62,6 +62,9 @@ struct usbc_notify {
u8 orientation;
u8 mux_ctrl;
#define MUX_CTRL_STATE_NO_CONN 0
+#define MUX_CTRL_STATE_USB3_ONLY 1
+#define MUX_CTRL_STATE_DP4LN 2
+#define MUX_CTRL_STATE_USB3_DP 3
#define MUX_CTRL_STATE_TUNNELING 4
u8 res;
@@ -350,15 +353,20 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
typec_switch_set(alt_port->typec_switch, alt_port->orientation);
- if (alt_port->mux_ctrl == MUX_CTRL_STATE_NO_CONN) {
- pmic_glink_altmode_safe(altmode, alt_port);
- } else if (alt_port->svid == USB_TYPEC_TBT_SID) {
- pmic_glink_altmode_enable_tbt(altmode, alt_port);
- } else if (alt_port->svid == USB_TYPEC_DP_SID) {
- pmic_glink_altmode_enable_dp(altmode, alt_port,
- alt_port->mode,
- alt_port->hpd_state,
- alt_port->hpd_irq);
+ /*
+ * MUX_CTRL_STATE_DP4LN/USB3_DP may only be set if SVID=DP, but we need
+ * to special-case the SVID=DP && mux_ctrl=NO_CONN case to deliver a
+ * HPD notification
+ */
+ if (alt_port->svid == USB_TYPEC_DP_SID) {
+ if (alt_port->mux_ctrl == MUX_CTRL_STATE_NO_CONN) {
+ pmic_glink_altmode_safe(altmode, alt_port);
+ } else {
+ pmic_glink_altmode_enable_dp(altmode, alt_port,
+ alt_port->mode,
+ alt_port->hpd_state,
+ alt_port->hpd_irq);
+ }
if (alt_port->hpd_state)
conn_status = connector_status_connected;
@@ -367,9 +375,18 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, conn_status);
} else if (alt_port->mux_ctrl == MUX_CTRL_STATE_TUNNELING) {
- pmic_glink_altmode_enable_usb4(altmode, alt_port);
- } else {
+ if (alt_port->svid == USB_TYPEC_TBT_SID)
+ pmic_glink_altmode_enable_tbt(altmode, alt_port);
+ else
+ pmic_glink_altmode_enable_usb4(altmode, alt_port);
+ } else if (alt_port->mux_ctrl == MUX_CTRL_STATE_USB3_ONLY) {
pmic_glink_altmode_enable_usb(altmode, alt_port);
+ } else if (alt_port->mux_ctrl == MUX_CTRL_STATE_NO_CONN) {
+ pmic_glink_altmode_safe(altmode, alt_port);
+ } else {
+ dev_err(altmode->dev, "Got unknown mux_ctrl: %u on port %u, forcing safe mode\n",
+ alt_port->mux_ctrl, alt_port->index);
+ pmic_glink_altmode_safe(altmode, alt_port);
}
pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c
index ca98932140d8..02022b11ecf0 100644
--- a/drivers/soc/qcom/qcom_pdr_msg.c
+++ b/drivers/soc/qcom/qcom_pdr_msg.c
@@ -325,7 +325,7 @@ const struct qmi_elem_info servreg_loc_pfr_req_ei[] = {
},
{
.data_type = QMI_STRING,
- .elem_len = SERVREG_NAME_LENGTH + 1,
+ .elem_len = SERVREG_PFR_LENGTH + 1,
.elem_size = sizeof(char),
.array_type = VAR_LEN_ARRAY,
.tlv_type = 0x02,
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
index 04937c40da47..b459607c118a 100644
--- a/drivers/soc/rockchip/grf.c
+++ b/drivers/soc/rockchip/grf.c
@@ -231,6 +231,7 @@ static int __init rockchip_grf_init(void)
grf = syscon_node_to_regmap(np);
if (IS_ERR(grf)) {
pr_err("%s: could not get grf syscon\n", __func__);
+ of_node_put(np);
return PTR_ERR(grf);
}
diff --git a/drivers/spi/spi-amlogic-spifc-a4.c b/drivers/spi/spi-amlogic-spifc-a4.c
index 2aef528cfc1b..16346f50c7d9 100644
--- a/drivers/spi/spi-amlogic-spifc-a4.c
+++ b/drivers/spi/spi-amlogic-spifc-a4.c
@@ -411,7 +411,7 @@ static int aml_sfc_dma_buffer_setup(struct aml_sfc *sfc, void *databuf,
ret = dma_mapping_error(sfc->dev, sfc->daddr);
if (ret) {
dev_err(sfc->dev, "DMA mapping error\n");
- goto out_map_data;
+ return ret;
}
cmd = CMD_DATA_ADDRL(sfc->daddr);
@@ -429,7 +429,6 @@ static int aml_sfc_dma_buffer_setup(struct aml_sfc *sfc, void *databuf,
ret = dma_mapping_error(sfc->dev, sfc->iaddr);
if (ret) {
dev_err(sfc->dev, "DMA mapping error\n");
- dma_unmap_single(sfc->dev, sfc->daddr, datalen, dir);
goto out_map_data;
}
@@ -448,7 +447,7 @@ static int aml_sfc_dma_buffer_setup(struct aml_sfc *sfc, void *databuf,
return 0;
out_map_info:
- dma_unmap_single(sfc->dev, sfc->iaddr, datalen, dir);
+ dma_unmap_single(sfc->dev, sfc->iaddr, infolen, dir);
out_map_data:
dma_unmap_single(sfc->dev, sfc->daddr, datalen, dir);
@@ -1067,6 +1066,13 @@ static const struct nand_ecc_engine_ops aml_sfc_ecc_engine_ops = {
.finish_io_req = aml_sfc_ecc_finish_io_req,
};
+static void aml_sfc_unregister_ecc_engine(void *data)
+{
+ struct nand_ecc_engine *eng = data;
+
+ nand_ecc_unregister_on_host_hw_engine(eng);
+}
+
static int aml_sfc_clk_init(struct aml_sfc *sfc)
{
sfc->gate_clk = devm_clk_get_enabled(sfc->dev, "gate");
@@ -1084,14 +1090,6 @@ static int aml_sfc_clk_init(struct aml_sfc *sfc)
return clk_set_rate(sfc->core_clk, SFC_BUS_DEFAULT_CLK);
}
-static int aml_sfc_disable_clk(struct aml_sfc *sfc)
-{
- clk_disable_unprepare(sfc->core_clk);
- clk_disable_unprepare(sfc->gate_clk);
-
- return 0;
-}
-
static int aml_sfc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1142,16 +1140,12 @@ static int aml_sfc_probe(struct platform_device *pdev)
/* Enable Amlogic flash controller spi mode */
ret = regmap_write(sfc->regmap_base, SFC_SPI_CFG, SPI_MODE_EN);
- if (ret) {
- dev_err(dev, "failed to enable SPI mode\n");
- goto err_out;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable SPI mode\n");
ret = dma_set_mask(sfc->dev, DMA_BIT_MASK(32));
- if (ret) {
- dev_err(sfc->dev, "failed to set dma mask\n");
- goto err_out;
- }
+ if (ret)
+ return dev_err_probe(sfc->dev, ret, "failed to set dma mask\n");
sfc->ecc_eng.dev = &pdev->dev;
sfc->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
@@ -1159,10 +1153,13 @@ static int aml_sfc_probe(struct platform_device *pdev)
sfc->ecc_eng.priv = sfc;
ret = nand_ecc_register_on_host_hw_engine(&sfc->ecc_eng);
- if (ret) {
- dev_err(&pdev->dev, "failed to register Aml host ecc engine.\n");
- goto err_out;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to register Aml host ecc engine.\n");
+
+ ret = devm_add_action_or_reset(dev, aml_sfc_unregister_ecc_engine,
+ &sfc->ecc_eng);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add ECC unregister action\n");
ret = of_property_read_u32(np, "amlogic,rx-adj", &val);
if (!ret)
@@ -1178,24 +1175,7 @@ static int aml_sfc_probe(struct platform_device *pdev)
ctrl->min_speed_hz = SFC_MIN_FREQUENCY;
ctrl->num_chipselect = SFC_MAX_CS_NUM;
- ret = devm_spi_register_controller(dev, ctrl);
- if (ret)
- goto err_out;
-
- return 0;
-
-err_out:
- aml_sfc_disable_clk(sfc);
-
- return ret;
-}
-
-static void aml_sfc_remove(struct platform_device *pdev)
-{
- struct spi_controller *ctlr = platform_get_drvdata(pdev);
- struct aml_sfc *sfc = spi_controller_get_devdata(ctlr);
-
- aml_sfc_disable_clk(sfc);
+ return devm_spi_register_controller(dev, ctrl);
}
static const struct of_device_id aml_sfc_of_match[] = {
@@ -1213,7 +1193,6 @@ static struct platform_driver aml_sfc_driver = {
.of_match_table = aml_sfc_of_match,
},
.probe = aml_sfc_probe,
- .remove = aml_sfc_remove,
};
module_platform_driver(aml_sfc_driver);
diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c
index 1509df2b17ae..9d568e385f05 100644
--- a/drivers/spi/spi-amlogic-spisg.c
+++ b/drivers/spi/spi-amlogic-spisg.c
@@ -729,9 +729,9 @@ static int aml_spisg_probe(struct platform_device *pdev)
};
if (of_property_read_bool(dev->of_node, "spi-slave"))
- ctlr = spi_alloc_target(dev, sizeof(*spisg));
+ ctlr = devm_spi_alloc_target(dev, sizeof(*spisg));
else
- ctlr = spi_alloc_host(dev, sizeof(*spisg));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*spisg));
if (!ctlr)
return -ENOMEM;
@@ -750,10 +750,8 @@ static int aml_spisg_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(spisg->map), "regmap init failed\n");
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto out_controller;
- }
+ if (irq < 0)
+ return irq;
ret = device_reset_optional(dev);
if (ret)
@@ -817,8 +815,6 @@ out_clk:
if (spisg->core)
clk_disable_unprepare(spisg->core);
clk_disable_unprepare(spisg->pclk);
-out_controller:
- spi_controller_put(ctlr);
return ret;
}
diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c
index 60a37ff5c6f5..2665f31a49ce 100644
--- a/drivers/spi/spi-atcspi200.c
+++ b/drivers/spi/spi-atcspi200.c
@@ -195,7 +195,15 @@ static void atcspi_set_trans_ctl(struct atcspi_dev *spi,
if (op->addr.buswidth > 1)
tc |= TRANS_ADDR_FMT;
if (op->data.nbytes) {
- tc |= TRANS_DUAL_QUAD(ffs(op->data.buswidth) - 1);
+ unsigned int width_code;
+
+ width_code = ffs(op->data.buswidth) - 1;
+ if (unlikely(width_code > 3)) {
+ WARN_ON_ONCE(1);
+ width_code = 0;
+ }
+ tc |= TRANS_DUAL_QUAD(width_code);
+
if (op->data.dir == SPI_MEM_DATA_IN) {
if (op->dummy.nbytes)
tc |= TRANS_MODE_DMY_READ |
@@ -497,31 +505,17 @@ static int atcspi_init_resources(struct platform_device *pdev,
static int atcspi_configure_dma(struct atcspi_dev *spi)
{
- struct dma_chan *dma_chan;
- int ret = 0;
+ spi->host->dma_rx = devm_dma_request_chan(spi->dev, "rx");
+ if (IS_ERR(spi->host->dma_rx))
+ return PTR_ERR(spi->host->dma_rx);
- dma_chan = devm_dma_request_chan(spi->dev, "rx");
- if (IS_ERR(dma_chan)) {
- ret = PTR_ERR(dma_chan);
- goto err_exit;
- }
- spi->host->dma_rx = dma_chan;
+ spi->host->dma_tx = devm_dma_request_chan(spi->dev, "tx");
+ if (IS_ERR(spi->host->dma_tx))
+ return PTR_ERR(spi->host->dma_tx);
- dma_chan = devm_dma_request_chan(spi->dev, "tx");
- if (IS_ERR(dma_chan)) {
- ret = PTR_ERR(dma_chan);
- goto free_rx;
- }
- spi->host->dma_tx = dma_chan;
init_completion(&spi->dma_completion);
- return ret;
-
-free_rx:
- dma_release_channel(spi->host->dma_rx);
- spi->host->dma_rx = NULL;
-err_exit:
- return ret;
+ return 0;
}
static int atcspi_enable_clk(struct atcspi_dev *spi)
diff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c
index 8cea81432c5b..8ddcd27def22 100644
--- a/drivers/spi/spi-axiado.c
+++ b/drivers/spi/spi-axiado.c
@@ -765,30 +765,22 @@ static int ax_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctlr);
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(xspi->regs)) {
- ret = PTR_ERR(xspi->regs);
- goto remove_ctlr;
- }
+ if (IS_ERR(xspi->regs))
+ return PTR_ERR(xspi->regs);
xspi->pclk = devm_clk_get(&pdev->dev, "pclk");
- if (IS_ERR(xspi->pclk)) {
- dev_err(&pdev->dev, "pclk clock not found.\n");
- ret = PTR_ERR(xspi->pclk);
- goto remove_ctlr;
- }
+ if (IS_ERR(xspi->pclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(xspi->pclk),
+ "pclk clock not found.\n");
xspi->ref_clk = devm_clk_get(&pdev->dev, "ref");
- if (IS_ERR(xspi->ref_clk)) {
- dev_err(&pdev->dev, "ref clock not found.\n");
- ret = PTR_ERR(xspi->ref_clk);
- goto remove_ctlr;
- }
+ if (IS_ERR(xspi->ref_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(xspi->ref_clk),
+ "ref clock not found.\n");
ret = clk_prepare_enable(xspi->pclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable APB clock.\n");
- goto remove_ctlr;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Unable to enable APB clock.\n");
ret = clk_prepare_enable(xspi->ref_clk);
if (ret) {
@@ -869,8 +861,7 @@ clk_dis_all:
clk_disable_unprepare(xspi->ref_clk);
clk_dis_apb:
clk_disable_unprepare(xspi->pclk);
-remove_ctlr:
- spi_controller_put(ctlr);
+
return ret;
}
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 649ff55333f0..2ead419e896e 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -76,6 +76,11 @@ struct cqspi_flash_pdata {
u8 cs;
};
+static const struct clk_bulk_data cqspi_clks[CLK_QSPI_NUM] = {
+ [CLK_QSPI_APB] = { .id = "apb" },
+ [CLK_QSPI_AHB] = { .id = "ahb" },
+};
+
struct cqspi_st {
struct platform_device *pdev;
struct spi_controller *host;
@@ -1478,14 +1483,6 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
if (refcount_read(&cqspi->inflight_ops) == 0)
return -ENODEV;
- if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
- ret = pm_runtime_resume_and_get(dev);
- if (ret) {
- dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
- return ret;
- }
- }
-
if (!refcount_read(&cqspi->refcount))
return -EBUSY;
@@ -1497,6 +1494,14 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
return -EBUSY;
}
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret) {
+ dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
+ goto dec_inflight_refcount;
+ }
+ }
+
ret = cqspi_mem_process(mem, op);
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
@@ -1505,6 +1510,7 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
if (ret)
dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
+dec_inflight_refcount:
if (refcount_read(&cqspi->inflight_ops) > 1)
refcount_dec(&cqspi->inflight_ops);
@@ -1823,6 +1829,7 @@ static int cqspi_probe(struct platform_device *pdev)
}
/* Obtain QSPI clocks. */
+ memcpy(&cqspi->clks, &cqspi_clks, sizeof(cqspi->clks));
ret = devm_clk_bulk_get_optional(dev, CLK_QSPI_NUM, cqspi->clks);
if (ret)
return dev_err_probe(dev, ret, "Failed to get clocks\n");
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index 65adec7c7524..fe726b9b1780 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -271,7 +271,7 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
msecs_to_jiffies(ms));
if (ms == 0) {
- dev_err(&dws->ctlr->cur_msg->spi->dev,
+ dev_err(&dws->ctlr->dev,
"DMA transaction timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index b361c1bb3e43..45390e9b8cae 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -1009,7 +1009,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
enable_irq(irq);
}
- ret = devm_spi_register_controller(&pdev->dev, controller);
+ ret = spi_register_controller(controller);
if (ret < 0) {
dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n");
goto free_dma;
@@ -1035,6 +1035,7 @@ static void fsl_lpspi_remove(struct platform_device *pdev)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
+ spi_unregister_controller(controller);
fsl_lpspi_dma_exit(controller);
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 43ce47f2454c..d5fb0edc8e0c 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -359,9 +359,9 @@ static int setup_fifo_params(struct spi_device *spi_slv,
writel((spi_slv->mode & SPI_LOOP) ? LOOPBACK_ENABLE : 0, se->base + SE_SPI_LOOPBACK);
if (cs_changed)
writel(chipselect, se->base + SE_SPI_DEMUX_SEL);
- if (mode_changed & SE_SPI_CPHA)
+ if (mode_changed & SPI_CPHA)
writel((spi_slv->mode & SPI_CPHA) ? CPHA : 0, se->base + SE_SPI_CPHA);
- if (mode_changed & SE_SPI_CPOL)
+ if (mode_changed & SPI_CPOL)
writel((spi_slv->mode & SPI_CPOL) ? CPOL : 0, se->base + SE_SPI_CPOL);
if ((mode_changed & SPI_CS_HIGH) || (cs_changed && (spi_slv->mode & SPI_CS_HIGH)))
writel((spi_slv->mode & SPI_CS_HIGH) ? BIT(chipselect) : 0, se->base + SE_SPI_DEMUX_OUTPUT_INV);
@@ -906,10 +906,13 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
struct spi_controller *spi = data;
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
struct geni_se *se = &mas->se;
- u32 m_irq;
+ u32 m_irq, dma_tx_status, dma_rx_status;
m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
- if (!m_irq)
+ dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+ dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (!m_irq && !dma_tx_status && !dma_rx_status)
return IRQ_NONE;
if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |
@@ -957,8 +960,6 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
}
} else if (mas->cur_xfer_mode == GENI_SE_DMA) {
const struct spi_transfer *xfer = mas->cur_xfer;
- u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
- u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
if (dma_tx_status)
writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c
index bce3d149bea1..d8ef8f89330a 100644
--- a/drivers/spi/spi-intel-pci.c
+++ b/drivers/spi/spi-intel-pci.c
@@ -96,6 +96,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0xd323), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xe323), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xe423), (unsigned long)&cnl_info },
{ },
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index a7001b9e36e6..57768da3205d 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -1101,8 +1101,6 @@ static void meson_spicc_remove(struct platform_device *pdev)
/* Disable SPI */
writel(0, spicc->base + SPICC_CONREG);
-
- spi_controller_put(spicc->host);
}
static const struct meson_spicc_data meson_spicc_gx_data = {
diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c
index 2990bf85ee47..174995042f53 100644
--- a/drivers/spi/spi-rockchip-sfc.c
+++ b/drivers/spi/spi-rockchip-sfc.c
@@ -711,7 +711,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
}
}
- ret = devm_spi_register_controller(dev, host);
+ ret = spi_register_controller(host);
if (ret)
goto err_register;
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index bfcc140df810..3c61c799723b 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -612,7 +612,7 @@ static int f_ospi_probe(struct platform_device *pdev)
u32 num_cs = OSPI_NUM_CS;
int ret;
- ctlr = spi_alloc_host(dev, sizeof(*ospi));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*ospi));
if (!ctlr)
return -ENOMEM;
@@ -635,43 +635,22 @@ static int f_ospi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ospi);
ospi->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(ospi->base)) {
- ret = PTR_ERR(ospi->base);
- goto err_put_ctlr;
- }
+ if (IS_ERR(ospi->base))
+ return PTR_ERR(ospi->base);
ospi->clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(ospi->clk)) {
- ret = PTR_ERR(ospi->clk);
- goto err_put_ctlr;
- }
+ if (IS_ERR(ospi->clk))
+ return PTR_ERR(ospi->clk);
- mutex_init(&ospi->mlock);
-
- ret = f_ospi_init(ospi);
+ ret = devm_mutex_init(dev, &ospi->mlock);
if (ret)
- goto err_destroy_mutex;
+ return ret;
- ret = devm_spi_register_controller(dev, ctlr);
+ ret = f_ospi_init(ospi);
if (ret)
- goto err_destroy_mutex;
-
- return 0;
-
-err_destroy_mutex:
- mutex_destroy(&ospi->mlock);
-
-err_put_ctlr:
- spi_controller_put(ctlr);
-
- return ret;
-}
-
-static void f_ospi_remove(struct platform_device *pdev)
-{
- struct f_ospi *ospi = platform_get_drvdata(pdev);
+ return ret;
- mutex_destroy(&ospi->mlock);
+ return devm_spi_register_controller(dev, ctlr);
}
static const struct of_device_id f_ospi_dt_ids[] = {
@@ -686,7 +665,6 @@ static struct platform_driver f_ospi_driver = {
.of_match_table = f_ospi_dt_ids,
},
.probe = f_ospi_probe,
- .remove = f_ospi_remove,
};
module_platform_driver(f_ospi_driver);
diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
index c98afe02a1b6..38405f8f547f 100644
--- a/drivers/spi/spi-stm32-ospi.c
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -928,7 +928,7 @@ static int stm32_ospi_probe(struct platform_device *pdev)
dma_cfg.dst_addr = ospi->regs_phys_base + OSPI_DR;
ret = stm32_ospi_dma_setup(ospi, &dma_cfg);
if (ret)
- return ret;
+ goto err_dma_free;
mutex_init(&ospi->lock);
@@ -965,19 +965,22 @@ static int stm32_ospi_probe(struct platform_device *pdev)
if (ret) {
/* Disable ospi */
writel_relaxed(0, ospi->regs_base + OSPI_CR);
- goto err_pm_resume;
+ goto err_reset_control;
}
pm_runtime_put_autosuspend(ospi->dev);
return 0;
+err_reset_control:
+ reset_control_release(ospi->rstc);
err_pm_resume:
pm_runtime_put_sync_suspend(ospi->dev);
err_pm_enable:
pm_runtime_force_suspend(ospi->dev);
mutex_destroy(&ospi->lock);
+err_dma_free:
if (ospi->dma_chtx)
dma_release_channel(ospi->dma_chtx);
if (ospi->dma_chrx)
@@ -989,11 +992,8 @@ err_pm_enable:
static void stm32_ospi_remove(struct platform_device *pdev)
{
struct stm32_ospi *ospi = platform_get_drvdata(pdev);
- int ret;
- ret = pm_runtime_resume_and_get(ospi->dev);
- if (ret < 0)
- return;
+ pm_runtime_resume_and_get(ospi->dev);
spi_unregister_controller(ospi->ctrl);
/* Disable ospi */
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index b99de8c4cc99..33f211e159ef 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -1625,6 +1625,9 @@ static int stm32_spi_prepare_rx_dma_mdma_chaining(struct stm32_spi *spi,
return -EINVAL;
}
+ *rx_mdma_desc = _mdma_desc;
+ *rx_dma_desc = _dma_desc;
+
return 0;
}
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index 5232483c4a3a..af252500195c 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -381,21 +381,10 @@ static int zynq_qspi_setup_op(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr);
- int ret;
if (ctlr->busy)
return -EBUSY;
- ret = clk_enable(qspi->refclk);
- if (ret)
- return ret;
-
- ret = clk_enable(qspi->pclk);
- if (ret) {
- clk_disable(qspi->refclk);
- return ret;
- }
-
zynq_qspi_write(qspi, ZYNQ_QSPI_ENABLE_OFFSET,
ZYNQ_QSPI_ENABLE_ENABLE_MASK);
@@ -661,7 +650,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
goto remove_ctlr;
}
- xqspi->pclk = devm_clk_get(&pdev->dev, "pclk");
+ xqspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(xqspi->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
ret = PTR_ERR(xqspi->pclk);
@@ -670,36 +659,24 @@ static int zynq_qspi_probe(struct platform_device *pdev)
init_completion(&xqspi->data_completion);
- xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk");
+ xqspi->refclk = devm_clk_get_enabled(&pdev->dev, "ref_clk");
if (IS_ERR(xqspi->refclk)) {
dev_err(&pdev->dev, "ref_clk clock not found.\n");
ret = PTR_ERR(xqspi->refclk);
goto remove_ctlr;
}
- ret = clk_prepare_enable(xqspi->pclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable APB clock.\n");
- goto remove_ctlr;
- }
-
- ret = clk_prepare_enable(xqspi->refclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable device clock.\n");
- goto clk_dis_pclk;
- }
-
xqspi->irq = platform_get_irq(pdev, 0);
if (xqspi->irq < 0) {
ret = xqspi->irq;
- goto clk_dis_all;
+ goto remove_ctlr;
}
ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq,
0, pdev->name, xqspi);
if (ret != 0) {
ret = -ENXIO;
dev_err(&pdev->dev, "request_irq failed\n");
- goto clk_dis_all;
+ goto remove_ctlr;
}
ret = of_property_read_u32(np, "num-cs",
@@ -709,7 +686,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
} else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) {
ret = -EINVAL;
dev_err(&pdev->dev, "only 2 chip selects are available\n");
- goto clk_dis_all;
+ goto remove_ctlr;
} else {
ctlr->num_chipselect = num_cs;
}
@@ -728,15 +705,11 @@ static int zynq_qspi_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(&pdev->dev, ctlr);
if (ret) {
dev_err(&pdev->dev, "devm_spi_register_controller failed\n");
- goto clk_dis_all;
+ goto remove_ctlr;
}
return ret;
-clk_dis_all:
- clk_disable_unprepare(xqspi->refclk);
-clk_dis_pclk:
- clk_disable_unprepare(xqspi->pclk);
remove_ctlr:
spi_controller_put(ctlr);
@@ -758,9 +731,6 @@ static void zynq_qspi_remove(struct platform_device *pdev)
struct zynq_qspi *xqspi = platform_get_drvdata(pdev);
zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0);
-
- clk_disable_unprepare(xqspi->refclk);
- clk_disable_unprepare(xqspi->pclk);
}
static const struct of_device_id zynq_qspi_of_match[] = {
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 61f7bde8c7fb..9b1125556d29 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -50,7 +50,6 @@ static void spidev_release(struct device *dev)
struct spi_device *spi = to_spi_device(dev);
spi_controller_put(spi->controller);
- kfree(spi->driver_override);
free_percpu(spi->pcpu_statistics);
kfree(spi);
}
@@ -73,10 +72,9 @@ static ssize_t driver_override_store(struct device *dev,
struct device_attribute *a,
const char *buf, size_t count)
{
- struct spi_device *spi = to_spi_device(dev);
int ret;
- ret = driver_set_override(dev, &spi->driver_override, buf, count);
+ ret = __device_set_driver_override(dev, buf, count);
if (ret)
return ret;
@@ -86,13 +84,8 @@ static ssize_t driver_override_store(struct device *dev,
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *a, char *buf)
{
- const struct spi_device *spi = to_spi_device(dev);
- ssize_t len;
-
- device_lock(dev);
- len = sysfs_emit(buf, "%s\n", spi->driver_override ? : "");
- device_unlock(dev);
- return len;
+ guard(spinlock)(&dev->driver_override.lock);
+ return sysfs_emit(buf, "%s\n", dev->driver_override.name ?: "");
}
static DEVICE_ATTR_RW(driver_override);
@@ -376,10 +369,12 @@ static int spi_match_device(struct device *dev, const struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
+ int ret;
/* Check override first, and if set, only use the named driver */
- if (spi->driver_override)
- return strcmp(spi->driver_override, drv->name) == 0;
+ ret = device_match_driver_override(dev, drv);
+ if (ret >= 0)
+ return ret;
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
@@ -3049,6 +3044,8 @@ static void spi_controller_release(struct device *dev)
struct spi_controller *ctlr;
ctlr = container_of(dev, struct spi_controller, dev);
+
+ free_percpu(ctlr->pcpu_statistics);
kfree(ctlr);
}
@@ -3192,6 +3189,12 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
if (!ctlr)
return NULL;
+ ctlr->pcpu_statistics = spi_alloc_pcpu_stats(NULL);
+ if (!ctlr->pcpu_statistics) {
+ kfree(ctlr);
+ return NULL;
+ }
+
device_initialize(&ctlr->dev);
INIT_LIST_HEAD(&ctlr->queue);
spin_lock_init(&ctlr->queue_lock);
@@ -3480,17 +3483,8 @@ int spi_register_controller(struct spi_controller *ctlr)
dev_info(dev, "controller is unqueued, this is deprecated\n");
} else if (ctlr->transfer_one || ctlr->transfer_one_message) {
status = spi_controller_initialize_queue(ctlr);
- if (status) {
- device_del(&ctlr->dev);
- goto free_bus_id;
- }
- }
- /* Add statistics */
- ctlr->pcpu_statistics = spi_alloc_pcpu_stats(dev);
- if (!ctlr->pcpu_statistics) {
- dev_err(dev, "Error allocating per-cpu statistics\n");
- status = -ENOMEM;
- goto destroy_queue;
+ if (status)
+ goto del_ctrl;
}
mutex_lock(&board_lock);
@@ -3504,8 +3498,8 @@ int spi_register_controller(struct spi_controller *ctlr)
acpi_register_spi_devices(ctlr);
return status;
-destroy_queue:
- spi_destroy_queue(ctlr);
+del_ctrl:
+ device_del(&ctlr->dev);
free_bus_id:
mutex_lock(&board_lock);
idr_remove(&spi_controller_idr, ctlr->bus_num);
@@ -3540,8 +3534,19 @@ int devm_spi_register_controller(struct device *dev,
if (ret)
return ret;
- return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
+ /*
+ * Prevent controller from being freed by spi_unregister_controller()
+ * if devm_add_action_or_reset() fails for a non-devres allocated
+ * controller.
+ */
+ spi_controller_get(ctlr);
+
+ ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
+ if (ret == 0 || ctlr->devm_allocated)
+ spi_controller_put(ctlr);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(devm_spi_register_controller);
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index 6cf217e21593..3e2b5e6b07f9 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -186,20 +186,25 @@ u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, u
cnt = 0;
- while (cnt < in_len) {
+ while (cnt + 2 <= in_len) {
+ u8 ie_len = in_ie[cnt + 1];
+
+ if (cnt + 2 + ie_len > in_len)
+ break;
+
if (eid == in_ie[cnt]
- && (!oui || !memcmp(&in_ie[cnt+2], oui, oui_len))) {
+ && (!oui || (ie_len >= oui_len && !memcmp(&in_ie[cnt + 2], oui, oui_len)))) {
target_ie = &in_ie[cnt];
if (ie)
- memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
+ memcpy(ie, &in_ie[cnt], ie_len + 2);
if (ielen)
- *ielen = in_ie[cnt+1]+2;
+ *ielen = ie_len + 2;
break;
}
- cnt += in_ie[cnt+1]+2; /* goto next */
+ cnt += ie_len + 2; /* goto next */
}
return target_ie;
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 7df651708381..1ef48bf6581c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -1988,7 +1988,10 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
while (i < in_len) {
ielength = initial_out_len;
- if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && in_ie[i + 5] == 0x02 && i + 5 < in_len) { /* WMM element ID and OUI */
+ if (i + 5 < in_len &&
+ in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 &&
+ in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 &&
+ in_ie[i + 5] == 0x02) {
for (j = i; j < i + 9; j++) {
out_ie[ielength] = in_ie[j];
ielength++;
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index dec1f6b88a7d..62f6e0cdff4d 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -1123,6 +1123,7 @@ static void lynxfb_pci_remove(struct pci_dev *pdev)
iounmap(sm750_dev->pvReg);
iounmap(sm750_dev->pvMem);
+ pci_release_region(pdev, 1);
kfree(g_settings);
}
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
index a29faee91c78..f60b152a647d 100644
--- a/drivers/staging/sm750fb/sm750_hw.c
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -36,16 +36,11 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
pr_info("mmio phyAddr = %lx\n", sm750_dev->vidreg_start);
- /*
- * reserve the vidreg space of smi adaptor
- * if you do this, you need to add release region code
- * in lynxfb_remove, or memory will not be mapped again
- * successfully
- */
+ /* reserve the vidreg space of smi adaptor */
ret = pci_request_region(pdev, 1, "sm750fb");
if (ret) {
pr_err("Can not request PCI regions.\n");
- goto exit;
+ return ret;
}
/* now map mmio and vidmem */
@@ -54,7 +49,7 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
if (!sm750_dev->pvReg) {
pr_err("mmio failed\n");
ret = -EFAULT;
- goto exit;
+ goto err_release_region;
}
pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
@@ -79,13 +74,18 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
sm750_dev->pvMem =
ioremap_wc(sm750_dev->vidmem_start, sm750_dev->vidmem_size);
if (!sm750_dev->pvMem) {
- iounmap(sm750_dev->pvReg);
pr_err("Map video memory failed\n");
ret = -EFAULT;
- goto exit;
+ goto err_unmap_reg;
}
pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
-exit:
+
+ return 0;
+
+err_unmap_reg:
+ iounmap(sm750_dev->pvReg);
+err_release_region:
+ pci_release_region(pdev, 1);
return ret;
}
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index d668bd19fd4a..528883d989b8 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/configfs.h>
+#include <linux/blk-mq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
@@ -269,15 +270,27 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}
+static bool tcm_loop_flush_work_iter(struct request *rq, void *data)
+{
+ struct scsi_cmnd *sc = blk_mq_rq_to_pdu(rq);
+ struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);
+ struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;
+
+ flush_work(&se_cmd->work);
+ return true;
+}
+
static int tcm_loop_target_reset(struct scsi_cmnd *sc)
{
struct tcm_loop_hba *tl_hba;
struct tcm_loop_tpg *tl_tpg;
+ struct Scsi_Host *sh = sc->device->host;
+ int ret;
/*
* Locate the tcm_loop_hba_t pointer
*/
- tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
+ tl_hba = *(struct tcm_loop_hba **)shost_priv(sh);
if (!tl_hba) {
pr_err("Unable to perform device reset without active I_T Nexus\n");
return FAILED;
@@ -286,11 +299,38 @@ static int tcm_loop_target_reset(struct scsi_cmnd *sc)
* Locate the tl_tpg pointer from TargetID in sc->device->id
*/
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
- if (tl_tpg) {
- tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
- return SUCCESS;
- }
- return FAILED;
+ if (!tl_tpg)
+ return FAILED;
+
+ /*
+ * Issue a LUN_RESET to drain all commands that the target core
+ * knows about. This handles commands not yet marked CMD_T_COMPLETE.
+ */
+ ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, 0, TMR_LUN_RESET);
+ if (ret != TMR_FUNCTION_COMPLETE)
+ return FAILED;
+
+ /*
+ * Flush any deferred target core completion work that may still be
+ * queued. Commands that already had CMD_T_COMPLETE set before the TMR
+ * are skipped by the TMR drain, but their async completion work
+ * (transport_lun_remove_cmd → percpu_ref_put, release_cmd → scsi_done)
+ * may still be pending in target_completion_wq.
+ *
+ * The SCSI EH will reuse in-flight scsi_cmnd structures for recovery
+ * commands (e.g. TUR) immediately after this handler returns SUCCESS —
+ * if deferred work is still pending, the memset in queuecommand would
+ * zero the se_cmd while the work accesses it, leaking the LUN
+ * percpu_ref and hanging configfs unlink forever.
+ *
+ * Use blk_mq_tagset_busy_iter() to find all started requests and
+ * flush_work() on each — the same pattern used by mpi3mr, scsi_debug,
+ * and other SCSI drivers to drain outstanding commands during reset.
+ */
+ blk_mq_tagset_busy_iter(&sh->tag_set, tcm_loop_flush_work_iter, NULL);
+
+ tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
+ return SUCCESS;
}
static const struct scsi_host_template tcm_loop_driver_template = {
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 17608ea39d5a..a1c91d4515bc 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -108,8 +108,8 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
const char *page, size_t count)
{
ssize_t read_bytes;
- struct file *fp;
ssize_t r = -EINVAL;
+ struct path path = {};
mutex_lock(&target_devices_lock);
if (target_devices) {
@@ -131,17 +131,14 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
db_root_stage[read_bytes - 1] = '\0';
/* validate new db root before accepting it */
- fp = filp_open(db_root_stage, O_RDONLY, 0);
- if (IS_ERR(fp)) {
+ r = kern_path(db_root_stage, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
+ if (r) {
pr_err("db_root: cannot open: %s\n", db_root_stage);
+ if (r == -ENOTDIR)
+ pr_err("db_root: not a directory: %s\n", db_root_stage);
goto unlock;
}
- if (!S_ISDIR(file_inode(fp)->i_mode)) {
- filp_close(fp, NULL);
- pr_err("db_root: not a directory: %s\n", db_root_stage);
- goto unlock;
- }
- filp_close(fp, NULL);
+ path_put(&path);
strscpy(db_root, db_root_stage);
pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 3ae1f7137d9d..3d593af30aa5 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -276,7 +276,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
ssize_t len = 0;
int ret = 0, i;
- aio_cmd = kmalloc_flex(*aio_cmd, bvecs, sgl_nents);
+ aio_cmd = kzalloc_flex(*aio_cmd, bvecs, sgl_nents);
if (!aio_cmd)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 6c5b9e352e5e..e9ea9f80cfd9 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -23,29 +23,11 @@ struct tee_shm_dma_mem {
struct page *page;
};
-static void shm_put_kernel_pages(struct page **pages, size_t page_count)
-{
- size_t n;
-
- for (n = 0; n < page_count; n++)
- put_page(pages[n]);
-}
-
-static void shm_get_kernel_pages(struct page **pages, size_t page_count)
-{
- size_t n;
-
- for (n = 0; n < page_count; n++)
- get_page(pages[n]);
-}
-
static void release_registered_pages(struct tee_shm *shm)
{
if (shm->pages) {
if (shm->flags & TEE_SHM_USER_MAPPED)
unpin_user_pages(shm->pages, shm->num_pages);
- else
- shm_put_kernel_pages(shm->pages, shm->num_pages);
kfree(shm->pages);
}
@@ -477,13 +459,6 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
goto err_put_shm_pages;
}
- /*
- * iov_iter_extract_kvec_pages does not get reference on the pages,
- * get a reference on them.
- */
- if (iov_iter_is_kvec(iter))
- shm_get_kernel_pages(shm->pages, num_pages);
-
shm->offset = off;
shm->size = len;
shm->num_pages = num_pages;
@@ -499,8 +474,6 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
err_put_shm_pages:
if (!iov_iter_is_kvec(iter))
unpin_user_pages(shm->pages, shm->num_pages);
- else
- shm_put_kernel_pages(shm->pages, shm->num_pages);
err_free_shm_pages:
kfree(shm->pages);
err_free_shm:
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
index 49ff3bae7271..91f291627132 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
@@ -176,15 +176,21 @@ static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 v
static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider)
{
+ u8 offset;
u64 val;
val = read_soc_slider(proc_priv);
val &= ~SLIDER_MASK;
val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT);
+ if (slider == SOC_SLIDER_VALUE_MINIMUM || slider == SOC_SLIDER_VALUE_MAXIMUM)
+ offset = 0;
+ else
+ offset = slider_offset;
+
/* Set the slider offset from module params */
val &= ~SLIDER_OFFSET_MASK;
- val |= FIELD_PREP(SLIDER_OFFSET_MASK, slider_offset);
+ val |= FIELD_PREP(SLIDER_OFFSET_MASK, offset);
write_soc_slider(proc_priv, val);
}
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index b7d706ed7ed9..d1beee9e15f8 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -41,6 +41,8 @@ static struct thermal_governor *def_governor;
static bool thermal_pm_suspended;
+static struct workqueue_struct *thermal_wq __ro_after_init;
+
/*
* Governor section: set of functions to handle thermal governors
*
@@ -313,7 +315,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
if (delay > HZ)
delay = round_jiffies_relative(delay);
- mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, delay);
+ mod_delayed_work(thermal_wq, &tz->poll_queue, delay);
}
static void thermal_zone_recheck(struct thermal_zone_device *tz, int error)
@@ -1640,6 +1642,7 @@ unregister:
device_del(&tz->device);
release_device:
put_device(&tz->device);
+ wait_for_completion(&tz->removal);
remove_id:
ida_free(&thermal_tz_ida, id);
free_tzp:
@@ -1785,6 +1788,10 @@ static void thermal_zone_device_resume(struct work_struct *work)
guard(thermal_zone)(tz);
+ /* If the thermal zone is going away, there's nothing to do. */
+ if (tz->state & TZ_STATE_FLAG_EXIT)
+ return;
+
tz->state &= ~(TZ_STATE_FLAG_SUSPENDED | TZ_STATE_FLAG_RESUMING);
thermal_debug_tz_resume(tz);
@@ -1811,6 +1818,9 @@ static void thermal_zone_pm_prepare(struct thermal_zone_device *tz)
}
tz->state |= TZ_STATE_FLAG_SUSPENDED;
+
+ /* Prevent new work from getting to the workqueue subsequently. */
+ cancel_delayed_work(&tz->poll_queue);
}
static void thermal_pm_notify_prepare(void)
@@ -1829,8 +1839,6 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
{
guard(thermal_zone)(tz);
- cancel_delayed_work(&tz->poll_queue);
-
reinit_completion(&tz->resume);
tz->state |= TZ_STATE_FLAG_RESUMING;
@@ -1840,7 +1848,7 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
*/
INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_resume);
/* Queue up the work without a delay. */
- mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, 0);
+ mod_delayed_work(thermal_wq, &tz->poll_queue, 0);
}
static void thermal_pm_notify_complete(void)
@@ -1863,6 +1871,11 @@ static int thermal_pm_notify(struct notifier_block *nb,
case PM_RESTORE_PREPARE:
case PM_SUSPEND_PREPARE:
thermal_pm_notify_prepare();
+ /*
+ * Allow any leftover thermal work items already on the
+ * worqueue to complete so they don't get in the way later.
+ */
+ flush_workqueue(thermal_wq);
break;
case PM_POST_HIBERNATION:
case PM_POST_RESTORE:
@@ -1895,9 +1908,16 @@ static int __init thermal_init(void)
if (result)
goto error;
+ thermal_wq = alloc_workqueue("thermal_events",
+ WQ_FREEZABLE | WQ_POWER_EFFICIENT | WQ_PERCPU, 0);
+ if (!thermal_wq) {
+ result = -ENOMEM;
+ goto unregister_netlink;
+ }
+
result = thermal_register_governors();
if (result)
- goto unregister_netlink;
+ goto destroy_workqueue;
thermal_class = kzalloc_obj(*thermal_class);
if (!thermal_class) {
@@ -1924,6 +1944,8 @@ static int __init thermal_init(void)
unregister_governors:
thermal_unregister_governors();
+destroy_workqueue:
+ destroy_workqueue(thermal_wq);
unregister_netlink:
thermal_netlink_exit();
error:
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index ccce020a2432..2bb2e79ca3cb 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -1020,7 +1020,7 @@ static bool nhi_wake_supported(struct pci_dev *pdev)
* If power rails are sustainable for wakeup from S4 this
* property is set by the BIOS.
*/
- if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
+ if (!device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
return !!val;
return true;
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 8caecfc85d93..77fe0588fd6b 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -175,7 +175,9 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
return value;
}
+void serial8250_clear_fifos(struct uart_8250_port *p);
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
@@ -400,6 +402,26 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
return dma && dma->tx_running;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ dmaengine_pause(dma->txchan);
+}
+
+static inline void serial8250_tx_dma_resume(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ dmaengine_resume(dma->txchan);
+}
#else
static inline int serial8250_tx_dma(struct uart_8250_port *p)
{
@@ -421,6 +443,9 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
{
return false;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) { }
+static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) { }
#endif
static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index bdd26c9f34bd..3b6452e759d5 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -162,7 +162,22 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
*/
dma->tx_size = 0;
+ /*
+ * We can't use `dmaengine_terminate_sync` because `uart_flush_buffer` is
+ * holding the uart port spinlock.
+ */
dmaengine_terminate_async(dma->txchan);
+
+ /*
+ * The callback might or might not run. If it doesn't run, we need to ensure
+ * that `tx_running` is cleared so that we can schedule new transactions.
+ * If it does run, then the zombie callback will clear `tx_running` again
+ * and perform a no-op since `tx_size` was cleared above.
+ *
+ * In either case, we ASSUME the DMA transaction will terminate before we
+ * issue a new `serial8250_tx_dma`.
+ */
+ dma->tx_running = 0;
}
int serial8250_rx_dma(struct uart_8250_port *p)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index db73b2ae17fa..94beadb4024d 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -9,10 +9,14 @@
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/lockdep.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
@@ -40,8 +44,12 @@
#define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */
/* DesignWare specific register fields */
+#define DW_UART_IIR_IID GENMASK(3, 0)
+
#define DW_UART_MCR_SIRE BIT(6)
+#define DW_UART_USR_BUSY BIT(0)
+
/* Renesas specific register fields */
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
@@ -56,6 +64,13 @@
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
#define DW_UART_QUIRK_APMC0D08 BIT(4)
#define DW_UART_QUIRK_CPR_VALUE BIT(5)
+#define DW_UART_QUIRK_IER_KICK BIT(6)
+
+/*
+ * Number of consecutive IIR_NO_INT interrupts required to trigger interrupt
+ * storm prevention code.
+ */
+#define DW_UART_QUIRK_IER_KICK_THRES 4
struct dw8250_platform_data {
u8 usr_reg;
@@ -77,6 +92,9 @@ struct dw8250_data {
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
+ unsigned int in_idle:1;
+
+ u8 no_int_count;
};
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
@@ -107,78 +125,167 @@ static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u3
return value;
}
+static void dw8250_idle_exit(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ if (d->uart_16550_compatible)
+ return;
+
+ if (up->capabilities & UART_CAP_FIFO)
+ serial_port_out(p, UART_FCR, up->fcr);
+ serial_port_out(p, UART_MCR, up->mcr);
+ serial_port_out(p, UART_IER, up->ier);
+
+ /* DMA Rx is restarted by IRQ handler as needed. */
+ if (up->dma)
+ serial8250_tx_dma_resume(up);
+
+ d->in_idle = 0;
+}
+
/*
- * This function is being called as part of the uart_port::serial_out()
- * routine. Hence, it must not call serial_port_out() or serial_out()
- * against the modified registers here, i.e. LCR.
+ * Ensure BUSY is not asserted. If DW UART is configured with
+ * !uart_16550_compatible, the writes to LCR, DLL, and DLH fail while
+ * BUSY is asserted.
+ *
+ * Context: port's lock must be held
*/
-static void dw8250_force_idle(struct uart_port *p)
+static int dw8250_idle_enter(struct uart_port *p)
{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int lsr;
+ int retries;
+ u32 lsr;
- /*
- * The following call currently performs serial_out()
- * against the FCR register. Because it differs to LCR
- * there will be no infinite loop, but if it ever gets
- * modified, we might need a new custom version of it
- * that avoids infinite recursion.
- */
- serial8250_clear_and_reinit_fifos(up);
+ lockdep_assert_held_once(&p->lock);
+
+ if (d->uart_16550_compatible)
+ return 0;
+
+ d->in_idle = 1;
+
+ /* Prevent triggering interrupt from RBR filling */
+ serial_port_out(p, UART_IER, 0);
+
+ if (up->dma) {
+ serial8250_rx_dma_flush(up);
+ if (serial8250_tx_dma_running(up))
+ serial8250_tx_dma_pause(up);
+ }
/*
- * With PSLVERR_RESP_EN parameter set to 1, the device generates an
- * error response when an attempt to read an empty RBR with FIFO
- * enabled.
+ * Wait until Tx becomes empty + one extra frame time to ensure all bits
+ * have been sent on the wire.
+ *
+ * FIXME: frame_time delay is too long with very low baudrates.
*/
- if (up->fcr & UART_FCR_ENABLE_FIFO) {
- lsr = serial_port_in(p, UART_LSR);
- if (!(lsr & UART_LSR_DR))
- return;
+ serial8250_fifo_wait_for_lsr_thre(up, p->fifosize);
+ ndelay(p->frame_time);
+
+ serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP);
+
+ retries = 4; /* Arbitrary limit, 2 was always enough in tests */
+ do {
+ serial8250_clear_fifos(up);
+ if (!(serial_port_in(p, usr_reg) & DW_UART_USR_BUSY))
+ break;
+ /* FIXME: frame_time delay is too long with very low baudrates. */
+ ndelay(p->frame_time);
+ } while (--retries);
+
+ lsr = serial_lsr_in(up);
+ if (lsr & UART_LSR_DR) {
+ serial_port_in(p, UART_RX);
+ up->lsr_saved_flags = 0;
+ }
+
+ /* Now guaranteed to have BUSY deasserted? Just sanity check */
+ if (serial_port_in(p, usr_reg) & DW_UART_USR_BUSY) {
+ dw8250_idle_exit(p);
+ return -EBUSY;
}
- serial_port_in(p, UART_RX);
+ return 0;
+}
+
+static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int ret;
+
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ return;
+
+ serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB);
+ if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB))
+ goto idle_failed;
+
+ serial_dl_write(up, quot);
+ serial_port_out(p, UART_LCR, up->lcr);
+
+idle_failed:
+ dw8250_idle_exit(p);
}
/*
* This function is being called as part of the uart_port::serial_out()
- * routine. Hence, it must not call serial_port_out() or serial_out()
- * against the modified registers here, i.e. LCR.
+ * routine. Hence, special care must be taken when serial_port_out() or
+ * serial_out() against the modified registers here, i.e. LCR (d->in_idle is
+ * used to break recursion loop).
*/
static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
- void __iomem *addr = p->membase + (offset << p->regshift);
- int tries = 1000;
+ u32 lcr;
+ int ret;
if (offset != UART_LCR || d->uart_16550_compatible)
return;
+ lcr = serial_port_in(p, UART_LCR);
+
/* Make sure LCR write wasn't ignored */
- while (tries--) {
- u32 lcr = serial_port_in(p, offset);
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
+ if (d->in_idle)
+ goto write_err;
- dw8250_force_idle(p);
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ goto write_err;
-#ifdef CONFIG_64BIT
- if (p->type == PORT_OCTEON)
- __raw_writeq(value & 0xff, addr);
- else
-#endif
- if (p->iotype == UPIO_MEM32)
- writel(value, addr);
- else if (p->iotype == UPIO_MEM32BE)
- iowrite32be(value, addr);
- else
- writeb(value, addr);
- }
+ serial_port_out(p, UART_LCR, value);
+ dw8250_idle_exit(p);
+ return;
+
+write_err:
/*
* FIXME: this deadlocks if port->lock is already held
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
*/
+ return; /* Silences "label at the end of compound statement" */
+}
+
+/*
+ * With BUSY, LCR writes can be very expensive (IRQ + complex retry logic).
+ * If the write does not change the value of the LCR register, skip it entirely.
+ */
+static bool dw8250_can_skip_reg_write(struct uart_port *p, unsigned int offset, u32 value)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ u32 lcr;
+
+ if (offset != UART_LCR || d->uart_16550_compatible)
+ return false;
+
+ lcr = serial_port_in(p, offset);
+ return lcr == value;
}
/* Returns once the transmitter is empty or we run out of retries */
@@ -207,12 +314,18 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
writeb(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
/* Allow the TX to drain before we reconfigure */
if (offset == UART_LCR)
dw8250_tx_wait_empty(p);
@@ -237,6 +350,9 @@ static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset)
static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
@@ -248,6 +364,9 @@ static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 val
static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
writel(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -261,6 +380,9 @@ static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset)
static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value)
{
+ if (dw8250_can_skip_reg_write(p, offset, value))
+ return;
+
iowrite32be(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
@@ -272,6 +394,29 @@ static u32 dw8250_serial_in32be(struct uart_port *p, unsigned int offset)
return dw8250_modify_msr(p, offset, value);
}
+/*
+ * INTC10EE UART can IRQ storm while reporting IIR_NO_INT. Inducing IIR value
+ * change has been observed to break the storm.
+ *
+ * If Tx is empty (THRE asserted), we use here IER_THRI to cause IIR_NO_INT ->
+ * IIR_THRI transition.
+ */
+static void dw8250_quirk_ier_kick(struct uart_port *p)
+{
+ struct uart_8250_port *up = up_to_u8250p(p);
+ u32 lsr;
+
+ if (up->ier & UART_IER_THRI)
+ return;
+
+ lsr = serial_lsr_in(up);
+ if (!(lsr & UART_LSR_THRE))
+ return;
+
+ serial_port_out(p, UART_IER, up->ier | UART_IER_THRI);
+ serial_port_in(p, UART_LCR); /* safe, no side-effects */
+ serial_port_out(p, UART_IER, up->ier);
+}
static int dw8250_handle_irq(struct uart_port *p)
{
@@ -281,7 +426,31 @@ static int dw8250_handle_irq(struct uart_port *p)
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
- unsigned long flags;
+
+ guard(uart_port_lock_irqsave)(p);
+
+ switch (FIELD_GET(DW_UART_IIR_IID, iir)) {
+ case UART_IIR_NO_INT:
+ if (d->uart_16550_compatible || up->dma)
+ return 0;
+
+ if (quirks & DW_UART_QUIRK_IER_KICK &&
+ d->no_int_count == (DW_UART_QUIRK_IER_KICK_THRES - 1))
+ dw8250_quirk_ier_kick(p);
+ d->no_int_count = (d->no_int_count + 1) % DW_UART_QUIRK_IER_KICK_THRES;
+
+ return 0;
+
+ case UART_IIR_BUSY:
+ /* Clear the USR */
+ serial_port_in(p, d->pdata->usr_reg);
+
+ d->no_int_count = 0;
+
+ return 1;
+ }
+
+ d->no_int_count = 0;
/*
* There are ways to get Designware-based UARTs into a state where
@@ -294,20 +463,15 @@ static int dw8250_handle_irq(struct uart_port *p)
* so we limit the workaround only to non-DMA mode.
*/
if (!up->dma && rx_timeout) {
- uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(p, UART_RX);
-
- uart_port_unlock_irqrestore(p, flags);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */
if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
- uart_port_lock_irqsave(p, &flags);
status = serial_lsr_in(up);
- uart_port_unlock_irqrestore(p, flags);
if (status & (UART_LSR_DR | UART_LSR_BI)) {
dw8250_writel_ext(p, RZN1_UART_RDMACR, 0);
@@ -315,17 +479,9 @@ static int dw8250_handle_irq(struct uart_port *p)
}
}
- if (serial8250_handle_irq(p, iir))
- return 1;
-
- if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
- /* Clear the USR */
- serial_port_in(p, d->pdata->usr_reg);
-
- return 1;
- }
+ serial8250_handle_irq_locked(p, iir);
- return 0;
+ return 1;
}
static void dw8250_clk_work_cb(struct work_struct *work)
@@ -527,6 +683,14 @@ static void dw8250_reset_control_assert(void *data)
reset_control_assert(data);
}
+static void dw8250_shutdown(struct uart_port *port)
+{
+ struct dw8250_data *d = to_dw8250_data(port->private_data);
+
+ serial8250_do_shutdown(port);
+ d->no_int_count = 0;
+}
+
static int dw8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {}, *up = &uart;
@@ -545,8 +709,10 @@ static int dw8250_probe(struct platform_device *pdev)
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
p->dev = dev;
+
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
+ p->set_divisor = dw8250_set_divisor;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -654,10 +820,12 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible)
+ if (data->uart_16550_compatible) {
p->handle_irq = NULL;
- else if (data->pdata)
+ } else if (data->pdata) {
p->handle_irq = dw8250_handle_irq;
+ p->shutdown = dw8250_shutdown;
+ }
dw8250_setup_dma_filter(p, data);
@@ -789,6 +957,11 @@ static const struct dw8250_platform_data dw8250_skip_set_rate_data = {
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
+static const struct dw8250_platform_data dw8250_intc10ee = {
+ .usr_reg = DW_UART_USR,
+ .quirks = DW_UART_QUIRK_IER_KICK,
+};
+
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -818,7 +991,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
{ "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
- { "INTC10EE", (kernel_ulong_t)&dw8250_dw_apb },
+ { "INTC10EE", (kernel_ulong_t)&dw8250_intc10ee },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
@@ -836,6 +1009,7 @@ static struct platform_driver dw8250_platform_driver = {
module_platform_driver(dw8250_platform_driver);
+MODULE_IMPORT_NS("SERIAL_8250");
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index aa1ab4da9ff1..6cfd1b2af5b7 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -137,6 +137,8 @@ struct serial_private {
};
#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e
+#define PCIE_VENDOR_ID_ASIX 0x125B
+#define PCIE_DEVICE_ID_AX99100 0x9100
static const struct pci_device_id pci_use_msi[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
@@ -149,6 +151,8 @@ static const struct pci_device_id pci_use_msi[] = {
0xA000, 0x1000) },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL,
PCI_ANY_ID, PCI_ANY_ID) },
+ { PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+ 0xA000, 0x1000) },
{ }
};
@@ -920,6 +924,7 @@ static int pci_netmos_init(struct pci_dev *dev)
case PCI_DEVICE_ID_NETMOS_9912:
case PCI_DEVICE_ID_NETMOS_9922:
case PCI_DEVICE_ID_NETMOS_9900:
+ case PCIE_DEVICE_ID_AX99100:
num_serial = pci_netmos_9900_numports(dev);
break;
@@ -2544,6 +2549,14 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.init = pci_netmos_init,
.setup = pci_netmos_9900_setup,
},
+ {
+ .vendor = PCIE_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_netmos_init,
+ .setup = pci_netmos_9900_setup,
+ },
/*
* EndRun Technologies
*/
@@ -6065,6 +6078,10 @@ static const struct pci_device_id serial_pci_tbl[] = {
0xA000, 0x3002,
0, 0, pbn_NETMOS9900_2s_115200 },
+ { PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
/*
* Best Connectivity and Rosewill PCI Multi I/O cards
*/
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index cc94af2d578a..328711b5df1a 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -18,6 +18,7 @@
#include <linux/irq.h>
#include <linux/console.h>
#include <linux/gpio/consumer.h>
+#include <linux/lockdep.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -488,7 +489,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
/*
* FIFO support.
*/
-static void serial8250_clear_fifos(struct uart_8250_port *p)
+void serial8250_clear_fifos(struct uart_8250_port *p)
{
if (p->capabilities & UART_CAP_FIFO) {
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -497,6 +498,7 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
serial_out(p, UART_FCR, 0);
}
}
+EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, "SERIAL_8250");
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -1782,20 +1784,16 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
}
/*
- * This handles the interrupt from one port.
+ * Context: port's lock must be held by the caller.
*/
-int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_port *tport = &port->state->port;
bool skip_rx = false;
- unsigned long flags;
u16 status;
- if (iir & UART_IIR_NO_INT)
- return 0;
-
- uart_port_lock_irqsave(port, &flags);
+ lockdep_assert_held_once(&port->lock);
status = serial_lsr_in(up);
@@ -1828,8 +1826,19 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
else if (!up->dma->tx_running)
__stop_tx(up);
}
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_handle_irq_locked, "SERIAL_8250");
+
+/*
+ * This handles the interrupt from one port.
+ */
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+{
+ if (iir & UART_IIR_NO_INT)
+ return 0;
- uart_unlock_and_check_sysrq_irqrestore(port, flags);
+ guard(uart_port_lock_irqsave)(port);
+ serial8250_handle_irq_locked(port, iir);
return 1;
}
@@ -2147,8 +2156,7 @@ static void serial8250_THRE_test(struct uart_port *port)
if (up->port.flags & UPF_NO_THRE_TEST)
return;
- if (port->irqflags & IRQF_SHARED)
- disable_irq_nosync(port->irq);
+ disable_irq(port->irq);
/*
* Test for UARTs that do not reassert THRE when the transmitter is idle and the interrupt
@@ -2170,8 +2178,7 @@ static void serial8250_THRE_test(struct uart_port *port)
serial_port_out(port, UART_IER, 0);
}
- if (port->irqflags & IRQF_SHARED)
- enable_irq(port->irq);
+ enable_irq(port->irq);
/*
* If the interrupt is not reasserted, or we otherwise don't trust the iir, setup a timer to
@@ -2350,6 +2357,7 @@ static int serial8250_startup(struct uart_port *port)
void serial8250_do_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ u32 lcr;
serial8250_rpm_get(up);
/*
@@ -2376,13 +2384,13 @@ void serial8250_do_shutdown(struct uart_port *port)
port->mctrl &= ~TIOCM_OUT2;
serial8250_set_mctrl(port, port->mctrl);
+
+ /* Disable break condition */
+ lcr = serial_port_in(port, UART_LCR);
+ lcr &= ~UART_LCR_SBC;
+ serial_port_out(port, UART_LCR, lcr);
}
- /*
- * Disable break condition and FIFOs
- */
- serial_port_out(port, UART_LCR,
- serial_port_in(port, UART_LCR) & ~UART_LCR_SBC);
serial8250_clear_fifos(up);
rsa_disable(up);
@@ -2392,6 +2400,12 @@ void serial8250_do_shutdown(struct uart_port *port)
* the IRQ chain.
*/
serial_port_in(port, UART_RX);
+ /*
+ * LCR writes on DW UART can trigger late (unmaskable) IRQs.
+ * Handle them before releasing the handler.
+ */
+ synchronize_irq(port->irq);
+
serial8250_rpm_put(up);
up->ops->release_irq(up);
@@ -3185,6 +3199,17 @@ void serial8250_set_defaults(struct uart_8250_port *up)
}
EXPORT_SYMBOL_GPL(serial8250_set_defaults);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ if (wait_for_lsr(up, UART_LSR_THRE))
+ return;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250");
+
#ifdef CONFIG_SERIAL_8250_CONSOLE
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3226,16 +3251,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
-static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
-{
- unsigned int i;
-
- for (i = 0; i < count; i++) {
- if (wait_for_lsr(up, UART_LSR_THRE))
- return;
- }
-}
-
/*
* Print a string to the serial port using the device FIFO
*
@@ -3254,7 +3269,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
while (s != end) {
/* Allow timeout for each byte of a possibly full FIFO */
- fifo_wait_for_lsr(up, fifosize);
+ serial8250_fifo_wait_for_lsr_thre(up, fifosize);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
@@ -3272,7 +3287,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
* Allow timeout for each byte written since the caller will only wait
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
*/
- fifo_wait_for_lsr(up, tx_count);
+ serial8250_fifo_wait_for_lsr_thre(up, tx_count);
}
/*
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 487756947a96..89cebdd27841 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -643,7 +643,10 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned int ret;
port = uart_port_ref_lock(state, &flags);
- ret = kfifo_avail(&state->port.xmit_fifo);
+ if (!state->port.xmit_buf)
+ ret = 0;
+ else
+ ret = kfifo_avail(&state->port.xmit_fifo);
uart_port_unlock_deref(port, flags);
return ret;
}
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 39c1fd1ff9ce..6240c3d4dfd7 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -878,6 +878,7 @@ of_err:
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index c1f152d8b03b..b4b19157f05c 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1339,6 +1339,8 @@ struct vc_data *vc_deallocate(unsigned int currcons)
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
}
+ vc_uniscr_free(vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = NULL;
}
return vc;
}
@@ -1884,6 +1886,8 @@ static void enter_alt_screen(struct vc_data *vc)
vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL);
if (vc->vc_saved_screen == NULL)
return;
+ vc->vc_saved_uni_lines = vc->vc_uni_lines;
+ vc->vc_uni_lines = NULL;
vc->vc_saved_rows = vc->vc_rows;
vc->vc_saved_cols = vc->vc_cols;
save_cur(vc);
@@ -1905,6 +1909,26 @@ static void leave_alt_screen(struct vc_data *vc)
dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
memcpy(dest, src, 2 * cols);
}
+ /*
+ * If the console was resized while in the alternate screen,
+ * resize the saved unicode buffer to the current dimensions.
+ * On allocation failure new_uniscr is NULL, causing the old
+ * buffer to be freed and vc_uni_lines to be lazily rebuilt
+ * via vc_uniscr_check() when next needed.
+ */
+ if (vc->vc_saved_uni_lines &&
+ (vc->vc_saved_rows != vc->vc_rows ||
+ vc->vc_saved_cols != vc->vc_cols)) {
+ u32 **new_uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
+
+ if (new_uniscr)
+ vc_uniscr_copy_area(new_uniscr, vc->vc_cols, vc->vc_rows,
+ vc->vc_saved_uni_lines, cols, 0, rows);
+ vc_uniscr_free(vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = new_uniscr;
+ }
+ vc_uniscr_set(vc, vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = NULL;
restore_cur(vc);
/* Update the entire screen */
if (con_should_update(vc))
@@ -2227,6 +2251,8 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
if (vc->vc_saved_screen != NULL) {
kfree(vc->vc_saved_screen);
vc->vc_saved_screen = NULL;
+ vc_uniscr_free(vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = NULL;
vc->vc_saved_rows = 0;
vc->vc_saved_cols = 0;
}
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 847b55789bb8..9ceb6d6d479d 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -24,6 +24,7 @@
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
#include <linux/sched/clock.h>
+#include <linux/sizes.h>
#include <linux/iopoll.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
@@ -517,8 +518,8 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, struct scsi_cmnd *cmd,
if (hba->mcq_enabled) {
struct ufs_hw_queue *hwq = ufshcd_mcq_req_to_hwq(hba, rq);
-
- hwq_id = hwq->id;
+ if (hwq)
+ hwq_id = hwq->id;
} else {
doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
}
@@ -4389,14 +4390,6 @@ out_unlock:
spin_unlock_irqrestore(hba->host->host_lock, flags);
mutex_unlock(&hba->uic_cmd_mutex);
- /*
- * If the h8 exit fails during the runtime resume process, it becomes
- * stuck and cannot be recovered through the error handler. To fix
- * this, use link recovery instead of the error handler.
- */
- if (ret && hba->pm_op_in_progress)
- ret = ufshcd_link_recovery(hba);
-
return ret;
}
@@ -5249,6 +5242,25 @@ static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev)
hba->dev_info.rpmb_region_size[1] = desc_buf[RPMB_UNIT_DESC_PARAM_REGION1_SIZE];
hba->dev_info.rpmb_region_size[2] = desc_buf[RPMB_UNIT_DESC_PARAM_REGION2_SIZE];
hba->dev_info.rpmb_region_size[3] = desc_buf[RPMB_UNIT_DESC_PARAM_REGION3_SIZE];
+
+ if (hba->dev_info.wspecversion <= 0x0220) {
+ /*
+ * These older spec chips have only one RPMB region,
+ * sized between 128 kB minimum and 16 MB maximum.
+ * No per region size fields are provided (respective
+ * REGIONX_SIZE fields always contain zeros), so get
+ * it from the logical block count and size fields for
+ * compatibility
+ *
+ * (See JESD220C-2_2 Section 14.1.4.6
+ * RPMB Unit Descriptor,* offset 13h, 4 bytes)
+ */
+ hba->dev_info.rpmb_region_size[0] =
+ (get_unaligned_be64(desc_buf
+ + RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT)
+ << desc_buf[RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE])
+ / SZ_128K;
+ }
}
@@ -5963,6 +5975,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
hba->auto_bkops_enabled = false;
trace_ufshcd_auto_bkops_state(hba, "Disabled");
+ hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT;
hba->is_urgent_bkops_lvl_checked = false;
out:
return err;
@@ -6066,7 +6079,7 @@ static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba)
* impacted or critical. Handle these device by determining their urgent
* bkops status at runtime.
*/
- if (curr_status < BKOPS_STATUS_PERF_IMPACT) {
+ if ((curr_status > BKOPS_STATUS_NO_OP) && (curr_status < BKOPS_STATUS_PERF_IMPACT)) {
dev_err(hba->dev, "%s: device raised urgent BKOPS exception for bkops status %d\n",
__func__, curr_status);
/* update the current status as the urgent bkops level */
@@ -7097,7 +7110,7 @@ static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba)
ret = ufshcd_vops_get_outstanding_cqs(hba, &outstanding_cqs);
if (ret)
- outstanding_cqs = (1U << hba->nr_hw_queues) - 1;
+ outstanding_cqs = (1ULL << hba->nr_hw_queues) - 1;
/* Exclude the poll queues */
nr_queues = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
@@ -10053,6 +10066,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
}
flush_work(&hba->eeh_work);
+ cancel_delayed_work_sync(&hba->ufs_rtc_update_work);
ret = ufshcd_vops_suspend(hba, pm_op, PRE_CHANGE);
if (ret)
@@ -10107,7 +10121,6 @@ vops_suspend:
if (ret)
goto set_link_active;
- cancel_delayed_work_sync(&hba->ufs_rtc_update_work);
goto out;
set_link_active:
@@ -10179,7 +10192,15 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
} else {
dev_err(hba->dev, "%s: hibern8 exit failed %d\n",
__func__, ret);
- goto vendor_suspend;
+ /*
+ * If the h8 exit fails during the runtime resume
+ * process, it becomes stuck and cannot be recovered
+ * through the error handler. To fix this, use link
+ * recovery instead of the error handler.
+ */
+ ret = ufshcd_link_recovery(hba);
+ if (ret)
+ goto vendor_suspend;
}
} else if (ufshcd_is_link_off(hba)) {
/*
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index d59a60a16ec7..8382231af357 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -2589,6 +2589,9 @@ static int __cdns3_gadget_ep_queue(struct usb_ep *ep,
struct cdns3_request *priv_req;
int ret = 0;
+ if (!ep->desc)
+ return -ESHUTDOWN;
+
request->actual = 0;
request->status = -EINPROGRESS;
priv_req = to_cdns3_request(request);
@@ -3428,6 +3431,7 @@ static int __cdns3_gadget_init(struct cdns *cdns)
ret = cdns3_gadget_start(cdns);
if (ret) {
pm_runtime_put_sync(cdns->dev);
+ cdns_drd_gadget_off(cdns);
return ret;
}
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ad38c746270a..cf3c3eede1a5 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1225,6 +1225,12 @@ static int acm_probe(struct usb_interface *intf,
if (!data_interface || !control_interface)
return -ENODEV;
goto skip_normal_probe;
+ } else if (quirks == NO_UNION_12) {
+ data_interface = usb_ifnum_to_if(usb_dev, 2);
+ control_interface = usb_ifnum_to_if(usb_dev, 1);
+ if (!data_interface || !control_interface)
+ return -ENODEV;
+ goto skip_normal_probe;
}
/* normal probing*/
@@ -1379,6 +1385,8 @@ made_compressed_probe:
acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities;
if (quirks & NO_CAP_LINE)
acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
+ if (quirks & MISSING_CAP_BRK)
+ acm->ctrl_caps |= USB_CDC_CAP_BRK;
acm->ctrlsize = ctrlsize;
acm->readsize = readsize;
acm->rx_buflimit = num_rx_buf;
@@ -1746,6 +1754,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
+ { USB_DEVICE(0x04b8, 0x0d12), /* EPSON HMD Com&Sens */
+ .driver_info = NO_UNION_12, /* union descriptor is garbage */
+ },
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
@@ -2002,6 +2013,9 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = IGNORE_DEVICE,
},
+ /* CH343 supports CAP_BRK, but doesn't advertise it */
+ { USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, },
+
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 759ac15631d3..25fd5329a878 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -113,3 +113,5 @@ struct acm {
#define CLEAR_HALT_CONDITIONS BIT(5)
#define SEND_ZERO_PACKET BIT(6)
#define DISABLE_ECHO BIT(7)
+#define MISSING_CAP_BRK BIT(8)
+#define NO_UNION_12 BIT(9)
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index f2d94cfc70af..7556c0dac908 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -225,7 +225,8 @@ static void wdm_in_callback(struct urb *urb)
/* we may already be in overflow */
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
memmove(desc->ubuf + desc->length, desc->inbuf, length);
- desc->length += length;
+ smp_wmb(); /* against wdm_read() */
+ WRITE_ONCE(desc->length, desc->length + length);
}
}
skip_error:
@@ -533,6 +534,7 @@ static ssize_t wdm_read
return -ERESTARTSYS;
cntr = READ_ONCE(desc->length);
+ smp_rmb(); /* against wdm_in_callback() */
if (cntr == 0) {
desc->read = 0;
retry:
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 2526a0e03cde..bd9347804dec 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -254,6 +254,9 @@ static int usbtmc_release(struct inode *inode, struct file *file)
list_del(&file_data->file_elem);
spin_unlock_irq(&file_data->data->dev_lock);
+
+ /* flush anchored URBs */
+ usbtmc_draw_down(file_data);
mutex_unlock(&file_data->data->io_mutex);
kref_put(&file_data->data->kref, usbtmc_delete);
@@ -727,7 +730,7 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
buffer[1] = data->bTag;
buffer[2] = ~data->bTag;
- retval = usb_bulk_msg(data->usb_dev,
+ retval = usb_bulk_msg_killable(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE,
@@ -1347,7 +1350,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
buffer[11] = 0; /* Reserved */
/* Send bulk URB */
- retval = usb_bulk_msg(data->usb_dev,
+ retval = usb_bulk_msg_killable(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE,
@@ -1419,7 +1422,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
actual = 0;
/* Send bulk URB */
- retval = usb_bulk_msg(data->usb_dev,
+ retval = usb_bulk_msg_killable(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev,
data->bulk_in),
buffer, bufsize, &actual,
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index 56c9bfaf2ea3..b34fb65813c4 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -331,10 +331,9 @@ struct ulpi *ulpi_register_interface(struct device *dev,
ulpi->ops = ops;
ret = ulpi_register(dev, ulpi);
- if (ret) {
- kfree(ulpi);
+ if (ret)
return ERR_PTR(ret);
- }
+
return ulpi;
}
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 1cd5fa61dc76..6a1fd967e0a6 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -927,7 +927,11 @@ int usb_get_configuration(struct usb_device *dev)
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
- if (ncfg < 1) {
+ if (ncfg < 1 && dev->quirks & USB_QUIRK_FORCE_ONE_CONFIG) {
+ dev_info(ddev, "Device claims zero configurations, forcing to 1\n");
+ dev->descriptor.bNumConfigurations = 1;
+ ncfg = 1;
+ } else if (ncfg < 1) {
dev_err(ddev, "no configurations\n");
return -EINVAL;
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2574e65bc640..f63004417058 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1415,14 +1415,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
int status = 0;
int i = 0, n = 0;
struct usb_interface *intf;
+ bool offload_active = false;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED)
goto done;
+ usb_offload_set_pm_locked(udev, true);
if (msg.event == PM_EVENT_SUSPEND && usb_offload_check(udev)) {
dev_dbg(&udev->dev, "device offloaded, skip suspend.\n");
- udev->offload_at_suspend = 1;
+ offload_active = true;
}
/* Suspend all the interfaces and then udev itself */
@@ -1436,8 +1438,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
* interrupt urbs, allowing interrupt events to be
* handled during system suspend.
*/
- if (udev->offload_at_suspend &&
- intf->needs_remote_wakeup) {
+ if (offload_active && intf->needs_remote_wakeup) {
dev_dbg(&intf->dev,
"device offloaded, skip suspend.\n");
continue;
@@ -1452,7 +1453,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
}
if (status == 0) {
- if (!udev->offload_at_suspend)
+ if (!offload_active)
status = usb_suspend_device(udev, msg);
/*
@@ -1498,7 +1499,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
*/
} else {
udev->can_submit = 0;
- if (!udev->offload_at_suspend) {
+ if (!offload_active) {
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
@@ -1507,6 +1508,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
done:
+ if (status != 0)
+ usb_offload_set_pm_locked(udev, false);
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
@@ -1536,16 +1539,19 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
int status = 0;
int i;
struct usb_interface *intf;
+ bool offload_active = false;
if (udev->state == USB_STATE_NOTATTACHED) {
status = -ENODEV;
goto done;
}
udev->can_submit = 1;
+ if (msg.event == PM_EVENT_RESUME)
+ offload_active = usb_offload_check(udev);
/* Resume the device */
if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) {
- if (!udev->offload_at_suspend)
+ if (!offload_active)
status = usb_resume_device(udev, msg);
else
dev_dbg(&udev->dev,
@@ -1562,8 +1568,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
* pending interrupt urbs, allowing interrupt events
* to be handled during system suspend.
*/
- if (udev->offload_at_suspend &&
- intf->needs_remote_wakeup) {
+ if (offload_active && intf->needs_remote_wakeup) {
dev_dbg(&intf->dev,
"device offloaded, skip resume.\n");
continue;
@@ -1572,11 +1577,11 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
udev->reset_resume);
}
}
- udev->offload_at_suspend = 0;
usb_mark_last_busy(udev);
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+ usb_offload_set_pm_locked(udev, false);
if (!status)
udev->reset_resume = 0;
return status;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index dee842ea6931..89221f1ce769 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2403,7 +2403,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
if (hcd->rh_registered) {
pm_wakeup_event(&hcd->self.root_hub->dev, 0);
set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
- queue_work(pm_wq, &hcd->wakeup_work);
+ queue_work(system_freezable_wq, &hcd->wakeup_work);
}
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ea970ddf8879..2ab120ce2fa8 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -42,16 +42,19 @@ static void usb_api_blocking_completion(struct urb *urb)
/*
- * Starts urb and waits for completion or timeout. Note that this call
- * is NOT interruptible. Many device driver i/o requests should be
- * interruptible and therefore these drivers should implement their
- * own interruptible routines.
+ * Starts urb and waits for completion or timeout.
+ * Whether or not the wait is killable depends on the flag passed in.
+ * For example, compare usb_bulk_msg() and usb_bulk_msg_killable().
+ *
+ * For non-killable waits, we enforce a maximum limit on the timeout value.
*/
-static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
+static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length,
+ bool killable)
{
struct api_context ctx;
unsigned long expire;
int retval;
+ long rc;
init_completion(&ctx.done);
urb->context = &ctx;
@@ -60,13 +63,24 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
if (unlikely(retval))
goto out;
- expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
- if (!wait_for_completion_timeout(&ctx.done, expire)) {
+ if (!killable && (timeout <= 0 || timeout > USB_MAX_SYNCHRONOUS_TIMEOUT))
+ timeout = USB_MAX_SYNCHRONOUS_TIMEOUT;
+ expire = (timeout > 0) ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ if (killable)
+ rc = wait_for_completion_killable_timeout(&ctx.done, expire);
+ else
+ rc = wait_for_completion_timeout(&ctx.done, expire);
+ if (rc <= 0) {
usb_kill_urb(urb);
- retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
+ if (ctx.status != -ENOENT)
+ retval = ctx.status;
+ else if (rc == 0)
+ retval = -ETIMEDOUT;
+ else
+ retval = rc;
dev_dbg(&urb->dev->dev,
- "%s timed out on ep%d%s len=%u/%u\n",
+ "%s timed out or killed on ep%d%s len=%u/%u\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
@@ -100,7 +114,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
- retv = usb_start_wait_urb(urb, timeout, &length);
+ retv = usb_start_wait_urb(urb, timeout, &length, false);
if (retv < 0)
return retv;
else
@@ -117,8 +131,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
- * @timeout: time in msecs to wait for the message to complete before timing
- * out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: task context, might sleep.
*
@@ -173,8 +186,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg);
* @index: USB message index value
* @driver_data: pointer to the data to send
* @size: length in bytes of the data to send
- * @timeout: time in msecs to wait for the message to complete before timing
- * out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
* @memflags: the flags for memory allocation for buffers
*
* Context: !in_interrupt ()
@@ -232,8 +244,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_send);
* @index: USB message index value
* @driver_data: pointer to the data to be filled in by the message
* @size: length in bytes of the data to be received
- * @timeout: time in msecs to wait for the message to complete before timing
- * out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
* @memflags: the flags for memory allocation for buffers
*
* Context: !in_interrupt ()
@@ -304,8 +315,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv);
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred
* in bytes
- * @timeout: time in msecs to wait for the message to complete before
- * timing out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: task context, might sleep.
*
@@ -337,8 +347,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred
* in bytes
- * @timeout: time in msecs to wait for the message to complete before
- * timing out (if 0 the wait is forever)
+ * @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: task context, might sleep.
*
@@ -385,10 +394,59 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
- return usb_start_wait_urb(urb, timeout, actual_length);
+ return usb_start_wait_urb(urb, timeout, actual_length, false);
}
EXPORT_SYMBOL_GPL(usb_bulk_msg);
+/**
+ * usb_bulk_msg_killable - Builds a bulk urb, sends it off and waits for completion in a killable state
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred
+ * in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ * timing out (if <= 0, the wait is as long as possible)
+ *
+ * Context: task context, might sleep.
+ *
+ * This function is just like usb_blk_msg(), except that it waits in a
+ * killable state and there is no limit on the timeout length.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length parameter.
+ *
+ */
+int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe,
+ void *data, int len, int *actual_length, int timeout)
+{
+ struct urb *urb;
+ struct usb_host_endpoint *ep;
+
+ ep = usb_pipe_endpoint(usb_dev, pipe);
+ if (!ep || len < 0)
+ return -EINVAL;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+
+ if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT) {
+ pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+ usb_fill_int_urb(urb, usb_dev, pipe, data, len,
+ usb_api_blocking_completion, NULL,
+ ep->desc.bInterval);
+ } else
+ usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
+ usb_api_blocking_completion, NULL);
+
+ return usb_start_wait_urb(urb, timeout, actual_length, true);
+}
+EXPORT_SYMBOL_GPL(usb_bulk_msg_killable);
+
/*-------------------------------------------------------------------*/
static void sg_clean(struct usb_sg_request *io)
diff --git a/drivers/usb/core/offload.c b/drivers/usb/core/offload.c
index 7c699f1b8d2b..9db3cfedd29c 100644
--- a/drivers/usb/core/offload.c
+++ b/drivers/usb/core/offload.c
@@ -25,33 +25,30 @@
*/
int usb_offload_get(struct usb_device *udev)
{
- int ret;
+ int ret = 0;
- usb_lock_device(udev);
- if (udev->state == USB_STATE_NOTATTACHED) {
- usb_unlock_device(udev);
+ if (!usb_get_dev(udev))
return -ENODEV;
- }
- if (udev->state == USB_STATE_SUSPENDED ||
- udev->offload_at_suspend) {
- usb_unlock_device(udev);
- return -EBUSY;
+ if (pm_runtime_get_if_active(&udev->dev) != 1) {
+ ret = -EBUSY;
+ goto err_rpm;
}
- /*
- * offload_usage could only be modified when the device is active, since
- * it will alter the suspend flow of the device.
- */
- ret = usb_autoresume_device(udev);
- if (ret < 0) {
- usb_unlock_device(udev);
- return ret;
+ spin_lock(&udev->offload_lock);
+
+ if (udev->offload_pm_locked) {
+ ret = -EAGAIN;
+ goto err;
}
udev->offload_usage++;
- usb_autosuspend_device(udev);
- usb_unlock_device(udev);
+
+err:
+ spin_unlock(&udev->offload_lock);
+ pm_runtime_put_autosuspend(&udev->dev);
+err_rpm:
+ usb_put_dev(udev);
return ret;
}
@@ -69,35 +66,32 @@ EXPORT_SYMBOL_GPL(usb_offload_get);
*/
int usb_offload_put(struct usb_device *udev)
{
- int ret;
+ int ret = 0;
- usb_lock_device(udev);
- if (udev->state == USB_STATE_NOTATTACHED) {
- usb_unlock_device(udev);
+ if (!usb_get_dev(udev))
return -ENODEV;
- }
- if (udev->state == USB_STATE_SUSPENDED ||
- udev->offload_at_suspend) {
- usb_unlock_device(udev);
- return -EBUSY;
+ if (pm_runtime_get_if_active(&udev->dev) != 1) {
+ ret = -EBUSY;
+ goto err_rpm;
}
- /*
- * offload_usage could only be modified when the device is active, since
- * it will alter the suspend flow of the device.
- */
- ret = usb_autoresume_device(udev);
- if (ret < 0) {
- usb_unlock_device(udev);
- return ret;
+ spin_lock(&udev->offload_lock);
+
+ if (udev->offload_pm_locked) {
+ ret = -EAGAIN;
+ goto err;
}
/* Drop the count when it wasn't 0, ignore the operation otherwise. */
if (udev->offload_usage)
udev->offload_usage--;
- usb_autosuspend_device(udev);
- usb_unlock_device(udev);
+
+err:
+ spin_unlock(&udev->offload_lock);
+ pm_runtime_put_autosuspend(&udev->dev);
+err_rpm:
+ usb_put_dev(udev);
return ret;
}
@@ -112,25 +106,47 @@ EXPORT_SYMBOL_GPL(usb_offload_put);
* management.
*
* The caller must hold @udev's device lock. In addition, the caller should
- * ensure downstream usb devices are all either suspended or marked as
- * "offload_at_suspend" to ensure the correctness of the return value.
+ * ensure the device itself and the downstream usb devices are all marked as
+ * "offload_pm_locked" to ensure the correctness of the return value.
*
* Returns true on any offload activity, false otherwise.
*/
bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex)
{
struct usb_device *child;
- bool active;
+ bool active = false;
int port1;
+ if (udev->offload_usage)
+ return true;
+
usb_hub_for_each_child(udev, port1, child) {
usb_lock_device(child);
active = usb_offload_check(child);
usb_unlock_device(child);
+
if (active)
- return true;
+ break;
}
- return !!udev->offload_usage;
+ return active;
}
EXPORT_SYMBOL_GPL(usb_offload_check);
+
+/**
+ * usb_offload_set_pm_locked - set the PM lock state of a USB device
+ * @udev: the USB device to modify
+ * @locked: the new lock state
+ *
+ * Setting @locked to true prevents offload_usage from being modified. This
+ * ensures that offload activities cannot be started or stopped during critical
+ * power management transitions, maintaining a stable state for the duration
+ * of the transition.
+ */
+void usb_offload_set_pm_locked(struct usb_device *udev, bool locked)
+{
+ spin_lock(&udev->offload_lock);
+ udev->offload_pm_locked = locked;
+ spin_unlock(&udev->offload_lock);
+}
+EXPORT_SYMBOL_GPL(usb_offload_set_pm_locked);
diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c
index faa20054ad5a..4d966cc9cdc9 100644
--- a/drivers/usb/core/phy.c
+++ b/drivers/usb/core/phy.c
@@ -114,7 +114,7 @@ EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev)
{
struct usb_phy_roothub *phy_roothub;
- int num_phys;
+ int num_phys, usb2_phy_index;
if (!IS_ENABLED(CONFIG_GENERIC_PHY))
return NULL;
@@ -124,6 +124,16 @@ struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev)
if (num_phys <= 0)
return NULL;
+ /*
+ * If 'usb2-phy' is not present, usb_phy_roothub_alloc() added
+ * all PHYs to the primary HCD's phy_roothub already, so skip
+ * adding 'usb3-phy' here to avoid double use of that.
+ */
+ usb2_phy_index = of_property_match_string(dev->of_node, "phy-names",
+ "usb2-phy");
+ if (usb2_phy_index < 0)
+ return NULL;
+
phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
if (!phy_roothub)
return ERR_PTR(-ENOMEM);
@@ -200,16 +210,10 @@ int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
list_for_each_entry(roothub_entry, head, list) {
err = phy_set_mode(roothub_entry->phy, mode);
if (err)
- goto err_out;
+ return err;
}
return 0;
-
-err_out:
- list_for_each_entry_continue_reverse(roothub_entry, head, list)
- phy_power_off(roothub_entry->phy);
-
- return err;
}
EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 9e7e49712739..0ffdaefba508 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -140,6 +140,8 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
case 'p':
flags |= USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT;
break;
+ case 'q':
+ flags |= USB_QUIRK_FORCE_ONE_CONFIG;
/* Ignore unrecognized flag characters */
}
}
@@ -207,6 +209,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* HP v222w 16GB Mini USB Drive */
{ USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
+ /* Huawei 4G LTE module ME906S */
+ { USB_DEVICE(0x03f0, 0xa31d), .driver_info =
+ USB_QUIRK_DISCONNECT_SUSPEND },
+
/* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -376,6 +382,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* SanDisk Extreme 55AE */
{ USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM },
+ /* Avermedia Live Gamer Ultra 2.1 (GC553G2) - BOS descriptor fetch hangs at SuperSpeed Plus */
+ { USB_DEVICE(0x07ca, 0x2553), .driver_info = USB_QUIRK_NO_BOS },
+
/* Realforce 87U Keyboard */
{ USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM },
@@ -392,6 +401,7 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Silicon Motion Flash Drive */
{ USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT },
+ { USB_DEVICE(0x090c, 0x2000), .driver_info = USB_QUIRK_DELAY_INIT },
/* Sound Devices USBPre2 */
{ USB_DEVICE(0x0926, 0x0202), .driver_info =
@@ -436,6 +446,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+ /* ASUS TUF 4K PRO - BOS descriptor fetch hangs at SuperSpeed Plus */
+ { USB_DEVICE(0x0b05, 0x1ab9), .driver_info = USB_QUIRK_NO_BOS },
+
/* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/
{ USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
@@ -480,6 +493,8 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Razer - Razer Blade Keyboard */
{ USB_DEVICE(0x1532, 0x0116), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+ /* Razer - Razer Kiyo Pro Webcam */
+ { USB_DEVICE(0x1532, 0x0e05), .driver_info = USB_QUIRK_NO_LPM },
/* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */
{ USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -564,6 +579,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
+ /* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */
+ { USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS },
+
/* APTIV AUTOMOTIVE HUB */
{ USB_DEVICE(0x2c48, 0x0132), .driver_info =
USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT },
@@ -574,12 +592,18 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */
{ USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM },
+ /* ezcap401 - BOS descriptor fetch hangs at SuperSpeed Plus */
+ { USB_DEVICE(0x32ed, 0x0401), .driver_info = USB_QUIRK_NO_BOS },
+
/* DELL USB GEN2 */
{ USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
/* VCOM device */
{ USB_DEVICE(0x4296, 0x7570), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
+ /* Noji-MCS SmartCard Reader */
+ { USB_DEVICE(0x5131, 0x2007), .driver_info = USB_QUIRK_FORCE_ONE_CONFIG },
+
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index e9a10a33534c..df166cafe106 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -671,6 +671,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
dev->state = USB_STATE_ATTACHED;
dev->lpm_disable_count = 1;
+ spin_lock_init(&dev->offload_lock);
dev->offload_usage = 0;
atomic_set(&dev->urbnum, 0);
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index d216e26c787b..c8b02c27d27d 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -4607,7 +4607,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
/* Exit clock gating when driver is stopped. */
if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
hsotg->bus_suspended && !hsotg->params.no_clock_gating) {
+ spin_lock_irqsave(&hsotg->lock, flags);
dwc2_gadget_exit_clock_gating(hsotg, 0);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
}
/* all endpoints should be shutdown */
diff --git a/drivers/usb/dwc3/dwc3-google.c b/drivers/usb/dwc3/dwc3-google.c
index 2105c72af753..4ca567ec01d0 100644
--- a/drivers/usb/dwc3/dwc3-google.c
+++ b/drivers/usb/dwc3/dwc3-google.c
@@ -385,8 +385,9 @@ static int dwc3_google_probe(struct platform_device *pdev)
"google,usb-cfg-csr",
ARRAY_SIZE(args), args);
if (IS_ERR(google->usb_cfg_regmap)) {
- return dev_err_probe(dev, PTR_ERR(google->usb_cfg_regmap),
- "invalid usb cfg csr\n");
+ ret = dev_err_probe(dev, PTR_ERR(google->usb_cfg_regmap),
+ "invalid usb cfg csr\n");
+ goto err_deinit_pdom;
}
google->host_cfg_offset = args[0];
diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
index b3d7252bd910..1cf96540b66e 100644
--- a/drivers/usb/dwc3/dwc3-imx8mp.c
+++ b/drivers/usb/dwc3/dwc3-imx8mp.c
@@ -263,7 +263,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
if (!dwc3) {
err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n");
- goto depopulate;
+ goto put_dwc3;
}
dwc3->glue_ops = &dwc3_imx_glue_ops;
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 6ecadc81bd6b..6c1cbb722ca8 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -56,6 +56,7 @@
#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
#define PCI_DEVICE_ID_INTEL_CNPV 0xa3b0
#define PCI_DEVICE_ID_INTEL_RPL 0xa70e
+#define PCI_DEVICE_ID_INTEL_NVLH 0xd37f
#define PCI_DEVICE_ID_INTEL_PTLH 0xe332
#define PCI_DEVICE_ID_INTEL_PTLH_PCH 0xe37e
#define PCI_DEVICE_ID_INTEL_PTLU 0xe432
@@ -447,6 +448,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) },
{ PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) },
{ PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) },
+ { PCI_DEVICE_DATA(INTEL, NVLH, &dwc3_pci_intel_swnode) },
{ PCI_DEVICE_DATA(INTEL, PTLH, &dwc3_pci_intel_swnode) },
{ PCI_DEVICE_DATA(INTEL, PTLH_PCH, &dwc3_pci_intel_swnode) },
{ PCI_DEVICE_DATA(INTEL, PTLU, &dwc3_pci_intel_swnode) },
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index e0c02121374e..e495bac4efeb 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -681,6 +681,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
struct f_ecm_opts *ecm_opts;
+ struct net_device *net __free(detach_gadget) = NULL;
struct usb_request *request __free(free_usb_request) = NULL;
if (!can_support_ecm(cdev->gadget))
@@ -688,18 +689,18 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
- mutex_lock(&ecm_opts->lock);
-
- gether_set_gadget(ecm_opts->net, cdev->gadget);
-
- if (!ecm_opts->bound) {
- status = gether_register_netdev(ecm_opts->net);
- ecm_opts->bound = true;
- }
-
- mutex_unlock(&ecm_opts->lock);
- if (status)
- return status;
+ scoped_guard(mutex, &ecm_opts->lock)
+ if (ecm_opts->bind_count == 0 && !ecm_opts->bound) {
+ if (!device_is_registered(&ecm_opts->net->dev)) {
+ gether_set_gadget(ecm_opts->net, cdev->gadget);
+ status = gether_register_netdev(ecm_opts->net);
+ } else
+ status = gether_attach_gadget(ecm_opts->net, cdev->gadget);
+
+ if (status)
+ return status;
+ net = ecm_opts->net;
+ }
ecm_string_defs[1].s = ecm->ethaddr;
@@ -790,6 +791,9 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
ecm->notify_req = no_free_ptr(request);
+ ecm_opts->bind_count++;
+ retain_and_null_ptr(net);
+
DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n",
ecm->port.in_ep->name, ecm->port.out_ep->name,
ecm->notify->name);
@@ -836,7 +840,7 @@ static void ecm_free_inst(struct usb_function_instance *f)
struct f_ecm_opts *opts;
opts = container_of(f, struct f_ecm_opts, func_inst);
- if (opts->bound)
+ if (device_is_registered(&opts->net->dev))
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
@@ -906,9 +910,12 @@ static void ecm_free(struct usb_function *f)
static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_ecm *ecm = func_to_ecm(f);
+ struct f_ecm_opts *ecm_opts;
DBG(c->cdev, "ecm unbind\n");
+ ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
+
usb_free_all_descriptors(f);
if (atomic_read(&ecm->notify_count)) {
@@ -918,6 +925,10 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)
kfree(ecm->notify_req->buf);
usb_ep_free_request(ecm->notify, ecm->notify_req);
+
+ ecm_opts->bind_count--;
+ if (ecm_opts->bind_count == 0 && !ecm_opts->bound)
+ gether_detach_gadget(ecm_opts->net);
}
static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index 0142a0e487ee..ac37d7c1d168 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -7,6 +7,7 @@
* Copyright (C) 2009 EF Johnson Technologies
*/
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -251,24 +252,22 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
struct f_eem_opts *eem_opts;
+ struct net_device *net __free(detach_gadget) = NULL;
eem_opts = container_of(f->fi, struct f_eem_opts, func_inst);
- /*
- * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
- * configurations are bound in sequence with list_for_each_entry,
- * in each configuration its functions are bound in sequence
- * with list_for_each_entry, so we assume no race condition
- * with regard to eem_opts->bound access
- */
- if (!eem_opts->bound) {
- mutex_lock(&eem_opts->lock);
- gether_set_gadget(eem_opts->net, cdev->gadget);
- status = gether_register_netdev(eem_opts->net);
- mutex_unlock(&eem_opts->lock);
- if (status)
- return status;
- eem_opts->bound = true;
- }
+
+ scoped_guard(mutex, &eem_opts->lock)
+ if (eem_opts->bind_count == 0 && !eem_opts->bound) {
+ if (!device_is_registered(&eem_opts->net->dev)) {
+ gether_set_gadget(eem_opts->net, cdev->gadget);
+ status = gether_register_netdev(eem_opts->net);
+ } else
+ status = gether_attach_gadget(eem_opts->net, cdev->gadget);
+
+ if (status)
+ return status;
+ net = eem_opts->net;
+ }
us = usb_gstrings_attach(cdev, eem_strings,
ARRAY_SIZE(eem_string_defs));
@@ -279,21 +278,19 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
- goto fail;
+ return status;
eem->ctrl_id = status;
eem_intf.bInterfaceNumber = status;
- status = -ENODEV;
-
/* allocate instance-specific endpoints */
ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc);
if (!ep)
- goto fail;
+ return -ENODEV;
eem->port.in_ep = ep;
ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc);
if (!ep)
- goto fail;
+ return -ENODEV;
eem->port.out_ep = ep;
/* support all relevant hardware speeds... we expect that when
@@ -309,16 +306,14 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
eem_ss_function, eem_ss_function);
if (status)
- goto fail;
+ return status;
+
+ eem_opts->bind_count++;
+ retain_and_null_ptr(net);
DBG(cdev, "CDC Ethernet (EEM): IN/%s OUT/%s\n",
eem->port.in_ep->name, eem->port.out_ep->name);
return 0;
-
-fail:
- ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
- return status;
}
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
@@ -597,7 +592,7 @@ static void eem_free_inst(struct usb_function_instance *f)
struct f_eem_opts *opts;
opts = container_of(f, struct f_eem_opts, func_inst);
- if (opts->bound)
+ if (device_is_registered(&opts->net->dev))
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
@@ -640,9 +635,17 @@ static void eem_free(struct usb_function *f)
static void eem_unbind(struct usb_configuration *c, struct usb_function *f)
{
+ struct f_eem_opts *opts;
+
DBG(c->cdev, "eem unbind\n");
+ opts = container_of(f->fi, struct f_eem_opts, func_inst);
+
usb_free_all_descriptors(f);
+
+ opts->bind_count--;
+ if (opts->bind_count == 0 && !opts->bound)
+ gether_detach_gadget(opts->net);
}
static struct usb_function *eem_alloc(struct usb_function_instance *fi)
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 8c855c00b887..e5ccaec7750c 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -1207,9 +1207,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (!hidg->interval_user_set) {
hidg_fs_in_ep_desc.bInterval = 10;
hidg_hs_in_ep_desc.bInterval = 4;
+ hidg_ss_in_ep_desc.bInterval = 4;
} else {
hidg_fs_in_ep_desc.bInterval = hidg->interval;
hidg_hs_in_ep_desc.bInterval = hidg->interval;
+ hidg_ss_in_ep_desc.bInterval = hidg->interval;
}
hidg_ss_out_comp_desc.wBytesPerInterval =
@@ -1239,9 +1241,11 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (!hidg->interval_user_set) {
hidg_fs_out_ep_desc.bInterval = 10;
hidg_hs_out_ep_desc.bInterval = 4;
+ hidg_ss_out_ep_desc.bInterval = 4;
} else {
hidg_fs_out_ep_desc.bInterval = hidg->interval;
hidg_hs_out_ep_desc.bInterval = hidg->interval;
+ hidg_ss_out_ep_desc.bInterval = hidg->interval;
}
status = usb_assign_descriptors(f,
hidg_fs_descriptors_intout,
@@ -1258,17 +1262,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
if (status)
goto fail;
- spin_lock_init(&hidg->write_spinlock);
hidg->write_pending = 1;
hidg->req = NULL;
- spin_lock_init(&hidg->read_spinlock);
- spin_lock_init(&hidg->get_report_spinlock);
- init_waitqueue_head(&hidg->write_queue);
- init_waitqueue_head(&hidg->read_queue);
- init_waitqueue_head(&hidg->get_queue);
- init_waitqueue_head(&hidg->get_id_queue);
- INIT_LIST_HEAD(&hidg->completed_out_req);
- INIT_LIST_HEAD(&hidg->report_list);
INIT_WORK(&hidg->work, get_report_workqueue_handler);
hidg->workqueue = alloc_workqueue("report_work",
@@ -1604,6 +1599,16 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
mutex_lock(&opts->lock);
+ spin_lock_init(&hidg->write_spinlock);
+ spin_lock_init(&hidg->read_spinlock);
+ spin_lock_init(&hidg->get_report_spinlock);
+ init_waitqueue_head(&hidg->write_queue);
+ init_waitqueue_head(&hidg->read_queue);
+ init_waitqueue_head(&hidg->get_queue);
+ init_waitqueue_head(&hidg->get_id_queue);
+ INIT_LIST_HEAD(&hidg->completed_out_req);
+ INIT_LIST_HEAD(&hidg->report_list);
+
device_initialize(&hidg->dev);
hidg->dev.release = hidg_release;
hidg->dev.class = &hidg_class;
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 6af96e2b44eb..b7b06cb79ff5 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -180,6 +180,7 @@
#include <linux/kthread.h>
#include <linux/sched/signal.h>
#include <linux/limits.h>
+#include <linux/overflow.h>
#include <linux/pagemap.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
@@ -1853,8 +1854,15 @@ static int check_command_size_in_blocks(struct fsg_common *common,
int cmnd_size, enum data_direction data_dir,
unsigned int mask, int needs_medium, const char *name)
{
- if (common->curlun)
- common->data_size_from_cmnd <<= common->curlun->blkbits;
+ if (common->curlun) {
+ if (check_shl_overflow(common->data_size_from_cmnd,
+ common->curlun->blkbits,
+ &common->data_size_from_cmnd)) {
+ common->phase_error = 1;
+ return -EINVAL;
+ }
+ }
+
return check_command(common, cmnd_size, data_dir,
mask, needs_medium, name);
}
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 14fc7dce6f39..a6fa5ed3d6cb 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -83,11 +83,6 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
return container_of(f, struct f_ncm, port.func);
}
-static inline struct f_ncm_opts *func_to_ncm_opts(struct usb_function *f)
-{
- return container_of(f->fi, struct f_ncm_opts, func_inst);
-}
-
/*-------------------------------------------------------------------------*/
/*
@@ -864,7 +859,6 @@ invalid:
static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_ncm *ncm = func_to_ncm(f);
- struct f_ncm_opts *opts = func_to_ncm_opts(f);
struct usb_composite_dev *cdev = f->config->cdev;
/* Control interface has only altsetting 0 */
@@ -887,13 +881,12 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt > 1)
goto fail;
- scoped_guard(mutex, &opts->lock)
- if (opts->net) {
- DBG(cdev, "reset ncm\n");
- opts->net = NULL;
- gether_disconnect(&ncm->port);
- ncm_reset_values(ncm);
- }
+ if (ncm->netdev) {
+ DBG(cdev, "reset ncm\n");
+ ncm->netdev = NULL;
+ gether_disconnect(&ncm->port);
+ ncm_reset_values(ncm);
+ }
/*
* CDC Network only sends data in non-default altsettings.
@@ -926,8 +919,7 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
net = gether_connect(&ncm->port);
if (IS_ERR(net))
return PTR_ERR(net);
- scoped_guard(mutex, &opts->lock)
- opts->net = net;
+ ncm->netdev = net;
}
spin_lock(&ncm->lock);
@@ -1374,16 +1366,14 @@ err:
static void ncm_disable(struct usb_function *f)
{
struct f_ncm *ncm = func_to_ncm(f);
- struct f_ncm_opts *opts = func_to_ncm_opts(f);
struct usb_composite_dev *cdev = f->config->cdev;
DBG(cdev, "ncm deactivated\n");
- scoped_guard(mutex, &opts->lock)
- if (opts->net) {
- opts->net = NULL;
- gether_disconnect(&ncm->port);
- }
+ if (ncm->netdev) {
+ ncm->netdev = NULL;
+ gether_disconnect(&ncm->port);
+ }
if (ncm->notify->enabled) {
usb_ep_disable(ncm->notify);
@@ -1443,44 +1433,41 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_ncm *ncm = func_to_ncm(f);
- struct f_ncm_opts *ncm_opts = func_to_ncm_opts(f);
struct usb_string *us;
int status = 0;
struct usb_ep *ep;
+ struct f_ncm_opts *ncm_opts;
struct usb_os_desc_table *os_desc_table __free(kfree) = NULL;
- struct net_device *netdev __free(free_gether_netdev) = NULL;
+ struct net_device *net __free(detach_gadget) = NULL;
struct usb_request *request __free(free_usb_request) = NULL;
if (!can_support_ecm(cdev->gadget))
return -EINVAL;
+ ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
+
if (cdev->use_os_string) {
os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL);
if (!os_desc_table)
return -ENOMEM;
}
- netdev = gether_setup_default();
- if (IS_ERR(netdev))
- return -ENOMEM;
-
- scoped_guard(mutex, &ncm_opts->lock) {
- gether_apply_opts(netdev, &ncm_opts->net_opts);
- netdev->mtu = ncm_opts->max_segment_size - ETH_HLEN;
- }
-
- gether_set_gadget(netdev, cdev->gadget);
- status = gether_register_netdev(netdev);
- if (status)
- return status;
+ scoped_guard(mutex, &ncm_opts->lock)
+ if (ncm_opts->bind_count == 0) {
+ if (!device_is_registered(&ncm_opts->net->dev)) {
+ ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN);
+ gether_set_gadget(ncm_opts->net, cdev->gadget);
+ status = gether_register_netdev(ncm_opts->net);
+ } else
+ status = gether_attach_gadget(ncm_opts->net, cdev->gadget);
+
+ if (status)
+ return status;
+ net = ncm_opts->net;
+ }
- /* export host's Ethernet address in CDC format */
- status = gether_get_host_addr_cdc(netdev, ncm->ethaddr,
- sizeof(ncm->ethaddr));
- if (status < 12)
- return -EINVAL;
- ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
+ ncm_string_defs[1].s = ncm->ethaddr;
us = usb_gstrings_attach(cdev, ncm_strings,
ARRAY_SIZE(ncm_string_defs));
@@ -1578,8 +1565,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
f->os_desc_n = 1;
}
ncm->notify_req = no_free_ptr(request);
- ncm->netdev = no_free_ptr(netdev);
- ncm->port.ioport = netdev_priv(ncm->netdev);
+
+ ncm_opts->bind_count++;
+ retain_and_null_ptr(net);
DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n",
ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1594,19 +1582,19 @@ static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
}
/* f_ncm_item_ops */
-USB_ETHER_OPTS_ITEM(ncm);
+USB_ETHERNET_CONFIGFS_ITEM(ncm);
/* f_ncm_opts_dev_addr */
-USB_ETHER_OPTS_ATTR_DEV_ADDR(ncm);
+USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm);
/* f_ncm_opts_host_addr */
-USB_ETHER_OPTS_ATTR_HOST_ADDR(ncm);
+USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm);
/* f_ncm_opts_qmult */
-USB_ETHER_OPTS_ATTR_QMULT(ncm);
+USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
/* f_ncm_opts_ifname */
-USB_ETHER_OPTS_ATTR_IFNAME(ncm);
+USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
static ssize_t ncm_opts_max_segment_size_show(struct config_item *item,
char *page)
@@ -1672,27 +1660,34 @@ static void ncm_free_inst(struct usb_function_instance *f)
struct f_ncm_opts *opts;
opts = container_of(f, struct f_ncm_opts, func_inst);
+ if (device_is_registered(&opts->net->dev))
+ gether_cleanup(netdev_priv(opts->net));
+ else
+ free_netdev(opts->net);
kfree(opts->ncm_interf_group);
kfree(opts);
}
static struct usb_function_instance *ncm_alloc_inst(void)
{
- struct usb_function_instance *ret;
+ struct f_ncm_opts *opts;
struct usb_os_desc *descs[1];
char *names[1];
struct config_group *ncm_interf_group;
- struct f_ncm_opts *opts __free(kfree) = kzalloc_obj(*opts);
+ opts = kzalloc_obj(*opts);
if (!opts)
return ERR_PTR(-ENOMEM);
-
- opts->net = NULL;
opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;
- gether_setup_opts_default(&opts->net_opts, "usb");
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = ncm_free_inst;
+ opts->net = gether_setup_default();
+ if (IS_ERR(opts->net)) {
+ struct net_device *net = opts->net;
+ kfree(opts);
+ return ERR_CAST(net);
+ }
opts->max_segment_size = ETH_FRAME_LEN;
INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
@@ -1703,30 +1698,37 @@ static struct usb_function_instance *ncm_alloc_inst(void)
ncm_interf_group =
usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
names, THIS_MODULE);
- if (IS_ERR(ncm_interf_group))
+ if (IS_ERR(ncm_interf_group)) {
+ ncm_free_inst(&opts->func_inst);
return ERR_CAST(ncm_interf_group);
+ }
opts->ncm_interf_group = ncm_interf_group;
- ret = &opts->func_inst;
- retain_and_null_ptr(opts);
- return ret;
+ return &opts->func_inst;
}
static void ncm_free(struct usb_function *f)
{
- struct f_ncm_opts *opts = func_to_ncm_opts(f);
+ struct f_ncm *ncm;
+ struct f_ncm_opts *opts;
- scoped_guard(mutex, &opts->lock)
- opts->refcnt--;
- kfree(func_to_ncm(f));
+ ncm = func_to_ncm(f);
+ opts = container_of(f->fi, struct f_ncm_opts, func_inst);
+ kfree(ncm);
+ mutex_lock(&opts->lock);
+ opts->refcnt--;
+ mutex_unlock(&opts->lock);
}
static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_ncm *ncm = func_to_ncm(f);
+ struct f_ncm_opts *ncm_opts;
DBG(c->cdev, "ncm unbind\n");
+ ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
+
hrtimer_cancel(&ncm->task_timer);
kfree(f->os_desc_table);
@@ -1743,14 +1745,16 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
kfree(ncm->notify_req->buf);
usb_ep_free_request(ncm->notify, ncm->notify_req);
- ncm->port.ioport = NULL;
- gether_cleanup(netdev_priv(ncm->netdev));
+ ncm_opts->bind_count--;
+ if (ncm_opts->bind_count == 0)
+ gether_detach_gadget(ncm_opts->net);
}
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
{
struct f_ncm *ncm;
struct f_ncm_opts *opts;
+ int status;
/* allocate and initialize one new instance */
ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
@@ -1758,12 +1762,22 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_ncm_opts, func_inst);
+ mutex_lock(&opts->lock);
+ opts->refcnt++;
- scoped_guard(mutex, &opts->lock)
- opts->refcnt++;
+ /* export host's Ethernet address in CDC format */
+ status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
+ sizeof(ncm->ethaddr));
+ if (status < 12) { /* strlen("01234567890a") */
+ kfree(ncm);
+ mutex_unlock(&opts->lock);
+ return ERR_PTR(-EINVAL);
+ }
spin_lock_init(&ncm->lock);
ncm_reset_values(ncm);
+ ncm->port.ioport = netdev_priv(opts->net);
+ mutex_unlock(&opts->lock);
ncm->port.is_fixed = true;
ncm->port.supports_multi_frame = true;
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index 8b11d8d6d89c..7de1c5f8e326 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -11,6 +11,7 @@
/* #define VERBOSE_DEBUG */
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -665,6 +666,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
struct f_rndis_opts *rndis_opts;
struct usb_os_desc_table *os_desc_table __free(kfree) = NULL;
+ struct net_device *net __free(detach_gadget) = NULL;
struct usb_request *request __free(free_usb_request) = NULL;
if (!can_support_rndis(c))
@@ -678,23 +680,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
return -ENOMEM;
}
- rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
- rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
- rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
-
- /*
- * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
- * configurations are bound in sequence with list_for_each_entry,
- * in each configuration its functions are bound in sequence
- * with list_for_each_entry, so we assume no race condition
- * with regard to rndis_opts->bound access
- */
- if (!rndis_opts->bound) {
- gether_set_gadget(rndis_opts->net, cdev->gadget);
- status = gether_register_netdev(rndis_opts->net);
- if (status)
- return status;
- rndis_opts->bound = true;
+ scoped_guard(mutex, &rndis_opts->lock) {
+ rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
+ rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass;
+ rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol;
+
+ if (rndis_opts->bind_count == 0 && !rndis_opts->borrowed_net) {
+ if (!device_is_registered(&rndis_opts->net->dev)) {
+ gether_set_gadget(rndis_opts->net, cdev->gadget);
+ status = gether_register_netdev(rndis_opts->net);
+ } else
+ status = gether_attach_gadget(rndis_opts->net, cdev->gadget);
+
+ if (status)
+ return status;
+ net = rndis_opts->net;
+ }
}
us = usb_gstrings_attach(cdev, rndis_strings,
@@ -793,6 +794,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
}
rndis->notify_req = no_free_ptr(request);
+ rndis_opts->bind_count++;
+ retain_and_null_ptr(net);
+
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
* until we're activated via set_alt().
@@ -809,11 +813,11 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
struct f_rndis_opts *opts;
opts = container_of(f, struct f_rndis_opts, func_inst);
- if (opts->bound)
+ if (device_is_registered(&opts->net->dev))
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
- opts->borrowed_net = opts->bound = true;
+ opts->borrowed_net = true;
opts->net = net;
}
EXPORT_SYMBOL_GPL(rndis_borrow_net);
@@ -871,7 +875,7 @@ static void rndis_free_inst(struct usb_function_instance *f)
opts = container_of(f, struct f_rndis_opts, func_inst);
if (!opts->borrowed_net) {
- if (opts->bound)
+ if (device_is_registered(&opts->net->dev))
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
@@ -940,6 +944,9 @@ static void rndis_free(struct usb_function *f)
static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rndis *rndis = func_to_rndis(f);
+ struct f_rndis_opts *rndis_opts;
+
+ rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
kfree(f->os_desc_table);
f->os_desc_n = 0;
@@ -947,6 +954,10 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
kfree(rndis->notify_req->buf);
usb_ep_free_request(rndis->notify, rndis->notify_req);
+
+ rndis_opts->bind_count--;
+ if (rndis_opts->bind_count == 0 && !rndis_opts->borrowed_net)
+ gether_detach_gadget(rndis_opts->net);
}
static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 076072386e5e..6e3265b8a3a0 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -6,6 +6,7 @@
* Copyright (C) 2008 Nokia Corporation
*/
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -298,25 +299,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
struct f_gether_opts *gether_opts;
+ struct net_device *net __free(detach_gadget) = NULL;
gether_opts = container_of(f->fi, struct f_gether_opts, func_inst);
- /*
- * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
- * configurations are bound in sequence with list_for_each_entry,
- * in each configuration its functions are bound in sequence
- * with list_for_each_entry, so we assume no race condition
- * with regard to gether_opts->bound access
- */
- if (!gether_opts->bound) {
- mutex_lock(&gether_opts->lock);
- gether_set_gadget(gether_opts->net, cdev->gadget);
- status = gether_register_netdev(gether_opts->net);
- mutex_unlock(&gether_opts->lock);
- if (status)
- return status;
- gether_opts->bound = true;
- }
+ scoped_guard(mutex, &gether_opts->lock)
+ if (gether_opts->bind_count == 0 && !gether_opts->bound) {
+ if (!device_is_registered(&gether_opts->net->dev)) {
+ gether_set_gadget(gether_opts->net, cdev->gadget);
+ status = gether_register_netdev(gether_opts->net);
+ } else
+ status = gether_attach_gadget(gether_opts->net, cdev->gadget);
+
+ if (status)
+ return status;
+ net = gether_opts->net;
+ }
us = usb_gstrings_attach(cdev, geth_strings,
ARRAY_SIZE(geth_string_defs));
@@ -329,20 +327,18 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
- goto fail;
+ return status;
subset_data_intf.bInterfaceNumber = status;
- status = -ENODEV;
-
/* allocate instance-specific endpoints */
ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc);
if (!ep)
- goto fail;
+ return -ENODEV;
geth->port.in_ep = ep;
ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc);
if (!ep)
- goto fail;
+ return -ENODEV;
geth->port.out_ep = ep;
/* support all relevant hardware speeds... we expect that when
@@ -360,21 +356,19 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
ss_eth_function, ss_eth_function);
if (status)
- goto fail;
+ return status;
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
* until we're activated via set_alt().
*/
+ gether_opts->bind_count++;
+ retain_and_null_ptr(net);
+
DBG(cdev, "CDC Subset: IN/%s OUT/%s\n",
geth->port.in_ep->name, geth->port.out_ep->name);
return 0;
-
-fail:
- ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
- return status;
}
static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item)
@@ -417,7 +411,7 @@ static void geth_free_inst(struct usb_function_instance *f)
struct f_gether_opts *opts;
opts = container_of(f, struct f_gether_opts, func_inst);
- if (opts->bound)
+ if (device_is_registered(&opts->net->dev))
gether_cleanup(netdev_priv(opts->net));
else
free_netdev(opts->net);
@@ -449,15 +443,28 @@ static struct usb_function_instance *geth_alloc_inst(void)
static void geth_free(struct usb_function *f)
{
struct f_gether *eth;
+ struct f_gether_opts *opts;
+
+ opts = container_of(f->fi, struct f_gether_opts, func_inst);
eth = func_to_geth(f);
+ scoped_guard(mutex, &opts->lock)
+ opts->refcnt--;
kfree(eth);
}
static void geth_unbind(struct usb_configuration *c, struct usb_function *f)
{
+ struct f_gether_opts *opts;
+
+ opts = container_of(f->fi, struct f_gether_opts, func_inst);
+
geth_string_defs[0].id = 0;
usb_free_all_descriptors(f);
+
+ opts->bind_count--;
+ if (opts->bind_count == 0 && !opts->bound)
+ gether_detach_gadget(opts->net);
}
static struct usb_function *geth_alloc(struct usb_function_instance *fi)
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index ec050d8f99f1..a7853dcbb14c 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1222,6 +1222,13 @@ static void usbg_submit_cmd(struct usbg_cmd *cmd)
se_cmd = &cmd->se_cmd;
tpg = cmd->fu->tpg;
tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ struct usb_gadget *gadget = fuas_to_gadget(cmd->fu);
+
+ dev_err(&gadget->dev, "Missing nexus, ignoring command\n");
+ return;
+ }
+
dir = get_cmd_dir(cmd->cmd_buf);
if (dir < 0)
goto out;
@@ -1483,6 +1490,13 @@ static void bot_cmd_work(struct work_struct *work)
se_cmd = &cmd->se_cmd;
tpg = cmd->fu->tpg;
tv_nexus = tpg->tpg_nexus;
+ if (!tv_nexus) {
+ struct usb_gadget *gadget = fuas_to_gadget(cmd->fu);
+
+ dev_err(&gadget->dev, "Missing nexus, ignoring command\n");
+ return;
+ }
+
dir = get_cmd_dir(cmd->cmd_buf);
if (dir < 0)
goto out;
diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c
index a0c953a99727..5d201a2e30e7 100644
--- a/drivers/usb/gadget/function/f_uac1_legacy.c
+++ b/drivers/usb/gadget/function/f_uac1_legacy.c
@@ -360,19 +360,46 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_audio *audio = req->context;
- int status = req->status;
- u32 data = 0;
struct usb_ep *out_ep = audio->out_ep;
- switch (status) {
-
- case 0: /* normal completion? */
- if (ep == out_ep)
+ switch (req->status) {
+ case 0:
+ if (ep == out_ep) {
f_audio_out_ep_complete(ep, req);
- else if (audio->set_con) {
- memcpy(&data, req->buf, req->length);
- audio->set_con->set(audio->set_con, audio->set_cmd,
- le16_to_cpu(data));
+ } else if (audio->set_con) {
+ struct usb_audio_control *con = audio->set_con;
+ u8 type = con->type;
+ u32 data;
+ bool valid_request = false;
+
+ switch (type) {
+ case UAC_FU_MUTE: {
+ u8 value;
+
+ if (req->actual == sizeof(value)) {
+ memcpy(&value, req->buf, sizeof(value));
+ data = value;
+ valid_request = true;
+ }
+ break;
+ }
+ case UAC_FU_VOLUME: {
+ __le16 value;
+
+ if (req->actual == sizeof(value)) {
+ memcpy(&value, req->buf, sizeof(value));
+ data = le16_to_cpu(value);
+ valid_request = true;
+ }
+ break;
+ }
+ }
+
+ if (valid_request)
+ con->set(con, audio->set_cmd, data);
+ else
+ usb_ep_set_halt(ep);
+
audio->set_con = NULL;
}
break;
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 494fdbc4e85b..8d404d88391c 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -413,6 +413,12 @@ uvc_function_disconnect(struct uvc_device *uvc)
{
int ret;
+ guard(mutex)(&uvc->lock);
+ if (uvc->func_unbound) {
+ dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n");
+ return;
+ }
+
if ((ret = usb_function_deactivate(&uvc->func)) < 0)
uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
}
@@ -431,6 +437,15 @@ static ssize_t function_name_show(struct device *dev,
static DEVICE_ATTR_RO(function_name);
+static void uvc_vdev_release(struct video_device *vdev)
+{
+ struct uvc_device *uvc = video_get_drvdata(vdev);
+
+ /* Signal uvc_function_unbind() that the video device has been released */
+ if (uvc->vdev_release_done)
+ complete(uvc->vdev_release_done);
+}
+
static int
uvc_register_video(struct uvc_device *uvc)
{
@@ -443,7 +458,7 @@ uvc_register_video(struct uvc_device *uvc)
uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev;
uvc->vdev.fops = &uvc_v4l2_fops;
uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops;
- uvc->vdev.release = video_device_release_empty;
+ uvc->vdev.release = uvc_vdev_release;
uvc->vdev.vfl_dir = VFL_DIR_TX;
uvc->vdev.lock = &uvc->video.mutex;
uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -659,6 +674,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
int ret = -EINVAL;
uvcg_info(f, "%s()\n", __func__);
+ scoped_guard(mutex, &uvc->lock)
+ uvc->func_unbound = false;
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters. */
@@ -988,12 +1005,19 @@ static void uvc_free(struct usb_function *f)
static void uvc_function_unbind(struct usb_configuration *c,
struct usb_function *f)
{
+ DECLARE_COMPLETION_ONSTACK(vdev_release_done);
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
struct uvc_video *video = &uvc->video;
long wait_ret = 1;
+ bool connected;
uvcg_info(f, "%s()\n", __func__);
+ scoped_guard(mutex, &uvc->lock) {
+ uvc->func_unbound = true;
+ uvc->vdev_release_done = &vdev_release_done;
+ connected = uvc->func_connected;
+ }
kthread_cancel_work_sync(&video->hw_submit);
@@ -1006,7 +1030,7 @@ static void uvc_function_unbind(struct usb_configuration *c,
* though the video device removal uevent. Allow some time for the
* application to close out before things get deleted.
*/
- if (uvc->func_connected) {
+ if (connected) {
uvcg_dbg(f, "waiting for clean disconnect\n");
wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
uvc->func_connected == false, msecs_to_jiffies(500));
@@ -1017,7 +1041,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
video_unregister_device(&uvc->vdev);
v4l2_device_unregister(&uvc->v4l2_dev);
- if (uvc->func_connected) {
+ scoped_guard(mutex, &uvc->lock)
+ connected = uvc->func_connected;
+
+ if (connected) {
/*
* Wait for the release to occur to ensure there are no longer any
* pending operations that may cause panics when resources are cleaned
@@ -1029,6 +1056,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
}
+ /* Wait for the video device to be released */
+ wait_for_completion(&vdev_release_done);
+ uvc->vdev_release_done = NULL;
+
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);
@@ -1047,6 +1078,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
return ERR_PTR(-ENOMEM);
mutex_init(&uvc->video.mutex);
+ mutex_init(&uvc->lock);
+ uvc->func_unbound = true;
uvc->state = UVC_STATE_DISCONNECTED;
init_waitqueue_head(&uvc->func_connected_queue);
opts = fi_to_f_uvc_opts(fi);
diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h
index 77cfb89932be..7f666b9dea02 100644
--- a/drivers/usb/gadget/function/u_ecm.h
+++ b/drivers/usb/gadget/function/u_ecm.h
@@ -15,17 +15,26 @@
#include <linux/usb/composite.h>
+/**
+ * struct f_ecm_opts - ECM function options
+ * @func_inst: USB function instance.
+ * @net: The net_device associated with the ECM function.
+ * @bound: True if the net_device is shared and pre-registered during the
+ * legacy composite driver's bind phase (e.g., multi.c). If false,
+ * the ECM function will register the net_device during its own
+ * bind phase.
+ * @bind_count: Tracks the number of configurations the ECM function is
+ * bound to, preventing double-registration of the @net device.
+ * @lock: Protects the data from concurrent access by configfs read/write
+ * and create symlink/remove symlink operations.
+ * @refcnt: Reference counter for the function instance.
+ */
struct f_ecm_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
+ int bind_count;
- /*
- * Read/write access to configfs attributes is handled by configfs.
- *
- * This is to protect the data from concurrent access by read/write
- * and create symlink/remove symlink.
- */
struct mutex lock;
int refcnt;
};
diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/function/u_eem.h
index 3bd85dfcd71c..78ef55815219 100644
--- a/drivers/usb/gadget/function/u_eem.h
+++ b/drivers/usb/gadget/function/u_eem.h
@@ -15,17 +15,26 @@
#include <linux/usb/composite.h>
+/**
+ * struct f_eem_opts - EEM function options
+ * @func_inst: USB function instance.
+ * @net: The net_device associated with the EEM function.
+ * @bound: True if the net_device is shared and pre-registered during the
+ * legacy composite driver's bind phase (e.g., multi.c). If false,
+ * the EEM function will register the net_device during its own
+ * bind phase.
+ * @bind_count: Tracks the number of configurations the EEM function is
+ * bound to, preventing double-registration of the @net device.
+ * @lock: Protects the data from concurrent access by configfs read/write
+ * and create symlink/remove symlink operations.
+ * @refcnt: Reference counter for the function instance.
+ */
struct f_eem_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
+ int bind_count;
- /*
- * Read/write access to configfs attributes is handled by configfs.
- *
- * This is to protect the data from concurrent access by read/write
- * and create symlink/remove symlink.
- */
struct mutex lock;
int refcnt;
};
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 338f6e2a85a9..59d85d6a84a8 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -113,8 +113,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
strscpy(p->driver, "g_ether", sizeof(p->driver));
strscpy(p->version, UETH__VERSION, sizeof(p->version));
- strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
- strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
+ if (dev->gadget) {
+ strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+ strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
+ }
}
/* REVISIT can also support:
@@ -897,6 +899,28 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
}
EXPORT_SYMBOL_GPL(gether_set_gadget);
+int gether_attach_gadget(struct net_device *net, struct usb_gadget *g)
+{
+ int ret;
+
+ ret = device_move(&net->dev, &g->dev, DPM_ORDER_DEV_AFTER_PARENT);
+ if (ret)
+ return ret;
+
+ gether_set_gadget(net, g);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gether_attach_gadget);
+
+void gether_detach_gadget(struct net_device *net)
+{
+ struct eth_dev *dev = netdev_priv(net);
+
+ device_move(&net->dev, NULL, DPM_ORDER_NONE);
+ dev->gadget = NULL;
+}
+EXPORT_SYMBOL_GPL(gether_detach_gadget);
+
int gether_set_dev_addr(struct net_device *net, const char *dev_addr)
{
struct eth_dev *dev;
@@ -1040,36 +1064,6 @@ int gether_set_ifname(struct net_device *net, const char *name, int len)
}
EXPORT_SYMBOL_GPL(gether_set_ifname);
-void gether_setup_opts_default(struct gether_opts *opts, const char *name)
-{
- opts->qmult = QMULT_DEFAULT;
- snprintf(opts->name, sizeof(opts->name), "%s%%d", name);
- eth_random_addr(opts->dev_mac);
- opts->addr_assign_type = NET_ADDR_RANDOM;
- eth_random_addr(opts->host_mac);
-}
-EXPORT_SYMBOL_GPL(gether_setup_opts_default);
-
-void gether_apply_opts(struct net_device *net, struct gether_opts *opts)
-{
- struct eth_dev *dev = netdev_priv(net);
-
- dev->qmult = opts->qmult;
-
- if (opts->ifname_set) {
- strscpy(net->name, opts->name, sizeof(net->name));
- dev->ifname_set = true;
- }
-
- memcpy(dev->host_mac, opts->host_mac, sizeof(dev->host_mac));
-
- if (opts->addr_assign_type == NET_ADDR_SET) {
- memcpy(dev->dev_mac, opts->dev_mac, sizeof(dev->dev_mac));
- net->addr_assign_type = opts->addr_assign_type;
- }
-}
-EXPORT_SYMBOL_GPL(gether_apply_opts);
-
void gether_suspend(struct gether *link)
{
struct eth_dev *dev = link->ioport;
@@ -1126,21 +1120,6 @@ void gether_cleanup(struct eth_dev *dev)
}
EXPORT_SYMBOL_GPL(gether_cleanup);
-void gether_unregister_free_netdev(struct net_device *net)
-{
- if (!net)
- return;
-
- struct eth_dev *dev = netdev_priv(net);
-
- if (net->reg_state == NETREG_REGISTERED) {
- unregister_netdev(net);
- flush_work(&dev->work);
- }
- free_netdev(net);
-}
-EXPORT_SYMBOL_GPL(gether_unregister_free_netdev);
-
/**
* gether_connect - notify network layer that USB link is active
* @link: the USB link, set up with endpoints, descriptors matching
@@ -1246,6 +1225,11 @@ void gether_disconnect(struct gether *link)
DBG(dev, "%s\n", __func__);
+ spin_lock(&dev->lock);
+ dev->port_usb = NULL;
+ link->is_suspend = false;
+ spin_unlock(&dev->lock);
+
netif_stop_queue(dev->net);
netif_carrier_off(dev->net);
@@ -1283,11 +1267,6 @@ void gether_disconnect(struct gether *link)
dev->header_len = 0;
dev->unwrap = NULL;
dev->wrap = NULL;
-
- spin_lock(&dev->lock);
- dev->port_usb = NULL;
- link->is_suspend = false;
- spin_unlock(&dev->lock);
}
EXPORT_SYMBOL_GPL(gether_disconnect);
diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h
index a212a8ec5eb1..c85a1cf3c115 100644
--- a/drivers/usb/gadget/function/u_ether.h
+++ b/drivers/usb/gadget/function/u_ether.h
@@ -38,31 +38,6 @@
struct eth_dev;
-/**
- * struct gether_opts - Options for Ethernet gadget function instances
- * @name: Pattern for the network interface name (e.g., "usb%d").
- * Used to generate the net device name.
- * @qmult: Queue length multiplier for high/super speed.
- * @host_mac: The MAC address to be used by the host side.
- * @dev_mac: The MAC address to be used by the device side.
- * @ifname_set: True if the interface name pattern has been set by userspace.
- * @addr_assign_type: The method used for assigning the device MAC address
- * (e.g., NET_ADDR_RANDOM, NET_ADDR_SET).
- *
- * This structure caches network-related settings provided through configfs
- * before the net_device is fully instantiated. This allows for early
- * configuration while deferring net_device allocation until the function
- * is bound.
- */
-struct gether_opts {
- char name[IFNAMSIZ];
- unsigned int qmult;
- u8 host_mac[ETH_ALEN];
- u8 dev_mac[ETH_ALEN];
- bool ifname_set;
- unsigned char addr_assign_type;
-};
-
/*
* This represents the USB side of an "ethernet" link, managed by a USB
* function which provides control and (maybe) framing. Two functions
@@ -176,6 +151,32 @@ static inline struct net_device *gether_setup_default(void)
void gether_set_gadget(struct net_device *net, struct usb_gadget *g);
/**
+ * gether_attach_gadget - Reparent net_device to the gadget device.
+ * @net: The network device to reparent.
+ * @g: The target USB gadget device to parent to.
+ *
+ * This function moves the network device to be a child of the USB gadget
+ * device in the device hierarchy. This is typically done when the function
+ * is bound to a configuration.
+ *
+ * Returns 0 on success, or a negative error code on failure.
+ */
+int gether_attach_gadget(struct net_device *net, struct usb_gadget *g);
+
+/**
+ * gether_detach_gadget - Detach net_device from its gadget parent.
+ * @net: The network device to detach.
+ *
+ * This function moves the network device to be a child of the virtual
+ * devices parent, effectively detaching it from the USB gadget device
+ * hierarchy. This is typically done when the function is unbound
+ * from a configuration but the instance is not yet freed.
+ */
+void gether_detach_gadget(struct net_device *net);
+
+DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T))
+
+/**
* gether_set_dev_addr - initialize an ethernet-over-usb link with eth address
* @net: device representing this link
* @dev_addr: eth address of this device
@@ -283,11 +284,6 @@ int gether_get_ifname(struct net_device *net, char *name, int len);
int gether_set_ifname(struct net_device *net, const char *name, int len);
void gether_cleanup(struct eth_dev *dev);
-void gether_unregister_free_netdev(struct net_device *net);
-DEFINE_FREE(free_gether_netdev, struct net_device *, gether_unregister_free_netdev(_T));
-
-void gether_setup_opts_default(struct gether_opts *opts, const char *name);
-void gether_apply_opts(struct net_device *net, struct gether_opts *opts);
void gether_suspend(struct gether *link);
void gether_resume(struct gether *link);
diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h
index 217990a266b2..51f0d79e5eca 100644
--- a/drivers/usb/gadget/function/u_ether_configfs.h
+++ b/drivers/usb/gadget/function/u_ether_configfs.h
@@ -13,13 +13,6 @@
#ifndef __U_ETHER_CONFIGFS_H
#define __U_ETHER_CONFIGFS_H
-#include <linux/cleanup.h>
-#include <linux/hex.h>
-#include <linux/if_ether.h>
-#include <linux/mutex.h>
-#include <linux/netdevice.h>
-#include <linux/rtnetlink.h>
-
#define USB_ETHERNET_CONFIGFS_ITEM(_f_) \
static void _f_##_attr_release(struct config_item *item) \
{ \
@@ -204,174 +197,4 @@ out: \
\
CONFIGFS_ATTR(_f_##_opts_, _n_)
-#define USB_ETHER_OPTS_ITEM(_f_) \
- static void _f_##_attr_release(struct config_item *item) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- \
- usb_put_function_instance(&opts->func_inst); \
- } \
- \
- static struct configfs_item_operations _f_##_item_ops = { \
- .release = _f_##_attr_release, \
- }
-
-#define USB_ETHER_OPTS_ATTR_DEV_ADDR(_f_) \
- static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \
- char *page) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- \
- guard(mutex)(&opts->lock); \
- return sysfs_emit(page, "%pM\n", opts->net_opts.dev_mac); \
- } \
- \
- static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \
- const char *page, size_t len) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- u8 new_addr[ETH_ALEN]; \
- const char *p = page; \
- \
- guard(mutex)(&opts->lock); \
- if (opts->refcnt) \
- return -EBUSY; \
- \
- for (int i = 0; i < ETH_ALEN; i++) { \
- unsigned char num; \
- if ((*p == '.') || (*p == ':')) \
- p++; \
- num = hex_to_bin(*p++) << 4; \
- num |= hex_to_bin(*p++); \
- new_addr[i] = num; \
- } \
- if (!is_valid_ether_addr(new_addr)) \
- return -EINVAL; \
- memcpy(opts->net_opts.dev_mac, new_addr, ETH_ALEN); \
- opts->net_opts.addr_assign_type = NET_ADDR_SET; \
- return len; \
- } \
- \
- CONFIGFS_ATTR(_f_##_opts_, dev_addr)
-
-#define USB_ETHER_OPTS_ATTR_HOST_ADDR(_f_) \
- static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \
- char *page) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- \
- guard(mutex)(&opts->lock); \
- return sysfs_emit(page, "%pM\n", opts->net_opts.host_mac); \
- } \
- \
- static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \
- const char *page, size_t len) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- u8 new_addr[ETH_ALEN]; \
- const char *p = page; \
- \
- guard(mutex)(&opts->lock); \
- if (opts->refcnt) \
- return -EBUSY; \
- \
- for (int i = 0; i < ETH_ALEN; i++) { \
- unsigned char num; \
- if ((*p == '.') || (*p == ':')) \
- p++; \
- num = hex_to_bin(*p++) << 4; \
- num |= hex_to_bin(*p++); \
- new_addr[i] = num; \
- } \
- if (!is_valid_ether_addr(new_addr)) \
- return -EINVAL; \
- memcpy(opts->net_opts.host_mac, new_addr, ETH_ALEN); \
- return len; \
- } \
- \
- CONFIGFS_ATTR(_f_##_opts_, host_addr)
-
-#define USB_ETHER_OPTS_ATTR_QMULT(_f_) \
- static ssize_t _f_##_opts_qmult_show(struct config_item *item, \
- char *page) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- \
- guard(mutex)(&opts->lock); \
- return sysfs_emit(page, "%u\n", opts->net_opts.qmult); \
- } \
- \
- static ssize_t _f_##_opts_qmult_store(struct config_item *item, \
- const char *page, size_t len) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- u32 val; \
- int ret; \
- \
- guard(mutex)(&opts->lock); \
- if (opts->refcnt) \
- return -EBUSY; \
- \
- ret = kstrtou32(page, 0, &val); \
- if (ret) \
- return ret; \
- \
- opts->net_opts.qmult = val; \
- return len; \
- } \
- \
- CONFIGFS_ATTR(_f_##_opts_, qmult)
-
-#define USB_ETHER_OPTS_ATTR_IFNAME(_f_) \
- static ssize_t _f_##_opts_ifname_show(struct config_item *item, \
- char *page) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- const char *name; \
- \
- guard(mutex)(&opts->lock); \
- rtnl_lock(); \
- if (opts->net_opts.ifname_set) \
- name = opts->net_opts.name; \
- else if (opts->net) \
- name = netdev_name(opts->net); \
- else \
- name = "(inactive net_device)"; \
- rtnl_unlock(); \
- return sysfs_emit(page, "%s\n", name); \
- } \
- \
- static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
- const char *page, size_t len) \
- { \
- struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
- char tmp[IFNAMSIZ]; \
- const char *p; \
- size_t c_len = len; \
- \
- if (c_len > 0 && page[c_len - 1] == '\n') \
- c_len--; \
- \
- if (c_len >= sizeof(tmp)) \
- return -E2BIG; \
- \
- strscpy(tmp, page, c_len + 1); \
- if (!dev_valid_name(tmp)) \
- return -EINVAL; \
- \
- /* Require exactly one %d */ \
- p = strchr(tmp, '%'); \
- if (!p || p[1] != 'd' || strchr(p + 2, '%')) \
- return -EINVAL; \
- \
- guard(mutex)(&opts->lock); \
- if (opts->refcnt) \
- return -EBUSY; \
- strscpy(opts->net_opts.name, tmp, sizeof(opts->net_opts.name)); \
- opts->net_opts.ifname_set = true; \
- return len; \
- } \
- \
- CONFIGFS_ATTR(_f_##_opts_, ifname)
-
#endif /* __U_ETHER_CONFIGFS_H */
diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/function/u_gether.h
index 2f7a373ed449..e7b6b51f69c1 100644
--- a/drivers/usb/gadget/function/u_gether.h
+++ b/drivers/usb/gadget/function/u_gether.h
@@ -15,17 +15,25 @@
#include <linux/usb/composite.h>
+/**
+ * struct f_gether_opts - subset function options
+ * @func_inst: USB function instance.
+ * @net: The net_device associated with the subset function.
+ * @bound: True if the net_device is shared and pre-registered during the
+ * legacy composite driver's bind phase (e.g., multi.c). If false,
+ * the subset function will register the net_device during its own
+ * bind phase.
+ * @bind_count: Tracks the number of configurations the subset function is
+ * bound to, preventing double-registration of the @net device.
+ * @lock: Protects the data from concurrent access by configfs read/write
+ * and create symlink/remove symlink operations.
+ * @refcnt: Reference counter for the function instance.
+ */
struct f_gether_opts {
struct usb_function_instance func_inst;
struct net_device *net;
bool bound;
-
- /*
- * Read/write access to configfs attributes is handled by configfs.
- *
- * This is to protect the data from concurrent access by read/write
- * and create symlink/remove symlink.
- */
+ int bind_count;
struct mutex lock;
int refcnt;
};
diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h
index d99330fe31e8..ce2f6358688a 100644
--- a/drivers/usb/gadget/function/u_ncm.h
+++ b/drivers/usb/gadget/function/u_ncm.h
@@ -15,22 +15,29 @@
#include <linux/usb/composite.h>
-#include "u_ether.h"
-
+/**
+ * struct f_ncm_opts - NCM function options
+ * @func_inst: USB function instance.
+ * @net: The net_device associated with the NCM function.
+ * @bind_count: Tracks the number of configurations the NCM function is
+ * bound to, preventing double-registration of the @net device.
+ * @ncm_interf_group: ConfigFS group for NCM interface.
+ * @ncm_os_desc: USB OS descriptor for NCM.
+ * @ncm_ext_compat_id: Extended compatibility ID.
+ * @lock: Protects the data from concurrent access by configfs read/write
+ * and create symlink/remove symlink operations.
+ * @refcnt: Reference counter for the function instance.
+ * @max_segment_size: Maximum segment size.
+ */
struct f_ncm_opts {
struct usb_function_instance func_inst;
struct net_device *net;
+ int bind_count;
- struct gether_opts net_opts;
struct config_group *ncm_interf_group;
struct usb_os_desc ncm_os_desc;
char ncm_ext_compat_id[16];
- /*
- * Read/write access to configfs attributes is handled by configfs.
- *
- * This is to protect the data from concurrent access by read/write
- * and create symlink/remove symlink.
- */
+
struct mutex lock;
int refcnt;
diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h
index a8c409b2f52f..4e64619714dc 100644
--- a/drivers/usb/gadget/function/u_rndis.h
+++ b/drivers/usb/gadget/function/u_rndis.h
@@ -15,12 +15,34 @@
#include <linux/usb/composite.h>
+/**
+ * struct f_rndis_opts - RNDIS function options
+ * @func_inst: USB function instance.
+ * @vendor_id: Vendor ID.
+ * @manufacturer: Manufacturer string.
+ * @net: The net_device associated with the RNDIS function.
+ * @bind_count: Tracks the number of configurations the RNDIS function is
+ * bound to, preventing double-registration of the @net device.
+ * @borrowed_net: True if the net_device is shared and pre-registered during
+ * the legacy composite driver's bind phase (e.g., multi.c).
+ * If false, the RNDIS function will register the net_device
+ * during its own bind phase.
+ * @rndis_interf_group: ConfigFS group for RNDIS interface.
+ * @rndis_os_desc: USB OS descriptor for RNDIS.
+ * @rndis_ext_compat_id: Extended compatibility ID.
+ * @class: USB class.
+ * @subclass: USB subclass.
+ * @protocol: USB protocol.
+ * @lock: Protects the data from concurrent access by configfs read/write
+ * and create symlink/remove symlink operations.
+ * @refcnt: Reference counter for the function instance.
+ */
struct f_rndis_opts {
struct usb_function_instance func_inst;
u32 vendor_id;
const char *manufacturer;
struct net_device *net;
- bool bound;
+ int bind_count;
bool borrowed_net;
struct config_group *rndis_interf_group;
@@ -30,13 +52,6 @@ struct f_rndis_opts {
u8 class;
u8 subclass;
u8 protocol;
-
- /*
- * Read/write access to configfs attributes is handled by configfs.
- *
- * This is to protect the data from concurrent access by read/write
- * and create symlink/remove symlink.
- */
struct mutex lock;
int refcnt;
};
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 676419a04976..7abfdd5e1eef 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -155,6 +155,9 @@ struct uvc_device {
enum uvc_state state;
struct usb_function func;
struct uvc_video video;
+ struct completion *vdev_release_done;
+ struct mutex lock; /* protects func_unbound and func_connected */
+ bool func_unbound;
bool func_connected;
wait_queue_head_t func_connected_queue;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index ed48d38498fb..514e5930b9ca 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -574,6 +574,8 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
return -EINVAL;
+ guard(mutex)(&uvc->lock);
+
if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
return -EBUSY;
@@ -595,7 +597,8 @@ static void uvc_v4l2_disable(struct uvc_device *uvc)
uvc_function_disconnect(uvc);
uvcg_video_disable(&uvc->video);
uvcg_free_buffers(&uvc->video.queue);
- uvc->func_connected = false;
+ scoped_guard(mutex, &uvc->lock)
+ uvc->func_connected = false;
wake_up_interruptible(&uvc->func_connected_queue);
}
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 7cea641b06b4..2f9700b3f1b6 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -513,7 +513,7 @@ uvc_video_prep_requests(struct uvc_video *video)
return;
}
- interval_duration = 2 << (video->ep->desc->bInterval - 1);
+ interval_duration = 1 << (video->ep->desc->bInterval - 1);
if (cdev->gadget->speed < USB_SPEED_HIGH)
interval_duration *= 10000;
else
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index c9eca90376e2..f094491b1041 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -462,8 +462,13 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
/* Report reset and disconnect events to the driver */
if (dum->ints_enabled && (disconnect || reset)) {
- stop_activity(dum);
++dum->callback_usage;
+ /*
+ * stop_activity() can drop dum->lock, so it must
+ * not come between the dum->ints_enabled test
+ * and the ++dum->callback_usage.
+ */
+ stop_activity(dum);
spin_unlock(&dum->lock);
if (reset)
usb_gadget_udc_reset(&dum->gadget, dum->driver);
@@ -908,21 +913,6 @@ static int dummy_pullup(struct usb_gadget *_gadget, int value)
spin_lock_irqsave(&dum->lock, flags);
dum->pullup = (value != 0);
set_link_state(dum_hcd);
- if (value == 0) {
- /*
- * Emulate synchronize_irq(): wait for callbacks to finish.
- * This seems to be the best place to emulate the call to
- * synchronize_irq() that's in usb_gadget_remove_driver().
- * Doing it in dummy_udc_stop() would be too late since it
- * is called after the unbind callback and unbind shouldn't
- * be invoked until all the other callbacks are finished.
- */
- while (dum->callback_usage > 0) {
- spin_unlock_irqrestore(&dum->lock, flags);
- usleep_range(1000, 2000);
- spin_lock_irqsave(&dum->lock, flags);
- }
- }
spin_unlock_irqrestore(&dum->lock, flags);
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
@@ -945,6 +935,20 @@ static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable)
spin_lock_irq(&dum->lock);
dum->ints_enabled = enable;
+ if (!enable) {
+ /*
+ * Emulate synchronize_irq(): wait for callbacks to finish.
+ * This has to happen after emulated interrupts are disabled
+ * (dum->ints_enabled is clear) and before the unbind callback,
+ * just like the call to synchronize_irq() in
+ * gadget/udc/core:gadget_unbind_driver().
+ */
+ while (dum->callback_usage > 0) {
+ spin_unlock_irq(&dum->lock);
+ usleep_range(1000, 2000);
+ spin_lock_irq(&dum->lock);
+ }
+ }
spin_unlock_irq(&dum->lock);
}
@@ -1534,6 +1538,12 @@ top:
/* rescan to continue with any other queued i/o */
if (rescan)
goto top;
+
+ /* request not fully transferred; stop iterating to
+ * preserve data ordering across queued requests.
+ */
+ if (req->req.actual < req->req.length)
+ break;
}
return sent;
}
diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c
index 888e8f6670d2..5e3156f94cc6 100644
--- a/drivers/usb/host/ehci-brcm.c
+++ b/drivers/usb/host/ehci-brcm.c
@@ -31,8 +31,8 @@ static inline void ehci_brcm_wait_for_sof(struct ehci_hcd *ehci, u32 delay)
int res;
/* Wait for next microframe (every 125 usecs) */
- res = readl_relaxed_poll_timeout(&ehci->regs->frame_index, val,
- val != frame_idx, 1, 130);
+ res = readl_relaxed_poll_timeout_atomic(&ehci->regs->frame_index,
+ val, val != frame_idx, 1, 130);
if (res)
ehci_err(ehci, "Error waiting for SOF\n");
udelay(delay);
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 890fc5e892f1..ade178ab34a7 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -386,11 +386,19 @@ static const struct file_operations port_fops = {
static int xhci_portli_show(struct seq_file *s, void *unused)
{
struct xhci_port *port = s->private;
- struct xhci_hcd *xhci = hcd_to_xhci(port->rhub->hcd);
+ struct xhci_hcd *xhci;
u32 portli;
portli = readl(&port->port_reg->portli);
+ /* port without protocol capability isn't added to a roothub */
+ if (!port->rhub) {
+ seq_printf(s, "0x%08x\n", portli);
+ return 0;
+ }
+
+ xhci = hcd_to_xhci(port->rhub->hcd);
+
/* PORTLI fields are valid if port is a USB3 or eUSB2V2 port */
if (port->rhub == &xhci->usb3_rhub)
seq_printf(s, "0x%08x LEC=%u RLC=%u TLC=%u\n", portli,
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9315ba18310d..1cbefee3c4ca 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3195,6 +3195,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (status & STS_HCE) {
xhci_warn(xhci, "WARNING: Host Controller Error\n");
+ xhci_halt(xhci);
goto out;
}
diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c
index abbcc0e44f1b..23153e136d4b 100644
--- a/drivers/usb/host/xhci-sideband.c
+++ b/drivers/usb/host/xhci-sideband.c
@@ -93,8 +93,6 @@ __xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *e
static void
__xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
{
- struct usb_device *udev;
-
lockdep_assert_held(&sb->mutex);
if (!sb->ir)
@@ -102,10 +100,6 @@ __xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir);
sb->ir = NULL;
- udev = sb->vdev->udev;
-
- if (udev->state != USB_STATE_NOTATTACHED)
- usb_offload_put(udev);
}
/* sideband api functions */
@@ -291,8 +285,8 @@ EXPORT_SYMBOL_GPL(xhci_sideband_get_event_buffer);
* Allow other drivers, such as usb controller driver, to check if there are
* any sideband activity on the host controller. This information could be used
* for power management or other forms of resource management. The caller should
- * ensure downstream usb devices are all either suspended or marked as
- * "offload_at_suspend" to ensure the correctness of the return value.
+ * ensure downstream usb devices are all marked as "offload_pm_locked" to ensure
+ * the correctness of the return value.
*
* Returns true on any active sideband existence, false otherwise.
*/
@@ -328,9 +322,6 @@ int
xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg,
bool ip_autoclear, u32 imod_interval, int intr_num)
{
- int ret = 0;
- struct usb_device *udev;
-
if (!sb || !sb->xhci)
return -ENODEV;
@@ -348,12 +339,9 @@ xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg,
if (!sb->ir)
return -ENOMEM;
- udev = sb->vdev->udev;
- ret = usb_offload_get(udev);
-
sb->ir->ip_autoclear = ip_autoclear;
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c36ab323d68e..ef6d8662adec 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4146,7 +4146,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
spin_unlock_irqrestore(&xhci->lock, flags);
- kfree(command);
+ xhci_free_command(xhci, command);
return -ENODEV;
}
@@ -4154,7 +4154,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
slot_id);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
- kfree(command);
+ xhci_free_command(xhci, command);
return ret;
}
xhci_ring_cmd_db(xhci);
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 8d8e79afa600..ca287b770e8c 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -707,7 +707,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
if (signal_pending (current))
{
mutex_unlock(&mdc800->io_lock);
- return -EINTR;
+ return len == left ? -EINTR : len-left;
}
sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
@@ -730,9 +730,11 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
mutex_unlock(&mdc800->io_lock);
return len-left;
}
- wait_event_timeout(mdc800->download_wait,
+ retval = wait_event_timeout(mdc800->download_wait,
mdc800->downloaded,
msecs_to_jiffies(TO_DOWNLOAD_GET_READY));
+ if (!retval)
+ usb_kill_urb(mdc800->download_urb);
mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
diff --git a/drivers/usb/misc/usbio.c b/drivers/usb/misc/usbio.c
index 2e68d48a2cc0..02d1e0760f0c 100644
--- a/drivers/usb/misc/usbio.c
+++ b/drivers/usb/misc/usbio.c
@@ -614,8 +614,10 @@ static int usbio_probe(struct usb_interface *intf, const struct usb_device_id *i
usb_fill_bulk_urb(usbio->urb, udev, usbio->rx_pipe, usbio->rxbuf,
usbio->rxbuf_len, usbio_bulk_recv, usbio);
ret = usb_submit_urb(usbio->urb, GFP_KERNEL);
- if (ret)
- return dev_err_probe(dev, ret, "Submitting usb urb\n");
+ if (ret) {
+ dev_err_probe(dev, ret, "Submitting usb urb\n");
+ goto err_free_urb;
+ }
mutex_lock(&usbio->ctrl_mutex);
@@ -663,6 +665,7 @@ static int usbio_probe(struct usb_interface *intf, const struct usb_device_id *i
err_unlock:
mutex_unlock(&usbio->ctrl_mutex);
usb_kill_urb(usbio->urb);
+err_free_urb:
usb_free_urb(usbio->urb);
return ret;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index ec8bd968c4de..a8af7615b1bf 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -736,7 +736,7 @@ static int uss720_probe(struct usb_interface *intf,
ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
if (ret < 0)
- return ret;
+ goto probe_abort;
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 9189e4bb213a..7a482cdee1e9 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -272,6 +272,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
dev->int_buffer, YUREX_BUF_SIZE, yurex_interrupt,
dev, 1);
dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ dev->bbu = -1;
if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
retval = -EIO;
dev_err(&interface->dev, "Could not submitting URB\n");
@@ -280,7 +281,6 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- dev->bbu = -1;
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &yurex_class);
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index cf4a0367d6d6..8c93bde4b816 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -815,6 +815,15 @@ static void usbhs_remove(struct platform_device *pdev)
usbhs_platform_call(priv, hardware_exit, pdev);
reset_control_assert(priv->rsts);
+
+ /*
+ * Explicitly free the IRQ to ensure the interrupt handler is
+ * disabled and synchronized before freeing resources.
+ * devm_free_irq() calls free_irq() which waits for any running
+ * ISR to complete, preventing UAF.
+ */
+ devm_free_irq(&pdev->dev, priv->irq, priv);
+
usbhs_mod_remove(priv);
usbhs_fifo_remove(priv);
usbhs_pipe_remove(priv);
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index b8e28ceca51e..edec139b68b5 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -139,9 +139,14 @@ static void *usb_role_switch_match(const struct fwnode_handle *fwnode, const cha
static struct usb_role_switch *
usb_role_switch_is_parent(struct fwnode_handle *fwnode)
{
- struct fwnode_handle *parent = fwnode_get_parent(fwnode);
+ struct fwnode_handle *parent;
struct device *dev;
+ if (!fwnode_device_is_compatible(fwnode, "usb-b-connector"))
+ return NULL;
+
+ parent = fwnode_get_parent(fwnode);
+
if (!fwnode_property_present(parent, "usb-role-switch")) {
fwnode_handle_put(parent);
return NULL;
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 58694b8943d1..3f5889145e51 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -73,6 +73,7 @@ static const struct usb_device_id edgeport_4port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) },
{ }
};
@@ -121,6 +122,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
@@ -470,6 +472,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
case ION_DEVICE_ID_EDGEPORT_2_DIN:
case ION_DEVICE_ID_EDGEPORT_4_DIN:
case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU:
+ case ION_DEVICE_ID_BLACKBOX_IC135A:
product_info->IsRS232 = 1;
break;
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index 9a6f742ad3ab..c82a275e8e76 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -211,6 +211,7 @@
//
// Definitions for other product IDs
+#define ION_DEVICE_ID_BLACKBOX_IC135A 0x0801 // OEM device (rebranded Edgeport/4)
#define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device
#define ION_DEVICE_ID_E5805A 0x1A01 // OEM device (rebranded Edgeport/4)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e349ed66d2ac..313612114db9 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2441,6 +2441,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM815 and SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825L */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM825WN (Diag) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825WN (AT) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825WN (NMEA) */
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
@@ -2461,6 +2464,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) }, /* Rolling RW101R-GL (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff), /* Rolling RW350-GL (laptop MBIM) */
.driver_info = RSVD(5) },
+ { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff) }, /* Rolling RW135R-GL (laptop MBIM) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
index d185688a16b1..35d9c3086990 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -100,9 +100,14 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
{
u8 pin_assign = 0;
u32 conf;
+ u32 signal;
/* DP Signalling */
- conf = (dp->data.conf & DP_CONF_SIGNALLING_MASK) >> DP_CONF_SIGNALLING_SHIFT;
+ signal = DP_CAP_DP_SIGNALLING(dp->port->vdo) & DP_CAP_DP_SIGNALLING(dp->alt->vdo);
+ if (dp->plug_prime)
+ signal &= DP_CAP_DP_SIGNALLING(dp->plug_prime->vdo);
+
+ conf = signal << DP_CONF_SIGNALLING_SHIFT;
switch (con) {
case DP_STATUS_CON_DISABLED:
diff --git a/drivers/usb/typec/altmodes/thunderbolt.c b/drivers/usb/typec/altmodes/thunderbolt.c
index c4c5da6154da..32250b94262a 100644
--- a/drivers/usb/typec/altmodes/thunderbolt.c
+++ b/drivers/usb/typec/altmodes/thunderbolt.c
@@ -39,28 +39,7 @@ static bool tbt_ready(struct typec_altmode *alt);
static int tbt_enter_mode(struct tbt_altmode *tbt)
{
- struct typec_altmode *plug = tbt->plug[TYPEC_PLUG_SOP_P];
- u32 vdo;
-
- vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1);
- vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0;
- vdo |= TBT_MODE;
-
- if (plug) {
- if (typec_cable_is_active(tbt->cable))
- vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
-
- vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo));
- vdo |= plug->vdo & TBT_CABLE_ROUNDED;
- vdo |= plug->vdo & TBT_CABLE_OPTICAL;
- vdo |= plug->vdo & TBT_CABLE_RETIMER;
- vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING;
- } else {
- vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE);
- }
-
- tbt->enter_vdo = vdo;
- return typec_altmode_enter(tbt->alt, &vdo);
+ return typec_altmode_enter(tbt->alt, &tbt->enter_vdo);
}
static void tbt_altmode_work(struct work_struct *work)
@@ -337,6 +316,7 @@ static bool tbt_ready(struct typec_altmode *alt)
{
struct tbt_altmode *tbt = typec_altmode_get_drvdata(alt);
struct typec_altmode *plug;
+ u32 vdo;
if (tbt->cable)
return true;
@@ -364,6 +344,26 @@ static bool tbt_ready(struct typec_altmode *alt)
tbt->plug[i] = plug;
}
+ vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1);
+ vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0;
+ vdo |= TBT_MODE;
+ plug = tbt->plug[TYPEC_PLUG_SOP_P];
+
+ if (plug) {
+ if (typec_cable_is_active(tbt->cable))
+ vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
+
+ vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo));
+ vdo |= plug->vdo & TBT_CABLE_ROUNDED;
+ vdo |= plug->vdo & TBT_CABLE_OPTICAL;
+ vdo |= plug->vdo & TBT_CABLE_RETIMER;
+ vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING;
+ } else {
+ vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE);
+ }
+
+ tbt->enter_vdo = vdo;
+
return true;
}
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 831430909471..0977581ad1b6 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -686,10 +686,6 @@ typec_register_altmode(struct device *parent,
alt->adev.dev.bus = &typec_bus;
- /* Plug alt modes need a class to generate udev events. */
- if (is_typec_plug(parent))
- alt->adev.dev.class = &typec_class;
-
ret = device_register(&alt->adev.dev);
if (ret) {
dev_err(parent, "failed to register alternate mode (%d)\n",
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 1d2f3af034c5..8e0e14a2704e 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -7890,7 +7890,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
port->partner_desc.identity = &port->partner_ident;
port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode);
- if (IS_ERR_OR_NULL(port->role_sw))
+ if (!port->role_sw)
port->role_sw = usb_role_switch_get(port->dev);
if (IS_ERR(port->role_sw)) {
err = PTR_ERR(port->role_sw);
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index f38a4d7ebc42..46262ee0d192 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -43,8 +43,14 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci)
if (cci & UCSI_CCI_BUSY)
return;
- if (UCSI_CCI_CONNECTOR(cci))
- ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
+ if (UCSI_CCI_CONNECTOR(cci)) {
+ if (!ucsi->cap.num_connectors ||
+ UCSI_CCI_CONNECTOR(cci) <= ucsi->cap.num_connectors)
+ ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
+ else
+ dev_err(ucsi->dev, "bogus connector number in CCI: %lu\n",
+ UCSI_CCI_CONNECTOR(cci));
+ }
if (cci & UCSI_CCI_ACK_COMPLETE &&
test_and_clear_bit(ACK_PENDING, &ucsi->flags))
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index 478beafc6ac3..b1d658b8f7b5 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -301,11 +301,10 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
*/
ret = dma_buf_fd(priv->dmabuf, get_dma_buf.open_flags);
if (ret < 0)
- goto err_dma_buf;
+ dma_buf_put(priv->dmabuf);
+
return ret;
-err_dma_buf:
- dma_buf_put(priv->dmabuf);
err_dev_put:
vfio_device_put_registration(&vdev->vdev);
err_free_phys:
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index 1a04154bc535..c54cfcd832bb 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -380,8 +380,12 @@ static struct au1100fb_panel known_lcd_panels[] =
#define panel_is_color(panel) (panel->control_base & LCD_CONTROL_PC)
#define panel_swap_rgb(panel) (panel->control_base & LCD_CONTROL_CCO)
-#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_MIPS)
-/* This is only defined to be able to compile this driver on non-mips platforms */
+#if defined(CONFIG_COMPILE_TEST) && (!defined(CONFIG_MIPS) || defined(CONFIG_64BIT))
+/*
+ * KSEG1ADDR() is defined in arch/mips/include/asm/addrspace.h
+ * for 32 bit configurations. Provide a stub for compile testing
+ * on other platforms.
+ */
#define KSEG1ADDR(x) (x)
#endif
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 4252b147593a..7cee97559ba2 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -171,6 +171,8 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp)
#define GET_QUOTE_SUCCESS 0
#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff
+#define TDX_QUOTE_MAX_LEN (GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_buf))
+
/* struct tdx_quote_buf: Format of Quote request buffer.
* @version: Quote format version, filled by TD.
* @status: Status code of Quote request, filled by VMM.
@@ -269,6 +271,7 @@ static int tdx_report_new_locked(struct tsm_report *report, void *data)
u8 *buf;
struct tdx_quote_buf *quote_buf = quote_data;
struct tsm_report_desc *desc = &report->desc;
+ u32 out_len;
int ret;
u64 err;
@@ -306,12 +309,17 @@ static int tdx_report_new_locked(struct tsm_report *report, void *data)
return ret;
}
- buf = kvmemdup(quote_buf->data, quote_buf->out_len, GFP_KERNEL);
+ out_len = READ_ONCE(quote_buf->out_len);
+
+ if (out_len > TDX_QUOTE_MAX_LEN)
+ return -EFBIG;
+
+ buf = kvmemdup(quote_buf->data, out_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
report->outblob = buf;
- report->outblob_len = quote_buf->out_len;
+ report->outblob_len = out_len;
/*
* TODO: parse the PEM-formatted cert chain out of the quote buffer when
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 335692d41617..fbca7ce1c6bf 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -2912,10 +2912,10 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf);
* @data: the token identifying the buffer.
* @gfp: how to do memory allocations (if necessary).
*
- * Same as virtqueue_add_inbuf but passes DMA_ATTR_CPU_CACHE_CLEAN to indicate
- * that the CPU will not dirty any cacheline overlapping this buffer while it
- * is available, and to suppress overlapping cacheline warnings in DMA debug
- * builds.
+ * Same as virtqueue_add_inbuf but passes DMA_ATTR_DEBUGGING_IGNORE_CACHELINES
+ * to indicate that the CPU will not dirty any cacheline overlapping this buffer
+ * while it is available, and to suppress overlapping cacheline warnings in DMA
+ * debug builds.
*
* Caller must ensure we don't call this with other virtqueue operations
* at the same time (except where noted).
@@ -2928,7 +2928,7 @@ int virtqueue_add_inbuf_cache_clean(struct virtqueue *vq,
gfp_t gfp)
{
return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, false, gfp,
- DMA_ATTR_CPU_CACHE_CLEAN);
+ DMA_ATTR_DEBUGGING_IGNORE_CACHELINES);
}
EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_cache_clean);
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 1759cc18753f..15ba592236e8 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -12,6 +12,7 @@
#include <linux/eventfd.h>
#include <linux/file.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
@@ -30,7 +31,10 @@
#include <linux/seq_file.h>
#include <linux/miscdevice.h>
#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/security.h>
#include <linux/virtio_mmio.h>
+#include <linux/wait.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
@@ -46,6 +50,7 @@
#include <xen/page.h>
#include <xen/xen-ops.h>
#include <xen/balloon.h>
+#include <xen/xenbus.h>
#ifdef CONFIG_XEN_ACPI
#include <xen/acpi.h>
#endif
@@ -68,10 +73,20 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
MODULE_PARM_DESC(dm_op_buf_max_size,
"Maximum size of a dm_op hypercall buffer");
+static bool unrestricted;
+module_param(unrestricted, bool, 0);
+MODULE_PARM_DESC(unrestricted,
+ "Don't restrict hypercalls to target domain if running in a domU");
+
struct privcmd_data {
domid_t domid;
};
+/* DOMID_INVALID implies no restriction */
+static domid_t target_domain = DOMID_INVALID;
+static bool restrict_wait;
+static DECLARE_WAIT_QUEUE_HEAD(restrict_wait_wq);
+
static int privcmd_vma_range_is_mapped(
struct vm_area_struct *vma,
unsigned long addr,
@@ -1563,13 +1578,16 @@ static long privcmd_ioctl(struct file *file,
static int privcmd_open(struct inode *ino, struct file *file)
{
- struct privcmd_data *data = kzalloc_obj(*data);
+ struct privcmd_data *data;
+ if (wait_event_interruptible(restrict_wait_wq, !restrict_wait) < 0)
+ return -EINTR;
+
+ data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
- /* DOMID_INVALID implies no restriction */
- data->domid = DOMID_INVALID;
+ data->domid = target_domain;
file->private_data = data;
return 0;
@@ -1662,6 +1680,52 @@ static struct miscdevice privcmd_dev = {
.fops = &xen_privcmd_fops,
};
+static int init_restrict(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ char *target;
+ unsigned int domid;
+
+ /* Default to an guaranteed unused domain-id. */
+ target_domain = DOMID_IDLE;
+
+ target = xenbus_read(XBT_NIL, "target", "", NULL);
+ if (IS_ERR(target) || kstrtouint(target, 10, &domid)) {
+ pr_err("No target domain found, blocking all hypercalls\n");
+ goto out;
+ }
+
+ target_domain = domid;
+
+ out:
+ if (!IS_ERR(target))
+ kfree(target);
+
+ restrict_wait = false;
+ wake_up_all(&restrict_wait_wq);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xenstore_notifier = {
+ .notifier_call = init_restrict,
+};
+
+static void __init restrict_driver(void)
+{
+ if (unrestricted) {
+ if (security_locked_down(LOCKDOWN_XEN_USER_ACTIONS))
+ pr_warn("Kernel is locked down, parameter \"unrestricted\" ignored\n");
+ else
+ return;
+ }
+
+ restrict_wait = true;
+
+ register_xenstore_notifier(&xenstore_notifier);
+}
+
static int __init privcmd_init(void)
{
int err;
@@ -1669,6 +1733,9 @@ static int __init privcmd_init(void)
if (!xen_domain())
return -ENODEV;
+ if (!xen_initial_domain())
+ restrict_driver();
+
err = misc_register(&privcmd_dev);
if (err != 0) {
pr_err("Could not register Xen privcmd device\n");
@@ -1698,6 +1765,9 @@ err_privcmdbuf:
static void __exit privcmd_exit(void)
{
+ if (!xen_initial_domain())
+ unregister_xenstore_notifier(&xenstore_notifier);
+
privcmd_ioeventfd_exit();
privcmd_irqfd_exit();
misc_deregister(&privcmd_dev);
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 31903bfdce9f..897ae2a0b5a0 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -378,11 +378,8 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_psd[acpi_id].domain);
}
- status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- if (!pblk)
- return AE_OK;
- }
+ if (!pblk && !acpi_has_method(handle, "_CST"))
+ return AE_OK;
/* .. and it has a C-state */
__set_bit(acpi_id, acpi_id_cst_present);
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
index 22ff9cf35fc4..b34785ba72e1 100644
--- a/drivers/xen/xen-pciback/xenbus.c
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -149,12 +149,12 @@ static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
mutex_lock(&pdev->dev_lock);
/* Make sure we only do this setup once */
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) !=
XenbusStateInitialised)
goto out;
/* Wait for frontend to state that it has published the configuration */
- if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->otherend) !=
XenbusStateInitialised)
goto out;
@@ -374,7 +374,7 @@ static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev,
dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
mutex_lock(&pdev->dev_lock);
- if (xenbus_read_driver_state(pdev->xdev->nodename) != state)
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) != state)
goto out;
err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
@@ -572,7 +572,7 @@ static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
/* It's possible we could get the call to setup twice, so make sure
* we're not already connected.
*/
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) !=
XenbusStateInitWait)
goto out;
@@ -662,7 +662,7 @@ static void xen_pcibk_be_watch(struct xenbus_watch *watch,
struct xen_pcibk_device *pdev =
container_of(watch, struct xen_pcibk_device, be_watch);
- switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+ switch (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename)) {
case XenbusStateInitWait:
xen_pcibk_setup_backend(pdev);
break;
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 0ab1329e79de..27682cb5e58a 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -226,8 +226,9 @@ __xenbus_switch_state(struct xenbus_device *dev,
struct xenbus_transaction xbt;
int current_state;
int err, abort;
+ bool vanished = false;
- if (state == dev->state)
+ if (state == dev->state || dev->vanished)
return 0;
again:
@@ -242,6 +243,10 @@ again:
err = xenbus_scanf(xbt, dev->nodename, "state", "%d", &current_state);
if (err != 1)
goto abort;
+ if (current_state != dev->state && current_state == XenbusStateInitialising) {
+ vanished = true;
+ goto abort;
+ }
err = xenbus_printf(xbt, dev->nodename, "state", "%d", state);
if (err) {
@@ -256,7 +261,7 @@ abort:
if (err == -EAGAIN && !abort)
goto again;
xenbus_switch_fatal(dev, depth, err, "ending transaction");
- } else
+ } else if (!vanished)
dev->state = state;
return 0;
@@ -931,14 +936,20 @@ static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr)
/**
* xenbus_read_driver_state - read state from a store path
+ * @dev: xenbus device pointer
* @path: path for driver
*
* Returns: the state of the driver rooted at the given store path, or
* XenbusStateUnknown if no state can be read.
*/
-enum xenbus_state xenbus_read_driver_state(const char *path)
+enum xenbus_state xenbus_read_driver_state(const struct xenbus_device *dev,
+ const char *path)
{
enum xenbus_state result;
+
+ if (dev && dev->vanished)
+ return XenbusStateUnknown;
+
int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
if (err)
result = XenbusStateUnknown;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 9f9011cd7447..eb260eceb4d2 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -191,7 +191,7 @@ void xenbus_otherend_changed(struct xenbus_watch *watch,
return;
}
- state = xenbus_read_driver_state(dev->otherend);
+ state = xenbus_read_driver_state(dev, dev->otherend);
dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n",
state, xenbus_strstate(state), dev->otherend_watch.node, path);
@@ -364,7 +364,7 @@ void xenbus_dev_remove(struct device *_dev)
* closed.
*/
if (!drv->allow_rebind ||
- xenbus_read_driver_state(dev->nodename) == XenbusStateClosing)
+ xenbus_read_driver_state(dev, dev->nodename) == XenbusStateClosing)
xenbus_switch_state(dev, XenbusStateClosed);
}
EXPORT_SYMBOL_GPL(xenbus_dev_remove);
@@ -444,6 +444,9 @@ static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
info.dev = NULL;
bus_for_each_dev(bus, NULL, &info, cleanup_dev);
if (info.dev) {
+ dev_warn(&info.dev->dev,
+ "device forcefully removed from xenstore\n");
+ info.dev->vanished = true;
device_unregister(&info.dev->dev);
put_device(&info.dev->dev);
}
@@ -514,7 +517,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
size_t stringlen;
char *tmpstring;
- enum xenbus_state state = xenbus_read_driver_state(nodename);
+ enum xenbus_state state = xenbus_read_driver_state(NULL, nodename);
if (state != XenbusStateInitialising) {
/* Device is not new, so ignore it. This can happen if a
@@ -659,6 +662,39 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
return;
dev = xenbus_device_find(root, &bus->bus);
+ /*
+ * Backend domain crash results in not coordinated frontend removal,
+ * without going through XenbusStateClosing. If this is a new instance
+ * of the same device Xen tools will have reset the state to
+ * XenbusStateInitializing.
+ * It might be that the backend crashed early during the init phase of
+ * device setup, in which case the known state would have been
+ * XenbusStateInitializing. So test the backend domid to match the
+ * saved one. In case the new backend happens to have the same domid as
+ * the old one, we can just carry on, as there is no inconsistency
+ * resulting in this case.
+ */
+ if (dev && !strcmp(bus->root, "device")) {
+ enum xenbus_state state = xenbus_read_driver_state(dev, dev->nodename);
+ unsigned int backend = xenbus_read_unsigned(root, "backend-id",
+ dev->otherend_id);
+
+ if (state == XenbusStateInitialising &&
+ (state != dev->state || backend != dev->otherend_id)) {
+ /*
+ * State has been reset, assume the old one vanished
+ * and new one needs to be probed.
+ */
+ dev_warn(&dev->dev,
+ "state reset occurred, reconnecting\n");
+ dev->vanished = true;
+ }
+ if (dev->vanished) {
+ device_unregister(&dev->dev);
+ put_device(&dev->dev);
+ dev = NULL;
+ }
+ }
if (!dev)
xenbus_probe_node(bus, type, root);
else
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index f04707d1f667..ca04609730df 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -253,7 +253,7 @@ static int print_device_status(struct device *dev, void *data)
} else if (xendev->state < XenbusStateConnected) {
enum xenbus_state rstate = XenbusStateUnknown;
if (xendev->otherend)
- rstate = xenbus_read_driver_state(xendev->otherend);
+ rstate = xenbus_read_driver_state(xendev, xendev->otherend);
pr_warn("Timeout connecting to device: %s (local state %d, remote state %d)\n",
xendev->nodename, xendev->state, rstate);
}